├── .nvmrc ├── app ├── .nvmrc ├── package.json ├── index.e2e.js ├── index.js └── package-lock.json ├── .npmignore ├── assets ├── architecture.png ├── moderation-workflow.png ├── s3-event.json ├── architecture.drawio └── e2e-green.log ├── jest.config.js ├── .gitignore ├── bin └── basup-ugc-stack.ts ├── CODE_OF_CONDUCT.md ├── test └── basup-ugc-stack.test.ts ├── package.json ├── tsconfig.json ├── LICENSE ├── cdk.json ├── README.md ├── CONTRIBUTING.md └── lib └── basup-ugc-stack-stack.ts /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.18.0 2 | -------------------------------------------------------------------------------- /app/.nvmrc: -------------------------------------------------------------------------------- 1 | v16.18.0 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /assets/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-ugc-moderation-sample/HEAD/assets/architecture.png -------------------------------------------------------------------------------- /assets/moderation-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-ugc-moderation-sample/HEAD/assets/moderation-workflow.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !app/*.js 3 | !jest.config.js 4 | *.d.ts 5 | node_modules 6 | 00-deploy.sh 7 | 10-upload.sh 8 | assets/cdk-outputs.json 9 | assets/*.mp4 10 | .DS_Store 11 | 12 | 13 | # CDK asset staging directory 14 | .cdk.staging 15 | cdk.out 16 | -------------------------------------------------------------------------------- /bin/basup-ugc-stack.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import 'source-map-support/register' 3 | import * as cdk from 'aws-cdk-lib' 4 | import { BasupUgcStackStack } from '../lib/basup-ugc-stack-stack' 5 | 6 | const app = new cdk.App() 7 | 8 | new BasupUgcStackStack(app, 'BasupUgcStackStack', {}) 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "basup-ugcmod-app", 3 | "version": "1.0.0", 4 | "description": "a set of Lamda functions to start and monitor the execution of Rekognition Moderation Jobs", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "gbatt@amazon.com", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@aws-sdk/client-rekognition": "^3.624.0", 13 | "@aws-sdk/client-s3": "^3.627.0", 14 | "@aws-sdk/client-sns": "^3.624.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/basup-ugc-stack.test.ts: -------------------------------------------------------------------------------- 1 | // import * as cdk from 'aws-cdk-lib'; 2 | // import { Template } from 'aws-cdk-lib/assertions'; 3 | // import * as BasupUgcStack from '../lib/basup-ugc-stack-stack'; 4 | 5 | // example test. To run these tests, uncomment this file along with the 6 | // example resource in lib/basup-ugc-stack-stack.ts 7 | test('SQS Queue Created', () => { 8 | // const app = new cdk.App(); 9 | // // WHEN 10 | // const stack = new BasupUgcStack.BasupUgcStackStack(app, 'MyTestStack'); 11 | // // THEN 12 | // const template = Template.fromStack(stack); 13 | 14 | // template.hasResourceProperties('AWS::SQS::Queue', { 15 | // VisibilityTimeout: 300 16 | // }); 17 | }); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "basup-ugc-stack", 3 | "version": "0.1.0", 4 | "bin": { 5 | "basup-ugc-stack": "bin/basup-ugc-stack.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^27.5.2", 15 | "@types/node": "10.17.27", 16 | "@types/prettier": "2.6.0", 17 | "aws-cdk": "2.152.0", 18 | "jest": "^27.5.1", 19 | "ts-jest": "^27.1.4", 20 | "ts-node": "^10.9.1", 21 | "typescript": "~3.9.7", 22 | "cdk-nag": "^2.21.18" 23 | }, 24 | "dependencies": { 25 | "aws-cdk-lib": "2.152.0", 26 | "constructs": "10.3.0", 27 | "source-map-support": "^0.5.21" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2018" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "cdk.out" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /assets/s3-event.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0", 3 | "id": "17793124-05d4-b198-2fde-7ededc63b103", 4 | "detail-type": "Object Created", 5 | "source": "aws.s3", 6 | "account": "REDACTED", 7 | "time": "2021-11-12T00:00:00Z", 8 | "region": "us-west-2", 9 | "resources": ["arn:aws:s3:::basup-manual-tests"], 10 | "detail": { 11 | "version": "0", 12 | "bucket": { 13 | "name": "basup-manual-tests" 14 | }, 15 | "object": { 16 | "key": "public/upload/room2.mp4", 17 | "size": 5, 18 | "etag": "b1946ac92492d2347c6235b4d2611184", 19 | "version-id": "IYV3p45BT0ac8hjHg1houSdS1a.Mro8e", 20 | "sequencer": "00617F08299329D189" 21 | }, 22 | "request-id": "N4N7GDK58NMKJ12R", 23 | "requester": "REDACTED", 24 | "source-ip-address": "1.2.3.4", 25 | "reason": "PutObject" 26 | }, 27 | "uuid":"TEST_UUID" 28 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | 16 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/basup-ugc-stack.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, 21 | "@aws-cdk/core:stackRelativeExports": true, 22 | "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, 23 | "@aws-cdk/aws-lambda:recognizeVersionProps": true, 24 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 25 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/core:checkSecretUsage": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 31 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 32 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 33 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 34 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 35 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 36 | "@aws-cdk/core:enablePartitionLiterals": true, 37 | "@aws-cdk/core:target-partitions": [ 38 | "aws", 39 | "aws-cn" 40 | ] 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # User Generated Content Moderation Video Pipeline 2 | 3 | ## Introduction 4 | This code sample illustrates a minimal User Generated Content Moderation Pipeline 5 | for video files. It makes use of Rekognition Moderation capabilities to scan 6 | video content for inappropriate images. The rationale behind this code sample is 7 | to block UGC from progressing further in the analysis pipeline, so that customers 8 | don't perform AI/ML workloads on inappropriate content. 9 | 10 | ## Process 11 | - Users upload media content to the inspection bucket deployed by the code sample 12 | - An upload notification is sent on EventBridge which triggers the UGC state machine 13 | ![assets/moderation-workflow.png](assets/moderation-workflow.png) 14 | - if the video is clear from inappropriate content, it gets replicated to 15 | a destination bucket 16 | - otherwise, an email is sent to the moderation team for further inspection 17 | 18 | ## Architecture 19 | ![assets/architecture.png](assets/architecture.png) 20 | 21 | ## Deployment Instructions 22 | ```bash 23 | REPLICATION_BUCKET_NAME= # for example "my-bucket-name" 24 | NOTIFICATION_EMAIL_ADDRESS= # for example "you@yourcompany.com" 25 | 26 | npm i 27 | cd app && npm i && cd .. 28 | 29 | cdk deploy \ 30 | --parameters replicationBucketName=$REPLICATION_BUCKET_NAME \ 31 | --parameters notificationEmailAddress=$NOTIFICATION_EMAIL_ADDRESS \ 32 | --outputs-file assets/cdk-outputs.json 33 | ``` 34 | 35 | ### Parameters 36 | `replicationBucketName` is the bucket where the object will be replicated if it 37 | does not contain inappropriate content. This must be in the same region as this stack. 38 | `notificationEmailAddress` is valid email address where you'll receive moderation 39 | events notifications. Expect a confirmation email to this address from AWS SNS. Make sure you confirm the SNS subscription. 40 | 41 | ## Running the Workflow 42 | You can start the workflow by uploading a video to your S3 bucket at the `/public/upload/` path. 43 | For example, run the following 44 | 45 | ```bash 46 | INSPECTION_BUCKET=$(cat ./assets/cdk-outputs.json | jq .BasupUgcStackStack.InspectionBucketName | xargs) 47 | UPLOAD_FILE_PATH=path/to/your/video 48 | 49 | aws s3 cp $UPLOAD_FILE_PATH s3://$INSPECTION_BUCKET/public/upload/ 50 | ``` 51 | 52 | You can monitor the execution of the flow in your StepFunction Console 53 | 54 | ### Acknowledgements 55 | This code sample has been developed by the UKIR Green Field Startup Solutions Architecture Team @AWS. 56 | -------------------------------------------------------------------------------- /assets/architecture.drawio: -------------------------------------------------------------------------------- 1 | 7VxZd9o4FP41PIbj3c5jgKTtTKfDNO1p85QjsABNbMtHFln66yvZMrYlsRWztYScE+ta6733+3S1kI7dj1/fEZDO/sEhjDqWEb527EHHskzH8NgfLnkTEj8wCsmUoFDIKsE9+gGFsMw2RyHMGhkpxhFFaVM4xkkCx7QhA4Tgl2a2CY6araZgChXB/RhEqvQbCumskAauUcnfQzSdlS2bhngTgzKzEGQzEOKXmsi+7dh9gjEtnuLXPoy49kq9FOXulrxddIzAhG5S4O/3w/8+D78PTURnP4beg3P38O+VYxXVPINoLkZ88+2eCe4pTNmfu3kypggnGXt+weRpErEhFMOhb6WOUowSmuvZ7bFf1o2+0XHZmz5PdS1XEshpvykw1RSvoymQ035TYMrVm1L7ptzBmkBJNao3pPaNWgfZr93DcxqhBPYXHmkw4ZSAEDFL9XGECZMlOGHa681oHLGUyR5fZojC+xSMuVZfGJyYbIITKjBhWmVaKJ7Xynwq5c/x65TjrwteMqc7JXie5k1+YKjQvn1kj48ZM/HjpDTw48K8rFpK8BMsu9qx7P7AsjyHdwBFkTSEZ0goYoC5idCUt0YxbxyIVAQnlNfIxoWS6cc8NbANMRZdEyHIZjAUAxTeyZqAr0v93lygifEQxDGk5I1lEQUs2y2KCAq68gIheKkA7Za0NKuB2S6hCwSJTBeVVzhjDwJqW8DOMxXYKaiCISMikcSEzvAUJyC6raQ9ZskkXKiqyvMRcxPkTvU/pPRNeBCYU9x0uaJN3tBq3bJ+4TkZi1yiqxSQKSw1pbcAgRGg6LlZ+y7KVNnqE6ZowtyP+zB78wWnaKyoUotIyf96+UeDVPbuznacwKq9GyACc9jkMCDcixrQ4PX1Tdv1dGCa5D+yp5cw+ghGMBriDInqR5hSHK/F2Zj1CpKmedexB8jSQh0T9Mr7oacTAgvjF2TSY0kdrWRsiigdSuM/CoKXwtWX4epfa+CqQau7N7B6ZwxWWwWrfpDOgSBsK8q8jQHiOe7no2xMUFpA+QLhs4Ww6xknBmErOB/EOipiTUOv743BmRe9IQS81TKIsL2qecgFtcBJsqIrLzDW5Hea+dlD0YPKjIuhbGRZR2GOD0nu/sXU35uPn5jC2iYOz7ixbX874rB83zT/IOKwW+INaeZ3nSPThn3OM3+5g1InEss70CxfNl6f5p9Zb3sE8WFYXsRXhSPCnqY0H6IHYu7TuTyEEzCPOLWM5tnilch4CQwOjW/ILTcqLLcXoDvHBrrjHwPXTIHk7bsonyceeKLrlsnBa/3l4K1T3xTZmg82XQo4h1rNm+pagK0BYsSB/xcetQ91P7g1nO2gPjDcvun/MVCPQDwKQTsoV2DuGUeGuavOSmc0n3ub4vf6UPhVw6N3PAI37img8+yC3/PGr+OdHH6vzweulib81sN1iRX2u7i3LTkGE2y9bHWvFLCNdpf3lkrOn2Ea8b19eKGS86YS25X3hsrztqNt6huKT50ulWgid+sYpBHYshnXkIZSwPdbJg11CZGfCPJRqbsM/H4KKY8K8/2IC7GcN7Eop4VHJxbHOyNi0SwpzF1X/7/ELGYgHzYELROFulb5+o6VMuqcIPMFX8dAngeMZ4wU2ieLy97j2rOFxiWldkjDPLn9R9s+H9LQD8BSmWTXGwW/RiRyxOGJK6jLQhSlgNvyseVKfSl09DWNMAgVb8iHDUkes2TCfIsLpYaM+ZqNmywhruxFEhcsQN4WWUic5Rr8oyGCOBsD2GVDmyewO88geSwuL+oBvc2tP2Xv0doM4ra/r7hAvfI3gBlFCbicXx97jqnOr3fyOWWVa2/odPsLRtXl0TeAVCdbcw25mmnMljTlbLC16B1UU+rtEkVLsouN0jjpUhQz2srYxMcjxhQSls69ecBaRWkGh5Wo7uAyB5NikIW8B8ZP01zrOuxJd6u1DLGRkbY6/mtWU7OTraNRIdtuslcm5yuz6SemZH48mWSCM+/anaCdU70xthLna+M0R3e77FCXQvR7+uYxFF0dvVen7Q+d+mF7m0fvK47pDnEe/0uBtBvIFG2vOSDwVxfYTyDtqoH0J6x4FCNB2nQAJfaQQ5QYhWHhazBDP8BoEXk0v+002Iyyl9Kx+N6aqL+zOAVZC3l39Qx7ZXRNswxmF+vc3Uh5/6zrbjALnwYNt45y91C3bvStu4riH6B6gv874mjJNoWonsPINBswCtoJbYImNoODRTbXiqnzy1ZGH8dpxALVjn2nGJ7McMzvYurXBwp0dlu6K4sDS93T131fL9jX4sA9oz39FeQinSDu+qWC3VTqK17YjyAgfwTlLAm4q6nbKGOpE56qA03gRdUzFL1VfwP4HHe+1lydLS7dnRp5O5rvfh2UvD01plx15vcFgljR4CabsOxzx7u17Kv+yl7qooC0+/pb7rHyzf2WPEzaZA0MNTrQbR162zsYS1b/n6MgzurfnNi3PwE= -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | 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/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /assets/e2e-green.log: -------------------------------------------------------------------------------- 1 | ***** starting simulated flow ***** 2 | { 3 | version: '0', 4 | id: '17793124-05d4-b198-2fde-7ededc63b103', 5 | 'detail-type': 'Object Created', 6 | source: 'aws.s3', 7 | account: 'REDACTED', 8 | time: '2021-11-12T00:00:00Z', 9 | region: 'us-west-2', 10 | resources: [ 'REDACTED' ], 11 | detail: { 12 | version: '0', 13 | bucket: { name: 'REDACTED' }, 14 | object: { 15 | key: 'public/upload/room.mp4', 16 | size: 5, 17 | etag: 'b1946ac92492d2347c6235b4d2611184', 18 | 'version-id': 'IYV3p45BT0ac8hjHg1houSdS1a.Mro8e', 19 | sequencer: '00617F08299329D189' 20 | }, 21 | 'request-id': 'N4N7GDK58NMKJ12R', 22 | requester: 'REDACTED', 23 | 'source-ip-address': '1.2.3.4', 24 | reason: 'PutObject' 25 | }, 26 | uuid: 'TEST_UUID', 27 | JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af', 28 | waitSeconds: 3, 29 | status: 'IN_PROGRESS', 30 | bucket: 'REDACTED', 31 | key: 'public/upload/room.mp4', 32 | failureReason: undefined 33 | } 34 | Passed Test for JobId 35 | Passed Test for status 36 | cached b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af as __JobId 37 | waiting for 3 second 38 | ***** now invoking getStatus ***** 39 | { 40 | version: '0', 41 | id: '17793124-05d4-b198-2fde-7ededc63b103', 42 | 'detail-type': 'Object Created', 43 | source: 'aws.s3', 44 | account: 'REDACTED', 45 | time: '2021-11-12T00:00:00Z', 46 | region: 'us-west-2', 47 | resources: [ 'REDACTED' ], 48 | detail: { 49 | version: '0', 50 | bucket: { name: 'REDACTED' }, 51 | object: { 52 | key: 'public/upload/room.mp4', 53 | size: 5, 54 | etag: 'b1946ac92492d2347c6235b4d2611184', 55 | 'version-id': 'IYV3p45BT0ac8hjHg1houSdS1a.Mro8e', 56 | sequencer: '00617F08299329D189' 57 | }, 58 | 'request-id': 'N4N7GDK58NMKJ12R', 59 | requester: 'REDACTED', 60 | 'source-ip-address': '1.2.3.4', 61 | reason: 'PutObject' 62 | }, 63 | uuid: 'TEST_UUID', 64 | JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af', 65 | waitSeconds: 3, 66 | status: 'NOT_CLEAR', 67 | bucket: 'REDACTED', 68 | key: 'public/upload/room.mp4', 69 | failureReason: undefined, 70 | __JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af' 71 | } 72 | Passed Unchanged Test for JobId 73 | Passed Test for uuid 74 | waiting for 3 second 75 | ***** invoking getStatus again ***** 76 | { 77 | version: '0', 78 | id: '17793124-05d4-b198-2fde-7ededc63b103', 79 | 'detail-type': 'Object Created', 80 | source: 'aws.s3', 81 | account: 'REDACTED', 82 | time: '2021-11-12T00:00:00Z', 83 | region: 'us-west-2', 84 | resources: [ 'REDACTED' ], 85 | detail: { 86 | version: '0', 87 | bucket: { name: 'REDACTED' }, 88 | object: { 89 | key: 'public/upload/room.mp4', 90 | size: 5, 91 | etag: 'b1946ac92492d2347c6235b4d2611184', 92 | 'version-id': 'IYV3p45BT0ac8hjHg1houSdS1a.Mro8e', 93 | sequencer: '00617F08299329D189' 94 | }, 95 | 'request-id': 'N4N7GDK58NMKJ12R', 96 | requester: 'REDACTED', 97 | 'source-ip-address': '1.2.3.4', 98 | reason: 'PutObject' 99 | }, 100 | uuid: 'TEST_UUID', 101 | JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af', 102 | waitSeconds: 3, 103 | status: 'NOT_CLEAR', 104 | bucket: 'REDACTED', 105 | key: 'public/upload/room.mp4', 106 | failureReason: undefined, 107 | __JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af' 108 | } 109 | Passed Test for uuid 110 | Passed Unchanged Test for JobId 111 | Passed Test for status 112 | ***** replicating to target bucket ***** 113 | { 114 | version: '0', 115 | id: '17793124-05d4-b198-2fde-7ededc63b103', 116 | 'detail-type': 'Object Created', 117 | source: 'aws.s3', 118 | account: 'REDACTED', 119 | time: '2021-11-12T00:00:00Z', 120 | region: 'us-west-2', 121 | resources: [ 'REDACTED' ], 122 | detail: { 123 | version: '0', 124 | bucket: { name: 'REDACTED' }, 125 | object: { 126 | key: 'public/upload/room.mp4', 127 | size: 5, 128 | etag: 'b1946ac92492d2347c6235b4d2611184', 129 | 'version-id': 'IYV3p45BT0ac8hjHg1houSdS1a.Mro8e', 130 | sequencer: '00617F08299329D189' 131 | }, 132 | 'request-id': 'N4N7GDK58NMKJ12R', 133 | requester: 'REDACTED', 134 | 'source-ip-address': '1.2.3.4', 135 | reason: 'PutObject' 136 | }, 137 | uuid: 'TEST_UUID', 138 | JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af', 139 | waitSeconds: 3, 140 | status: 'SUCCEEDED', 141 | bucket: 'REDACTED', 142 | key: 'public/upload/room.mp4', 143 | failureReason: undefined, 144 | __JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af' 145 | } 146 | Passed Unchanged Test for JobId 147 | Passed Test for uuid 148 | Passed Test for status 149 | ***** sending notification to SNS ***** 150 | { 151 | version: '0', 152 | id: '17793124-05d4-b198-2fde-7ededc63b103', 153 | 'detail-type': 'Object Created', 154 | source: 'aws.s3', 155 | account: 'REDACTED', 156 | time: '2021-11-12T00:00:00Z', 157 | region: 'us-west-2', 158 | resources: [ 'REDACTED' ], 159 | detail: { 160 | version: '0', 161 | bucket: { name: 'REDACTED' }, 162 | object: { 163 | key: 'public/upload/room.mp4', 164 | size: 5, 165 | etag: 'b1946ac92492d2347c6235b4d2611184', 166 | 'version-id': 'IYV3p45BT0ac8hjHg1houSdS1a.Mro8e', 167 | sequencer: '00617F08299329D189' 168 | }, 169 | 'request-id': 'N4N7GDK58NMKJ12R', 170 | requester: 'REDACTED', 171 | 'source-ip-address': '1.2.3.4', 172 | reason: 'PutObject' 173 | }, 174 | uuid: 'TEST_UUID', 175 | JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af', 176 | waitSeconds: 3, 177 | status: 'NOTIFIED', 178 | bucket: 'REDACTED', 179 | key: 'public/upload/room.mp4', 180 | failureReason: undefined, 181 | __JobId: 'b593f3d23bff56b6723ac0757d4fa4a75d76295af5f668302b2f1eacbf7175af' 182 | } 183 | Passed Unchanged Test for JobId 184 | Passed Test for uuid 185 | Passed Test for status 186 | -------------------------------------------------------------------------------- /app/index.e2e.js: -------------------------------------------------------------------------------- 1 | const { 2 | Payload, 3 | submit, 4 | getStatus, 5 | replicateToMIE, 6 | notifyModerationEvent 7 | } = require(".") 8 | 9 | const initialEvent = require("../assets/s3-event.json") 10 | 11 | let outputs 12 | 13 | try{ 14 | outputs = require('../assets/cdk-outputs.json') 15 | }catch(error){ 16 | console.log('End to End tests should run only after the stack is deployed.') 17 | console.log('missing output file in ../assets/cdk-outputs.json') 18 | console.error(error) 19 | 20 | process.exit(-1) 21 | } 22 | 23 | const stackName = 'BasupUgcStackStack' 24 | 25 | if(!stackName){ 26 | console.error('You should specify your stack name in this process environment') 27 | process.exit(-1) 28 | } 29 | 30 | const Stack = outputs[stackName] 31 | 32 | if(!Stack){ 33 | console.error(`Make sure you specified the right stack name. Current stack name = ${stackName}`) 34 | process.exit(-1) 35 | } 36 | 37 | const AWS = require('aws-sdk') 38 | const fsp = require('fs').promises 39 | 40 | async function startFlow(){ 41 | 42 | initialEvent.resources[0] = Stack.InspectionBucketArn 43 | initialEvent.region = Stack.DeploymentRegion 44 | initialEvent.detail.bucket.name = Stack.InspectionBucketName 45 | 46 | const s3 = new AWS.S3({region: Stack.DeploymentRegion }) 47 | 48 | const Body = await fsp.readFile('../assets/test.mp4') 49 | 50 | const uploadParams = { 51 | Bucket: Stack.InspectionBucketName, 52 | Key: 'public/upload/test.mp4', 53 | Body 54 | } 55 | 56 | console.log('Uploading test file to S3. This will also trigger actual workflow') 57 | 58 | try{ 59 | await s3.putObject(uploadParams).promise() 60 | }catch(error){ 61 | console.log('Could not upload file to S3. Are you sure you have permissions?') 62 | console.error(error) 63 | process.exit(-1) 64 | } 65 | 66 | const event_0 = Payload.fromEvent(initialEvent).toObject() 67 | const event_1 = await submit(event_0) 68 | 69 | return event_1 70 | } 71 | 72 | async function cleanup(){ 73 | 74 | const s3 = new AWS.S3({region: Stack.DeploymentRegion }) 75 | const deleteParams = { 76 | Bucket: Stack.InspectionBucketName, 77 | Key: 'public/upload/test.mp4' 78 | } 79 | 80 | console.log('Deleting Test S3 file') 81 | 82 | try{ 83 | await s3.deleteObject(deleteParams).promise() 84 | }catch(error){ 85 | console.log('Could not delete file to S3. Are you sure you have permissions?') 86 | console.error(error) 87 | process.exit(-1) 88 | } 89 | 90 | return null 91 | 92 | } 93 | 94 | async function delay(payload){ 95 | const { waitSeconds } = payload 96 | console.log(`waiting for ${waitSeconds} second`) 97 | await new Promise( 98 | (resolve, reject) => { 99 | setTimeout(resolve, waitSeconds * 1000) 100 | } 101 | ) 102 | 103 | return payload 104 | } 105 | 106 | const inspect = x => console.log(x) || x 107 | const comment = message => x => console.log(message) || x 108 | const assertEqual = (measuredLabel, expected) => data => { 109 | const { 110 | [measuredLabel]: measured 111 | } = data 112 | 113 | if(measured !== expected){ 114 | throw Error(`For ${measuredLabel} expected: ${expected} but got ${measured}`) 115 | } 116 | 117 | console.log(`Passed Test for ${measuredLabel}`) 118 | 119 | return data 120 | 121 | } 122 | const assertExists = (measuredLabel) => data => { 123 | const { 124 | [measuredLabel]: measured 125 | } = data 126 | 127 | if(measured === null || measured === undefined){ 128 | throw Error(`For ${measuredLabel} but got ${measured}, but expected non-null`) 129 | } 130 | 131 | console.log(`Passed Test for ${measuredLabel}`) 132 | return data 133 | 134 | } 135 | const assertUnchanged = (measuredLabel) => data => { 136 | const { 137 | [measuredLabel]: measured, 138 | [`__${measuredLabel}`]: previous 139 | } = data 140 | 141 | if(measured !== previous){ 142 | throw Error(`Assuming ${measuredLabel} is unchanged but received ${measured}; it should have been ${previous} `) 143 | } 144 | 145 | console.log(`Passed Unchanged Test for ${measuredLabel}`) 146 | return data 147 | } 148 | const cache = key => data => { 149 | data[`__${key}`] = data[key] 150 | console.log(`cached ${data[key]} as __${key}`) 151 | return data 152 | } 153 | 154 | if (!module.parent){ 155 | 156 | process.env = { 157 | ... process.env, 158 | MIE_S3_BUCKET: Stack.DestinationBucketName, 159 | AWS_REGION: Stack.DeploymentRegion, 160 | SNS_NOTIFICATION_TOPIC: Stack.SNSNotificationTopicArn, 161 | WAIT_SECONDS: 3 162 | } 163 | 164 | console.log("***** starting simulated flow *****") 165 | 166 | startFlow() 167 | .then(inspect) 168 | .then(assertExists("JobId")) 169 | .then(assertEqual("status", Payload.IN_PROGRESS)) 170 | .then(cache("JobId")) 171 | .then(delay) 172 | .then(comment("***** now invoking getStatus *****")) 173 | .then(getStatus) 174 | .then(inspect) 175 | .then(assertUnchanged("JobId")) 176 | .then(assertEqual("uuid", initialEvent.uuid)) 177 | .then(delay) 178 | .then(comment("***** invoking getStatus again *****")) 179 | .then(getStatus) 180 | .then(inspect) 181 | .then(assertEqual("uuid", initialEvent.uuid)) 182 | .then(assertUnchanged("JobId")) 183 | .then(assertEqual("status", Payload.NOT_CLEAR)) 184 | .then(comment("***** replicating to target bucket *****")) 185 | .then(replicateToMIE) 186 | .then(inspect) 187 | .then(assertUnchanged("JobId")) 188 | .then(assertEqual("uuid", initialEvent.uuid)) 189 | .then(assertEqual("status", Payload.SUCCEEDED)) 190 | .then(comment("***** sending notification to SNS *****")) 191 | .then(notifyModerationEvent) 192 | .then(inspect) 193 | .then(assertUnchanged("JobId")) 194 | .then(assertEqual("uuid", initialEvent.uuid)) 195 | .then(assertEqual("status", Payload.NOTIFIED)) 196 | .then(cleanup) 197 | .catch(console.error) 198 | 199 | } -------------------------------------------------------------------------------- /lib/basup-ugc-stack-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from 'aws-cdk-lib' 2 | import { Construct } from 'constructs' 3 | import * as S3 from 'aws-cdk-lib/aws-s3' 4 | import * as Events from 'aws-cdk-lib/aws-events' 5 | import * as Lambda from 'aws-cdk-lib/aws-lambda' 6 | import * as Targets from 'aws-cdk-lib/aws-events-targets' 7 | import * as SFn from 'aws-cdk-lib/aws-stepfunctions' 8 | import * as SFnTasks from 'aws-cdk-lib/aws-stepfunctions-tasks' 9 | import * as SNS from 'aws-cdk-lib/aws-sns' 10 | import * as IAM from 'aws-cdk-lib/aws-iam' 11 | import * as Logs from 'aws-cdk-lib/aws-logs' 12 | import * as path from 'path' 13 | 14 | export class BasupUgcStackStack extends cdk.Stack { 15 | constructor(scope: Construct, id: string, props?: cdk.StackProps) { 16 | super(scope, id, props) 17 | 18 | /* STACK PARAMETERS */ 19 | const replicationBucketName = new cdk.CfnParameter(this, 'replicationBucketName', { 20 | description: "Amazon S3 bucket name where to duplicate content for MIE ingestion", 21 | type: "String" 22 | }) 23 | 24 | const notificationEmailAddress = new cdk.CfnParameter(this, 'notificationEmailAddress', { 25 | description: "Email address where to send emails in case of a moderation event", 26 | type: "String" 27 | }) 28 | 29 | /* STACK UTILITIES */ 30 | const snsNotificationTopic = new SNS.Topic(this, "UGCModNotificationTopic", { 31 | displayName:"UGC Moderation Topic", 32 | fifo: false 33 | }) 34 | 35 | 36 | const subscription = new SNS.Subscription(this, "UGCModerationSubscription", { 37 | protocol: SNS.SubscriptionProtocol.EMAIL, 38 | endpoint: notificationEmailAddress.valueAsString, 39 | topic: snsNotificationTopic 40 | }) 41 | 42 | const UGCInspectionBucket = new S3.Bucket(this, 'UGCInspectionBucket', { 43 | eventBridgeEnabled: true, 44 | enforceSSL: true, 45 | blockPublicAccess: { 46 | blockPublicAcls: true, 47 | blockPublicPolicy: true, 48 | ignorePublicAcls: true, 49 | restrictPublicBuckets: true 50 | }, 51 | encryption: S3.BucketEncryption.S3_MANAGED 52 | 53 | }) 54 | 55 | UGCInspectionBucket.grantRead(new IAM.ServicePrincipal("rekognition.amazonaws.com")) 56 | 57 | const MIEReplicationBucket = S3.Bucket.fromBucketName( 58 | this, "MIEReplicationBucket", replicationBucketName.valueAsString 59 | ) 60 | 61 | const UGCInspectionRule = new Events.Rule(this, 'UGCInspectionRule', { 62 | eventPattern:{ 63 | "source": ["aws.s3"], 64 | "detailType": ["Object Created"], 65 | "detail": { 66 | "bucket": { 67 | "name": [UGCInspectionBucket.bucketName] 68 | }, 69 | "object": { 70 | "key": [{ 71 | "prefix": "public/upload/" 72 | }] 73 | } 74 | } 75 | } 76 | }) 77 | 78 | /* WORKFLOW LAMBDA FUNCTIONS */ 79 | 80 | const submitLambda = new Lambda.Function(this, 'UGCModSubmitJobLambda', { 81 | runtime: Lambda.Runtime.NODEJS_20_X, 82 | code: Lambda.Code.fromAsset(path.join(__dirname, "../app" )), 83 | architecture: Lambda.Architecture.ARM_64, 84 | handler: 'index.submit', 85 | timeout: cdk.Duration.minutes(3) 86 | }) 87 | 88 | const submitRekognitionJobPolicyStatement = new IAM.PolicyStatement({ 89 | actions: [ 90 | "rekognition:StartContentModeration" 91 | ], 92 | resources: ["*"] 93 | }) 94 | 95 | const submitRekognitionJobPolicy = new IAM.Policy(this, 'UGCMod-Reko-Put', { 96 | statements: [ 97 | submitRekognitionJobPolicyStatement 98 | ] 99 | }) 100 | 101 | submitLambda.role?.attachInlinePolicy(submitRekognitionJobPolicy) 102 | UGCInspectionBucket.grantRead(submitLambda) 103 | 104 | const getStatusLambda = new Lambda.Function(this, 'UGCModGetStatusLambda', { 105 | runtime: Lambda.Runtime.NODEJS_20_X, 106 | code: Lambda.Code.fromAsset(path.join(__dirname, "../app" )), 107 | architecture: Lambda.Architecture.ARM_64, 108 | handler: 'index.getStatus', 109 | timeout: cdk.Duration.minutes(3) 110 | }) 111 | 112 | const getRekognitionJobPolicyStatement = new IAM.PolicyStatement({ 113 | actions: [ 114 | "rekognition:GetContentModeration" 115 | ], 116 | resources: ["*"] 117 | }) 118 | 119 | const getRekognitionJobPolicy = new IAM.Policy(this, 'UGCMod-Reko-Read', { 120 | statements: [ 121 | getRekognitionJobPolicyStatement 122 | ] 123 | }) 124 | 125 | getStatusLambda.role?.attachInlinePolicy(getRekognitionJobPolicy) 126 | 127 | 128 | const replicateToMIELambda = new Lambda.Function(this, 'UGCModReplicateToMIELambda', { 129 | runtime: Lambda.Runtime.NODEJS_20_X, 130 | code: Lambda.Code.fromAsset(path.join(__dirname, "../app" )), 131 | architecture: Lambda.Architecture.ARM_64, 132 | handler: 'index.replicateToMIE', 133 | timeout: cdk.Duration.minutes(3), 134 | environment: { 135 | MIE_S3_BUCKET: MIEReplicationBucket.bucketName 136 | } 137 | }) 138 | 139 | UGCInspectionBucket.grantRead(replicateToMIELambda) 140 | MIEReplicationBucket.grantWrite(replicateToMIELambda) 141 | 142 | const notifyModerationEventLambda = new Lambda.Function(this, 'UGCnotifyModerationEventLambda', { 143 | runtime: Lambda.Runtime.NODEJS_20_X, 144 | code: Lambda.Code.fromAsset(path.join(__dirname, "../app" )), 145 | architecture: Lambda.Architecture.ARM_64, 146 | handler: 'index.notifyModerationEvent', 147 | timeout: cdk.Duration.minutes(3), 148 | environment:{ 149 | SNS_NOTIFICATION_TOPIC: snsNotificationTopic.topicArn 150 | } 151 | }) 152 | 153 | snsNotificationTopic.grantPublish(notifyModerationEventLambda) 154 | 155 | /* STEPFUNCTIONS WORKFLOW */ 156 | 157 | const submitJob = new SFnTasks.LambdaInvoke(this, 'Submit Job', { 158 | lambdaFunction: submitLambda, 159 | outputPath: '$.Payload', 160 | }) 161 | 162 | const waitX = new SFn.Wait(this, 'Wait X Seconds', { 163 | time: SFn.WaitTime.secondsPath('$.waitSeconds'), 164 | }) 165 | 166 | const getStatus = new SFnTasks.LambdaInvoke(this, 'Get Job Status', { 167 | lambdaFunction: getStatusLambda, 168 | outputPath: '$.Payload', 169 | }) 170 | 171 | const replicateToMIE = new SFnTasks.LambdaInvoke(this, 'Replicate to MIE Task', { 172 | lambdaFunction: replicateToMIELambda, 173 | outputPath: '$.Payload', 174 | }) 175 | 176 | const notifyModerationEvent = new SFnTasks.LambdaInvoke(this, 'Notify Moderation Event Task', { 177 | lambdaFunction: notifyModerationEventLambda, 178 | outputPath: '$.Payload', 179 | }) 180 | 181 | const jobFailed = new SFn.Fail(this, 'Job Failed', { 182 | cause: 'Rekognition Job failed', 183 | error: 'DescribeJob returned FAILED', 184 | }) 185 | 186 | const jobSucceeded = new SFn.Succeed(this, 'Job Succeeded', { 187 | comment: "Two possible success states: check for status. NOTIFIED | SUCCEEDED" 188 | }) 189 | 190 | const definition = submitJob 191 | .next(waitX) 192 | .next(getStatus) 193 | .next(new SFn.Choice(this, 'Job Complete?') 194 | .when(SFn.Condition.stringEquals('$.status', 'FAILED'), jobFailed) 195 | .when(SFn.Condition.stringEquals('$.status', 'CLEAR'), replicateToMIE.next(jobSucceeded)) 196 | .when(SFn.Condition.stringEquals('$.status', 'NOT_CLEAR'), notifyModerationEvent.next(jobSucceeded)) 197 | .otherwise(waitX)) 198 | 199 | const UGCModStateMachine = new SFn.StateMachine(this, 'StateMachine', { 200 | definition, 201 | timeout: cdk.Duration.minutes(30), 202 | tracingEnabled: true, 203 | logs:{ 204 | level: SFn.LogLevel.ALL, 205 | destination: new Logs.LogGroup(this, 'UGCModStateMachineLogs') 206 | } 207 | }) 208 | 209 | // Create an IAM role for Events to start the State Machine 210 | const eventsRole = new IAM.Role(this, 'UGCModEventsRuleRole', { 211 | assumedBy: new IAM.ServicePrincipal('events.amazonaws.com') 212 | }) 213 | 214 | UGCModStateMachine.grantStartExecution(eventsRole) 215 | 216 | const ruleTarget = new Targets.SfnStateMachine(UGCModStateMachine, { 217 | role: eventsRole 218 | }) 219 | 220 | UGCInspectionRule.addTarget(ruleTarget) 221 | 222 | new cdk.CfnOutput(this, 'InspectionBucketName', { 223 | value:UGCInspectionBucket.bucketName 224 | }) 225 | new cdk.CfnOutput(this, 'DestinationBucketName', { 226 | value:replicationBucketName.valueAsString 227 | }) 228 | new cdk.CfnOutput(this, 'InspectionBucketArn', { 229 | value:UGCInspectionBucket.bucketArn 230 | }) 231 | new cdk.CfnOutput(this, 'DestinationBucketArn', { 232 | value: MIEReplicationBucket.bucketArn 233 | }) 234 | new cdk.CfnOutput(this, 'NotificationEmailAddress', { 235 | value: notificationEmailAddress.valueAsString 236 | }) 237 | new cdk.CfnOutput(this, 'SNSNotificationTopicArn', { 238 | value: snsNotificationTopic.topicArn 239 | }) 240 | new cdk.CfnOutput(this, 'DeploymentRegion', { 241 | value: cdk.Stack.of(this).region 242 | }) 243 | 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | const { 2 | RekognitionClient, 3 | StartContentModerationCommand, 4 | GetContentModerationCommand 5 | } = require("@aws-sdk/client-rekognition") 6 | 7 | const { 8 | S3Client, CopyObjectCommand 9 | } = require("@aws-sdk/client-s3") 10 | 11 | const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns") 12 | 13 | const uuid = require("uuid") 14 | 15 | class Payload { 16 | 17 | static INITIALIZING = "INITIALIING" 18 | static FAILED = "FAILED" 19 | static IN_PROGRESS = "IN_PROGRESS" 20 | static CLEAR = "CLEAR" 21 | static SUCCEEDED = "SUCCEEDED" 22 | static NOT_CLEAR = "NOT_CLEAR" 23 | static NOTIFIED = "NOTIFIED" 24 | 25 | static FAILED_PARSE_S3 = "Failed to build Payload from event. Missing Bucket Name or Key" 26 | static WAIT_CONFIG_WARN = "Defaulting to 1 sec wait time." 27 | 28 | constructor(event){ 29 | this.event = event 30 | this.uuid = event.uuid? event.uuid : uuid.v4() 31 | this.JobId = event.JobId ? event.JobId : null 32 | this.waitSeconds = event.waitSeconds? event.waitSeconds : null 33 | this.status = event.status? event.status : null 34 | 35 | this.bucketName = event?.detail?.bucket?.name 36 | this.bucketKey = event?.detail?.object?.key 37 | 38 | if(!this.bucketName || !this.bucketKey){ 39 | this.setFailedStatus(Payload.FAILED_PARSE_S3) 40 | } 41 | 42 | } 43 | 44 | setFailedStatus(reason){ 45 | if(reason){ 46 | this.failedReason = reason 47 | } 48 | this.status = Payload.FAILED 49 | return this 50 | } 51 | setInProgressStatus(){ 52 | this.status = Payload.IN_PROGRESS 53 | return this 54 | } 55 | setClearStatus(){ 56 | this.status = Payload.CLEAR 57 | return this 58 | } 59 | setNotClearStatus(){ 60 | this.status = Payload.NOT_CLEAR 61 | return this 62 | } 63 | setInitializingStatus(){ 64 | this.status = Payload.INITIALIZING 65 | return this 66 | } 67 | setSucceededStatus(){ 68 | this.status = Payload.SUCCEEDED 69 | return this 70 | } 71 | setNotifiedStatus(){ 72 | this.status = Payload.NOTIFIED 73 | return this 74 | } 75 | 76 | setJobId(jobId){ 77 | this.JobId = jobId 78 | return this 79 | } 80 | 81 | wait(value){ 82 | let seconds = parseInt(value, 10) 83 | if(seconds <= 0 ){ 84 | console.warn(Payload.WAIT_CONFIG_WARN) 85 | seconds = 1 86 | } 87 | this.waitSeconds = seconds 88 | return this 89 | } 90 | 91 | toObject(){ 92 | return { 93 | ...this.event, 94 | JobId : this.JobId, 95 | waitSeconds: this.waitSeconds, 96 | status: this.status, 97 | bucket: this.bucketName, 98 | key: this.bucketKey, 99 | failureReason: this.failureReason, 100 | uuid: this.uuid 101 | } 102 | } 103 | 104 | toString(){ 105 | return JSON.stringify(this.toObject(), null, 2) 106 | } 107 | 108 | static fromEvent(event){ 109 | return new Payload(event) 110 | } 111 | } 112 | 113 | const submit = async event => { 114 | 115 | let { 116 | JOB_TAG, 117 | WAIT_SECONDS, 118 | MIN_CONFIDENCE 119 | } = process.env 120 | 121 | if(!JOB_TAG) 122 | JOB_TAG = "UGCMod-SubmitModerationJob" 123 | 124 | if(!WAIT_SECONDS) 125 | WAIT_SECONDS = 20 126 | 127 | if(!MIN_CONFIDENCE) 128 | MIN_CONFIDENCE = 60 129 | 130 | const payload = Payload.fromEvent(event) 131 | 132 | if(payload.status === Payload.FAILED){ 133 | console.log(JSON.stringify(event, null, 2)) 134 | console.error(payload.failedReason) 135 | 136 | return payload.wait(1).toObject() 137 | } 138 | 139 | const client = new RekognitionClient() 140 | 141 | const input = { 142 | ClientRequestToken: payload.uuid, 143 | JobTag: JOB_TAG, 144 | MinConfidence: MIN_CONFIDENCE, 145 | Video:{ 146 | S3Object: { 147 | Bucket: payload.toObject().bucket, 148 | Name: payload.toObject().key 149 | } 150 | } 151 | } 152 | 153 | const command = new StartContentModerationCommand(input) 154 | 155 | let response 156 | 157 | try{ 158 | response = await client.send(command) 159 | }catch(error){ 160 | payload.setFailedStatus(`Runtime Error: ${error}`) 161 | console.log(JSON.stringify(event, null, 2)) 162 | console.log(response) 163 | console.log(input) 164 | console.error(payload.failedReason) 165 | 166 | return payload.wait(1).toObject() 167 | } 168 | 169 | if(!response.JobId){ 170 | payload.setFailedStatus("Runtime Error: failed to get a JobId from Rekognition") 171 | console.log(JSON.stringify(event, null, 2)) 172 | console.log(response) 173 | console.log(input) 174 | console.error(payload.failedReason) 175 | 176 | return payload.wait(1).toObject() 177 | } 178 | 179 | payload.setInProgressStatus() 180 | payload.setJobId(response.JobId) 181 | 182 | return payload.wait(WAIT_SECONDS).toObject() 183 | 184 | } 185 | 186 | const getStatus = async event => { 187 | 188 | const payload = Payload.fromEvent(event) 189 | 190 | if(payload.status === Payload.FAILED){ 191 | console.log(JSON.stringify(event, null, 2)) 192 | console.error(payload.failedReason) 193 | 194 | return payload.toObject() 195 | } 196 | 197 | const client = new RekognitionClient() 198 | 199 | const input = { 200 | JobId: payload.toObject().JobId 201 | } 202 | 203 | const command = new GetContentModerationCommand(input) 204 | 205 | let response 206 | 207 | try{ 208 | response = await client.send(command) 209 | }catch(error){ 210 | payload.setFailedStatus(`Runtime Error: ${error}`) 211 | console.log(JSON.stringify(event, null, 2)) 212 | console.log(response) 213 | console.log(input) 214 | console.error(payload.failedReason) 215 | 216 | return payload.toObject() 217 | } 218 | 219 | const {JobStatus, ModerationLabels} = response 220 | 221 | if(ModerationLabels?.length > 0){ 222 | payload.setNotClearStatus() 223 | return payload.toObject() 224 | } 225 | 226 | if(!JobStatus || JobStatus === Payload.IN_PROGRESS){ 227 | return payload.toObject() 228 | } 229 | 230 | if(JobStatus === Payload.SUCCEEDED && ModerationLabels?.length === 0){ 231 | payload.setClearStatus() 232 | return payload.toObject() 233 | } 234 | 235 | } 236 | 237 | const replicateToMIE = async (event, context) => { 238 | 239 | const { MIE_S3_BUCKET, AWS_REGION } = process.env 240 | 241 | const { invokedFunctionArn } = context 242 | const accountId = invokedFunctionArn.split(':')[4] 243 | 244 | const payload = Payload.fromEvent(event) 245 | 246 | if(!MIE_S3_BUCKET){ 247 | payload.setFailedStatus("Runtime Error: MIE Destination bucket is not set") 248 | console.error(payload.failedReason) 249 | 250 | return payload.toObject() 251 | } 252 | 253 | if(MIE_S3_BUCKET === payload.toObject().bucket){ 254 | payload.setFailedStatus("Runtime Error: MIE Destination bucket cannot be the same as source bucket") 255 | console.error(payload.failedReason) 256 | 257 | return payload.toObject() 258 | } 259 | 260 | const s3Client = new S3Client({Region: AWS_REGION}) 261 | 262 | const input = { 263 | Bucket: MIE_S3_BUCKET, 264 | Key: payload.toObject().key, 265 | CopySource: encodeURI(`${payload.toObject().bucket}/${payload.toObject().key}`), 266 | ExpectedBucketOwner: accountId 267 | } 268 | 269 | const s3CopyCommand = new CopyObjectCommand(input) 270 | 271 | let response 272 | 273 | try{ 274 | response = await s3Client.send(s3CopyCommand) 275 | }catch(error){ 276 | payload.setFailedStatus("Runtime Error: Failed to copy object to MIE") 277 | console.error(payload.failedReason) 278 | console.log(error) 279 | 280 | return payload.wait(1).toObject() 281 | } 282 | 283 | payload.setSucceededStatus() 284 | return payload.toObject() 285 | } 286 | 287 | const notifyModerationEvent = async event => { 288 | const { SNS_NOTIFICATION_TOPIC } = process.env 289 | 290 | const payload = Payload.fromEvent(event) 291 | 292 | if(!SNS_NOTIFICATION_TOPIC){ 293 | payload.setFailedStatus("Runtime Error: SNS Notification tipic is not set") 294 | console.error(payload.failedReason) 295 | 296 | return payload.toObject() 297 | } 298 | 299 | const snsClient = new SNSClient(); 300 | 301 | const payloadObj = payload.toObject() 302 | 303 | const input = { 304 | TopicArn: SNS_NOTIFICATION_TOPIC, 305 | Subject: `New Moderation event`, 306 | Message: `New moderation event for ${payloadObj.bucket}/${payloadObj.key}, asset id: ${payloadObj.uuid}` 307 | } 308 | 309 | const publishCommand = new PublishCommand(input) 310 | 311 | let response 312 | 313 | try{ 314 | response = await snsClient.send(publishCommand) 315 | }catch(error){ 316 | payload.setFailedStatus("Runtime Error: Failed send SNS notification") 317 | console.error(payload.failedReason) 318 | console.log(error) 319 | 320 | return payload.wait(1).toObject() 321 | } 322 | 323 | payload.setNotifiedStatus() 324 | return payload.toObject() 325 | 326 | 327 | } 328 | 329 | module.exports = { 330 | Payload, 331 | submit, 332 | getStatus, 333 | replicateToMIE, 334 | notifyModerationEvent 335 | } 336 | -------------------------------------------------------------------------------- /app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "basup-ugcmod-app", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "basup-ugcmod-app", 9 | "version": "1.0.0", 10 | "license": "ISC", 11 | "devDependencies": { 12 | "@aws-sdk/client-rekognition": "^3.624.0", 13 | "@aws-sdk/client-s3": "^3.627.0", 14 | "@aws-sdk/client-sns": "^3.624.0" 15 | } 16 | }, 17 | "node_modules/@aws-crypto/crc32": { 18 | "version": "5.2.0", 19 | "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", 20 | "integrity": "sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==", 21 | "dev": true, 22 | "dependencies": { 23 | "@aws-crypto/util": "^5.2.0", 24 | "@aws-sdk/types": "^3.222.0", 25 | "tslib": "^2.6.2" 26 | }, 27 | "engines": { 28 | "node": ">=16.0.0" 29 | } 30 | }, 31 | "node_modules/@aws-crypto/crc32c": { 32 | "version": "5.2.0", 33 | "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz", 34 | "integrity": "sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag==", 35 | "dev": true, 36 | "dependencies": { 37 | "@aws-crypto/util": "^5.2.0", 38 | "@aws-sdk/types": "^3.222.0", 39 | "tslib": "^2.6.2" 40 | } 41 | }, 42 | "node_modules/@aws-crypto/sha1-browser": { 43 | "version": "5.2.0", 44 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz", 45 | "integrity": "sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg==", 46 | "dev": true, 47 | "dependencies": { 48 | "@aws-crypto/supports-web-crypto": "^5.2.0", 49 | "@aws-crypto/util": "^5.2.0", 50 | "@aws-sdk/types": "^3.222.0", 51 | "@aws-sdk/util-locate-window": "^3.0.0", 52 | "@smithy/util-utf8": "^2.0.0", 53 | "tslib": "^2.6.2" 54 | } 55 | }, 56 | "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/is-array-buffer": { 57 | "version": "2.2.0", 58 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", 59 | "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", 60 | "dev": true, 61 | "dependencies": { 62 | "tslib": "^2.6.2" 63 | }, 64 | "engines": { 65 | "node": ">=14.0.0" 66 | } 67 | }, 68 | "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-buffer-from": { 69 | "version": "2.2.0", 70 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", 71 | "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", 72 | "dev": true, 73 | "dependencies": { 74 | "@smithy/is-array-buffer": "^2.2.0", 75 | "tslib": "^2.6.2" 76 | }, 77 | "engines": { 78 | "node": ">=14.0.0" 79 | } 80 | }, 81 | "node_modules/@aws-crypto/sha1-browser/node_modules/@smithy/util-utf8": { 82 | "version": "2.3.0", 83 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", 84 | "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", 85 | "dev": true, 86 | "dependencies": { 87 | "@smithy/util-buffer-from": "^2.2.0", 88 | "tslib": "^2.6.2" 89 | }, 90 | "engines": { 91 | "node": ">=14.0.0" 92 | } 93 | }, 94 | "node_modules/@aws-crypto/sha256-browser": { 95 | "version": "5.2.0", 96 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", 97 | "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", 98 | "dev": true, 99 | "dependencies": { 100 | "@aws-crypto/sha256-js": "^5.2.0", 101 | "@aws-crypto/supports-web-crypto": "^5.2.0", 102 | "@aws-crypto/util": "^5.2.0", 103 | "@aws-sdk/types": "^3.222.0", 104 | "@aws-sdk/util-locate-window": "^3.0.0", 105 | "@smithy/util-utf8": "^2.0.0", 106 | "tslib": "^2.6.2" 107 | } 108 | }, 109 | "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { 110 | "version": "2.2.0", 111 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", 112 | "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", 113 | "dev": true, 114 | "dependencies": { 115 | "tslib": "^2.6.2" 116 | }, 117 | "engines": { 118 | "node": ">=14.0.0" 119 | } 120 | }, 121 | "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { 122 | "version": "2.2.0", 123 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", 124 | "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", 125 | "dev": true, 126 | "dependencies": { 127 | "@smithy/is-array-buffer": "^2.2.0", 128 | "tslib": "^2.6.2" 129 | }, 130 | "engines": { 131 | "node": ">=14.0.0" 132 | } 133 | }, 134 | "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { 135 | "version": "2.3.0", 136 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", 137 | "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", 138 | "dev": true, 139 | "dependencies": { 140 | "@smithy/util-buffer-from": "^2.2.0", 141 | "tslib": "^2.6.2" 142 | }, 143 | "engines": { 144 | "node": ">=14.0.0" 145 | } 146 | }, 147 | "node_modules/@aws-crypto/sha256-js": { 148 | "version": "5.2.0", 149 | "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", 150 | "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", 151 | "dev": true, 152 | "dependencies": { 153 | "@aws-crypto/util": "^5.2.0", 154 | "@aws-sdk/types": "^3.222.0", 155 | "tslib": "^2.6.2" 156 | }, 157 | "engines": { 158 | "node": ">=16.0.0" 159 | } 160 | }, 161 | "node_modules/@aws-crypto/supports-web-crypto": { 162 | "version": "5.2.0", 163 | "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", 164 | "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", 165 | "dev": true, 166 | "dependencies": { 167 | "tslib": "^2.6.2" 168 | } 169 | }, 170 | "node_modules/@aws-crypto/util": { 171 | "version": "5.2.0", 172 | "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", 173 | "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", 174 | "dev": true, 175 | "dependencies": { 176 | "@aws-sdk/types": "^3.222.0", 177 | "@smithy/util-utf8": "^2.0.0", 178 | "tslib": "^2.6.2" 179 | } 180 | }, 181 | "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { 182 | "version": "2.2.0", 183 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", 184 | "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", 185 | "dev": true, 186 | "dependencies": { 187 | "tslib": "^2.6.2" 188 | }, 189 | "engines": { 190 | "node": ">=14.0.0" 191 | } 192 | }, 193 | "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { 194 | "version": "2.2.0", 195 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", 196 | "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", 197 | "dev": true, 198 | "dependencies": { 199 | "@smithy/is-array-buffer": "^2.2.0", 200 | "tslib": "^2.6.2" 201 | }, 202 | "engines": { 203 | "node": ">=14.0.0" 204 | } 205 | }, 206 | "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { 207 | "version": "2.3.0", 208 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", 209 | "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", 210 | "dev": true, 211 | "dependencies": { 212 | "@smithy/util-buffer-from": "^2.2.0", 213 | "tslib": "^2.6.2" 214 | }, 215 | "engines": { 216 | "node": ">=14.0.0" 217 | } 218 | }, 219 | "node_modules/@aws-sdk/client-rekognition": { 220 | "version": "3.624.0", 221 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-rekognition/-/client-rekognition-3.624.0.tgz", 222 | "integrity": "sha512-ucOKn5RrpV6du+Zk+ozi6RGV93eSVam3gRCq9j9gR9CyS2/grlK5T3ANSxEnaQto+Db7zvKTti6cY36YobaWWw==", 223 | "dev": true, 224 | "dependencies": { 225 | "@aws-crypto/sha256-browser": "5.2.0", 226 | "@aws-crypto/sha256-js": "5.2.0", 227 | "@aws-sdk/client-sso-oidc": "3.624.0", 228 | "@aws-sdk/client-sts": "3.624.0", 229 | "@aws-sdk/core": "3.624.0", 230 | "@aws-sdk/credential-provider-node": "3.624.0", 231 | "@aws-sdk/middleware-host-header": "3.620.0", 232 | "@aws-sdk/middleware-logger": "3.609.0", 233 | "@aws-sdk/middleware-recursion-detection": "3.620.0", 234 | "@aws-sdk/middleware-user-agent": "3.620.0", 235 | "@aws-sdk/region-config-resolver": "3.614.0", 236 | "@aws-sdk/types": "3.609.0", 237 | "@aws-sdk/util-endpoints": "3.614.0", 238 | "@aws-sdk/util-user-agent-browser": "3.609.0", 239 | "@aws-sdk/util-user-agent-node": "3.614.0", 240 | "@smithy/config-resolver": "^3.0.5", 241 | "@smithy/core": "^2.3.2", 242 | "@smithy/fetch-http-handler": "^3.2.4", 243 | "@smithy/hash-node": "^3.0.3", 244 | "@smithy/invalid-dependency": "^3.0.3", 245 | "@smithy/middleware-content-length": "^3.0.5", 246 | "@smithy/middleware-endpoint": "^3.1.0", 247 | "@smithy/middleware-retry": "^3.0.14", 248 | "@smithy/middleware-serde": "^3.0.3", 249 | "@smithy/middleware-stack": "^3.0.3", 250 | "@smithy/node-config-provider": "^3.1.4", 251 | "@smithy/node-http-handler": "^3.1.4", 252 | "@smithy/protocol-http": "^4.1.0", 253 | "@smithy/smithy-client": "^3.1.12", 254 | "@smithy/types": "^3.3.0", 255 | "@smithy/url-parser": "^3.0.3", 256 | "@smithy/util-base64": "^3.0.0", 257 | "@smithy/util-body-length-browser": "^3.0.0", 258 | "@smithy/util-body-length-node": "^3.0.0", 259 | "@smithy/util-defaults-mode-browser": "^3.0.14", 260 | "@smithy/util-defaults-mode-node": "^3.0.14", 261 | "@smithy/util-endpoints": "^2.0.5", 262 | "@smithy/util-middleware": "^3.0.3", 263 | "@smithy/util-retry": "^3.0.3", 264 | "@smithy/util-utf8": "^3.0.0", 265 | "@smithy/util-waiter": "^3.1.2", 266 | "tslib": "^2.6.2", 267 | "uuid": "^9.0.1" 268 | }, 269 | "engines": { 270 | "node": ">=16.0.0" 271 | } 272 | }, 273 | "node_modules/@aws-sdk/client-s3": { 274 | "version": "3.627.0", 275 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.627.0.tgz", 276 | "integrity": "sha512-XTbtRLPVfq2lHo0SUP6HJb6HgBsKsJR54bhhVTwj5SZ4G26KOmx2iFOz9SgHie5apU7vWIhijb48LIhbLArgGg==", 277 | "dev": true, 278 | "dependencies": { 279 | "@aws-crypto/sha1-browser": "5.2.0", 280 | "@aws-crypto/sha256-browser": "5.2.0", 281 | "@aws-crypto/sha256-js": "5.2.0", 282 | "@aws-sdk/client-sso-oidc": "3.624.0", 283 | "@aws-sdk/client-sts": "3.624.0", 284 | "@aws-sdk/core": "3.624.0", 285 | "@aws-sdk/credential-provider-node": "3.624.0", 286 | "@aws-sdk/middleware-bucket-endpoint": "3.620.0", 287 | "@aws-sdk/middleware-expect-continue": "3.620.0", 288 | "@aws-sdk/middleware-flexible-checksums": "3.620.0", 289 | "@aws-sdk/middleware-host-header": "3.620.0", 290 | "@aws-sdk/middleware-location-constraint": "3.609.0", 291 | "@aws-sdk/middleware-logger": "3.609.0", 292 | "@aws-sdk/middleware-recursion-detection": "3.620.0", 293 | "@aws-sdk/middleware-sdk-s3": "3.626.0", 294 | "@aws-sdk/middleware-ssec": "3.609.0", 295 | "@aws-sdk/middleware-user-agent": "3.620.0", 296 | "@aws-sdk/region-config-resolver": "3.614.0", 297 | "@aws-sdk/signature-v4-multi-region": "3.626.0", 298 | "@aws-sdk/types": "3.609.0", 299 | "@aws-sdk/util-endpoints": "3.614.0", 300 | "@aws-sdk/util-user-agent-browser": "3.609.0", 301 | "@aws-sdk/util-user-agent-node": "3.614.0", 302 | "@aws-sdk/xml-builder": "3.609.0", 303 | "@smithy/config-resolver": "^3.0.5", 304 | "@smithy/core": "^2.3.2", 305 | "@smithy/eventstream-serde-browser": "^3.0.5", 306 | "@smithy/eventstream-serde-config-resolver": "^3.0.3", 307 | "@smithy/eventstream-serde-node": "^3.0.4", 308 | "@smithy/fetch-http-handler": "^3.2.4", 309 | "@smithy/hash-blob-browser": "^3.1.2", 310 | "@smithy/hash-node": "^3.0.3", 311 | "@smithy/hash-stream-node": "^3.1.2", 312 | "@smithy/invalid-dependency": "^3.0.3", 313 | "@smithy/md5-js": "^3.0.3", 314 | "@smithy/middleware-content-length": "^3.0.5", 315 | "@smithy/middleware-endpoint": "^3.1.0", 316 | "@smithy/middleware-retry": "^3.0.14", 317 | "@smithy/middleware-serde": "^3.0.3", 318 | "@smithy/middleware-stack": "^3.0.3", 319 | "@smithy/node-config-provider": "^3.1.4", 320 | "@smithy/node-http-handler": "^3.1.4", 321 | "@smithy/protocol-http": "^4.1.0", 322 | "@smithy/smithy-client": "^3.1.12", 323 | "@smithy/types": "^3.3.0", 324 | "@smithy/url-parser": "^3.0.3", 325 | "@smithy/util-base64": "^3.0.0", 326 | "@smithy/util-body-length-browser": "^3.0.0", 327 | "@smithy/util-body-length-node": "^3.0.0", 328 | "@smithy/util-defaults-mode-browser": "^3.0.14", 329 | "@smithy/util-defaults-mode-node": "^3.0.14", 330 | "@smithy/util-endpoints": "^2.0.5", 331 | "@smithy/util-middleware": "^3.0.3", 332 | "@smithy/util-retry": "^3.0.3", 333 | "@smithy/util-stream": "^3.1.3", 334 | "@smithy/util-utf8": "^3.0.0", 335 | "@smithy/util-waiter": "^3.1.2", 336 | "tslib": "^2.6.2" 337 | }, 338 | "engines": { 339 | "node": ">=16.0.0" 340 | } 341 | }, 342 | "node_modules/@aws-sdk/client-sns": { 343 | "version": "3.624.0", 344 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.624.0.tgz", 345 | "integrity": "sha512-GjK1rTAQmSVd7Q2QYdWf0GT8hNoR2LjDaGlCyJUDzdvtpVMriV1Yvq5p8ACgc4qkArEIVNZ0iaPgzpn56OOEBA==", 346 | "dev": true, 347 | "dependencies": { 348 | "@aws-crypto/sha256-browser": "5.2.0", 349 | "@aws-crypto/sha256-js": "5.2.0", 350 | "@aws-sdk/client-sso-oidc": "3.624.0", 351 | "@aws-sdk/client-sts": "3.624.0", 352 | "@aws-sdk/core": "3.624.0", 353 | "@aws-sdk/credential-provider-node": "3.624.0", 354 | "@aws-sdk/middleware-host-header": "3.620.0", 355 | "@aws-sdk/middleware-logger": "3.609.0", 356 | "@aws-sdk/middleware-recursion-detection": "3.620.0", 357 | "@aws-sdk/middleware-user-agent": "3.620.0", 358 | "@aws-sdk/region-config-resolver": "3.614.0", 359 | "@aws-sdk/types": "3.609.0", 360 | "@aws-sdk/util-endpoints": "3.614.0", 361 | "@aws-sdk/util-user-agent-browser": "3.609.0", 362 | "@aws-sdk/util-user-agent-node": "3.614.0", 363 | "@smithy/config-resolver": "^3.0.5", 364 | "@smithy/core": "^2.3.2", 365 | "@smithy/fetch-http-handler": "^3.2.4", 366 | "@smithy/hash-node": "^3.0.3", 367 | "@smithy/invalid-dependency": "^3.0.3", 368 | "@smithy/middleware-content-length": "^3.0.5", 369 | "@smithy/middleware-endpoint": "^3.1.0", 370 | "@smithy/middleware-retry": "^3.0.14", 371 | "@smithy/middleware-serde": "^3.0.3", 372 | "@smithy/middleware-stack": "^3.0.3", 373 | "@smithy/node-config-provider": "^3.1.4", 374 | "@smithy/node-http-handler": "^3.1.4", 375 | "@smithy/protocol-http": "^4.1.0", 376 | "@smithy/smithy-client": "^3.1.12", 377 | "@smithy/types": "^3.3.0", 378 | "@smithy/url-parser": "^3.0.3", 379 | "@smithy/util-base64": "^3.0.0", 380 | "@smithy/util-body-length-browser": "^3.0.0", 381 | "@smithy/util-body-length-node": "^3.0.0", 382 | "@smithy/util-defaults-mode-browser": "^3.0.14", 383 | "@smithy/util-defaults-mode-node": "^3.0.14", 384 | "@smithy/util-endpoints": "^2.0.5", 385 | "@smithy/util-middleware": "^3.0.3", 386 | "@smithy/util-retry": "^3.0.3", 387 | "@smithy/util-utf8": "^3.0.0", 388 | "tslib": "^2.6.2" 389 | }, 390 | "engines": { 391 | "node": ">=16.0.0" 392 | } 393 | }, 394 | "node_modules/@aws-sdk/client-sso": { 395 | "version": "3.624.0", 396 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.624.0.tgz", 397 | "integrity": "sha512-EX6EF+rJzMPC5dcdsu40xSi2To7GSvdGQNIpe97pD9WvZwM9tRNQnNM4T6HA4gjV1L6Jwk8rBlG/CnveXtLEMw==", 398 | "dev": true, 399 | "dependencies": { 400 | "@aws-crypto/sha256-browser": "5.2.0", 401 | "@aws-crypto/sha256-js": "5.2.0", 402 | "@aws-sdk/core": "3.624.0", 403 | "@aws-sdk/middleware-host-header": "3.620.0", 404 | "@aws-sdk/middleware-logger": "3.609.0", 405 | "@aws-sdk/middleware-recursion-detection": "3.620.0", 406 | "@aws-sdk/middleware-user-agent": "3.620.0", 407 | "@aws-sdk/region-config-resolver": "3.614.0", 408 | "@aws-sdk/types": "3.609.0", 409 | "@aws-sdk/util-endpoints": "3.614.0", 410 | "@aws-sdk/util-user-agent-browser": "3.609.0", 411 | "@aws-sdk/util-user-agent-node": "3.614.0", 412 | "@smithy/config-resolver": "^3.0.5", 413 | "@smithy/core": "^2.3.2", 414 | "@smithy/fetch-http-handler": "^3.2.4", 415 | "@smithy/hash-node": "^3.0.3", 416 | "@smithy/invalid-dependency": "^3.0.3", 417 | "@smithy/middleware-content-length": "^3.0.5", 418 | "@smithy/middleware-endpoint": "^3.1.0", 419 | "@smithy/middleware-retry": "^3.0.14", 420 | "@smithy/middleware-serde": "^3.0.3", 421 | "@smithy/middleware-stack": "^3.0.3", 422 | "@smithy/node-config-provider": "^3.1.4", 423 | "@smithy/node-http-handler": "^3.1.4", 424 | "@smithy/protocol-http": "^4.1.0", 425 | "@smithy/smithy-client": "^3.1.12", 426 | "@smithy/types": "^3.3.0", 427 | "@smithy/url-parser": "^3.0.3", 428 | "@smithy/util-base64": "^3.0.0", 429 | "@smithy/util-body-length-browser": "^3.0.0", 430 | "@smithy/util-body-length-node": "^3.0.0", 431 | "@smithy/util-defaults-mode-browser": "^3.0.14", 432 | "@smithy/util-defaults-mode-node": "^3.0.14", 433 | "@smithy/util-endpoints": "^2.0.5", 434 | "@smithy/util-middleware": "^3.0.3", 435 | "@smithy/util-retry": "^3.0.3", 436 | "@smithy/util-utf8": "^3.0.0", 437 | "tslib": "^2.6.2" 438 | }, 439 | "engines": { 440 | "node": ">=16.0.0" 441 | } 442 | }, 443 | "node_modules/@aws-sdk/client-sso-oidc": { 444 | "version": "3.624.0", 445 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.624.0.tgz", 446 | "integrity": "sha512-Ki2uKYJKKtfHxxZsiMTOvJoVRP6b2pZ1u3rcUb2m/nVgBPUfLdl8ZkGpqE29I+t5/QaS/sEdbn6cgMUZwl+3Dg==", 447 | "dev": true, 448 | "dependencies": { 449 | "@aws-crypto/sha256-browser": "5.2.0", 450 | "@aws-crypto/sha256-js": "5.2.0", 451 | "@aws-sdk/core": "3.624.0", 452 | "@aws-sdk/credential-provider-node": "3.624.0", 453 | "@aws-sdk/middleware-host-header": "3.620.0", 454 | "@aws-sdk/middleware-logger": "3.609.0", 455 | "@aws-sdk/middleware-recursion-detection": "3.620.0", 456 | "@aws-sdk/middleware-user-agent": "3.620.0", 457 | "@aws-sdk/region-config-resolver": "3.614.0", 458 | "@aws-sdk/types": "3.609.0", 459 | "@aws-sdk/util-endpoints": "3.614.0", 460 | "@aws-sdk/util-user-agent-browser": "3.609.0", 461 | "@aws-sdk/util-user-agent-node": "3.614.0", 462 | "@smithy/config-resolver": "^3.0.5", 463 | "@smithy/core": "^2.3.2", 464 | "@smithy/fetch-http-handler": "^3.2.4", 465 | "@smithy/hash-node": "^3.0.3", 466 | "@smithy/invalid-dependency": "^3.0.3", 467 | "@smithy/middleware-content-length": "^3.0.5", 468 | "@smithy/middleware-endpoint": "^3.1.0", 469 | "@smithy/middleware-retry": "^3.0.14", 470 | "@smithy/middleware-serde": "^3.0.3", 471 | "@smithy/middleware-stack": "^3.0.3", 472 | "@smithy/node-config-provider": "^3.1.4", 473 | "@smithy/node-http-handler": "^3.1.4", 474 | "@smithy/protocol-http": "^4.1.0", 475 | "@smithy/smithy-client": "^3.1.12", 476 | "@smithy/types": "^3.3.0", 477 | "@smithy/url-parser": "^3.0.3", 478 | "@smithy/util-base64": "^3.0.0", 479 | "@smithy/util-body-length-browser": "^3.0.0", 480 | "@smithy/util-body-length-node": "^3.0.0", 481 | "@smithy/util-defaults-mode-browser": "^3.0.14", 482 | "@smithy/util-defaults-mode-node": "^3.0.14", 483 | "@smithy/util-endpoints": "^2.0.5", 484 | "@smithy/util-middleware": "^3.0.3", 485 | "@smithy/util-retry": "^3.0.3", 486 | "@smithy/util-utf8": "^3.0.0", 487 | "tslib": "^2.6.2" 488 | }, 489 | "engines": { 490 | "node": ">=16.0.0" 491 | }, 492 | "peerDependencies": { 493 | "@aws-sdk/client-sts": "^3.624.0" 494 | } 495 | }, 496 | "node_modules/@aws-sdk/client-sts": { 497 | "version": "3.624.0", 498 | "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.624.0.tgz", 499 | "integrity": "sha512-k36fLZCb2nfoV/DKK3jbRgO/Yf7/R80pgYfMiotkGjnZwDmRvNN08z4l06L9C+CieazzkgRxNUzyppsYcYsQaw==", 500 | "dev": true, 501 | "dependencies": { 502 | "@aws-crypto/sha256-browser": "5.2.0", 503 | "@aws-crypto/sha256-js": "5.2.0", 504 | "@aws-sdk/client-sso-oidc": "3.624.0", 505 | "@aws-sdk/core": "3.624.0", 506 | "@aws-sdk/credential-provider-node": "3.624.0", 507 | "@aws-sdk/middleware-host-header": "3.620.0", 508 | "@aws-sdk/middleware-logger": "3.609.0", 509 | "@aws-sdk/middleware-recursion-detection": "3.620.0", 510 | "@aws-sdk/middleware-user-agent": "3.620.0", 511 | "@aws-sdk/region-config-resolver": "3.614.0", 512 | "@aws-sdk/types": "3.609.0", 513 | "@aws-sdk/util-endpoints": "3.614.0", 514 | "@aws-sdk/util-user-agent-browser": "3.609.0", 515 | "@aws-sdk/util-user-agent-node": "3.614.0", 516 | "@smithy/config-resolver": "^3.0.5", 517 | "@smithy/core": "^2.3.2", 518 | "@smithy/fetch-http-handler": "^3.2.4", 519 | "@smithy/hash-node": "^3.0.3", 520 | "@smithy/invalid-dependency": "^3.0.3", 521 | "@smithy/middleware-content-length": "^3.0.5", 522 | "@smithy/middleware-endpoint": "^3.1.0", 523 | "@smithy/middleware-retry": "^3.0.14", 524 | "@smithy/middleware-serde": "^3.0.3", 525 | "@smithy/middleware-stack": "^3.0.3", 526 | "@smithy/node-config-provider": "^3.1.4", 527 | "@smithy/node-http-handler": "^3.1.4", 528 | "@smithy/protocol-http": "^4.1.0", 529 | "@smithy/smithy-client": "^3.1.12", 530 | "@smithy/types": "^3.3.0", 531 | "@smithy/url-parser": "^3.0.3", 532 | "@smithy/util-base64": "^3.0.0", 533 | "@smithy/util-body-length-browser": "^3.0.0", 534 | "@smithy/util-body-length-node": "^3.0.0", 535 | "@smithy/util-defaults-mode-browser": "^3.0.14", 536 | "@smithy/util-defaults-mode-node": "^3.0.14", 537 | "@smithy/util-endpoints": "^2.0.5", 538 | "@smithy/util-middleware": "^3.0.3", 539 | "@smithy/util-retry": "^3.0.3", 540 | "@smithy/util-utf8": "^3.0.0", 541 | "tslib": "^2.6.2" 542 | }, 543 | "engines": { 544 | "node": ">=16.0.0" 545 | } 546 | }, 547 | "node_modules/@aws-sdk/core": { 548 | "version": "3.624.0", 549 | "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.624.0.tgz", 550 | "integrity": "sha512-WyFmPbhRIvtWi7hBp8uSFy+iPpj8ccNV/eX86hwF4irMjfc/FtsGVIAeBXxXM/vGCjkdfEzOnl+tJ2XACD4OXg==", 551 | "dev": true, 552 | "dependencies": { 553 | "@smithy/core": "^2.3.2", 554 | "@smithy/node-config-provider": "^3.1.4", 555 | "@smithy/protocol-http": "^4.1.0", 556 | "@smithy/signature-v4": "^4.1.0", 557 | "@smithy/smithy-client": "^3.1.12", 558 | "@smithy/types": "^3.3.0", 559 | "@smithy/util-middleware": "^3.0.3", 560 | "fast-xml-parser": "4.4.1", 561 | "tslib": "^2.6.2" 562 | }, 563 | "engines": { 564 | "node": ">=16.0.0" 565 | } 566 | }, 567 | "node_modules/@aws-sdk/credential-provider-env": { 568 | "version": "3.620.1", 569 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", 570 | "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", 571 | "dev": true, 572 | "dependencies": { 573 | "@aws-sdk/types": "3.609.0", 574 | "@smithy/property-provider": "^3.1.3", 575 | "@smithy/types": "^3.3.0", 576 | "tslib": "^2.6.2" 577 | }, 578 | "engines": { 579 | "node": ">=16.0.0" 580 | } 581 | }, 582 | "node_modules/@aws-sdk/credential-provider-http": { 583 | "version": "3.622.0", 584 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", 585 | "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", 586 | "dev": true, 587 | "dependencies": { 588 | "@aws-sdk/types": "3.609.0", 589 | "@smithy/fetch-http-handler": "^3.2.4", 590 | "@smithy/node-http-handler": "^3.1.4", 591 | "@smithy/property-provider": "^3.1.3", 592 | "@smithy/protocol-http": "^4.1.0", 593 | "@smithy/smithy-client": "^3.1.12", 594 | "@smithy/types": "^3.3.0", 595 | "@smithy/util-stream": "^3.1.3", 596 | "tslib": "^2.6.2" 597 | }, 598 | "engines": { 599 | "node": ">=16.0.0" 600 | } 601 | }, 602 | "node_modules/@aws-sdk/credential-provider-ini": { 603 | "version": "3.624.0", 604 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.624.0.tgz", 605 | "integrity": "sha512-mMoNIy7MO2WTBbdqMyLpbt6SZpthE6e0GkRYpsd0yozPt0RZopcBhEh+HG1U9Y1PVODo+jcMk353vAi61CfnhQ==", 606 | "dev": true, 607 | "dependencies": { 608 | "@aws-sdk/credential-provider-env": "3.620.1", 609 | "@aws-sdk/credential-provider-http": "3.622.0", 610 | "@aws-sdk/credential-provider-process": "3.620.1", 611 | "@aws-sdk/credential-provider-sso": "3.624.0", 612 | "@aws-sdk/credential-provider-web-identity": "3.621.0", 613 | "@aws-sdk/types": "3.609.0", 614 | "@smithy/credential-provider-imds": "^3.2.0", 615 | "@smithy/property-provider": "^3.1.3", 616 | "@smithy/shared-ini-file-loader": "^3.1.4", 617 | "@smithy/types": "^3.3.0", 618 | "tslib": "^2.6.2" 619 | }, 620 | "engines": { 621 | "node": ">=16.0.0" 622 | }, 623 | "peerDependencies": { 624 | "@aws-sdk/client-sts": "^3.624.0" 625 | } 626 | }, 627 | "node_modules/@aws-sdk/credential-provider-node": { 628 | "version": "3.624.0", 629 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.624.0.tgz", 630 | "integrity": "sha512-vYyGK7oNpd81BdbH5IlmQ6zfaQqU+rPwsKTDDBeLRjshtrGXOEpfoahVpG9PX0ibu32IOWp4ZyXBNyVrnvcMOw==", 631 | "dev": true, 632 | "dependencies": { 633 | "@aws-sdk/credential-provider-env": "3.620.1", 634 | "@aws-sdk/credential-provider-http": "3.622.0", 635 | "@aws-sdk/credential-provider-ini": "3.624.0", 636 | "@aws-sdk/credential-provider-process": "3.620.1", 637 | "@aws-sdk/credential-provider-sso": "3.624.0", 638 | "@aws-sdk/credential-provider-web-identity": "3.621.0", 639 | "@aws-sdk/types": "3.609.0", 640 | "@smithy/credential-provider-imds": "^3.2.0", 641 | "@smithy/property-provider": "^3.1.3", 642 | "@smithy/shared-ini-file-loader": "^3.1.4", 643 | "@smithy/types": "^3.3.0", 644 | "tslib": "^2.6.2" 645 | }, 646 | "engines": { 647 | "node": ">=16.0.0" 648 | } 649 | }, 650 | "node_modules/@aws-sdk/credential-provider-process": { 651 | "version": "3.620.1", 652 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", 653 | "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", 654 | "dev": true, 655 | "dependencies": { 656 | "@aws-sdk/types": "3.609.0", 657 | "@smithy/property-provider": "^3.1.3", 658 | "@smithy/shared-ini-file-loader": "^3.1.4", 659 | "@smithy/types": "^3.3.0", 660 | "tslib": "^2.6.2" 661 | }, 662 | "engines": { 663 | "node": ">=16.0.0" 664 | } 665 | }, 666 | "node_modules/@aws-sdk/credential-provider-sso": { 667 | "version": "3.624.0", 668 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.624.0.tgz", 669 | "integrity": "sha512-A02bayIjU9APEPKr3HudrFHEx0WfghoSPsPopckDkW7VBqO4wizzcxr75Q9A3vNX+cwg0wCN6UitTNe6pVlRaQ==", 670 | "dev": true, 671 | "dependencies": { 672 | "@aws-sdk/client-sso": "3.624.0", 673 | "@aws-sdk/token-providers": "3.614.0", 674 | "@aws-sdk/types": "3.609.0", 675 | "@smithy/property-provider": "^3.1.3", 676 | "@smithy/shared-ini-file-loader": "^3.1.4", 677 | "@smithy/types": "^3.3.0", 678 | "tslib": "^2.6.2" 679 | }, 680 | "engines": { 681 | "node": ">=16.0.0" 682 | } 683 | }, 684 | "node_modules/@aws-sdk/credential-provider-web-identity": { 685 | "version": "3.621.0", 686 | "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", 687 | "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", 688 | "dev": true, 689 | "dependencies": { 690 | "@aws-sdk/types": "3.609.0", 691 | "@smithy/property-provider": "^3.1.3", 692 | "@smithy/types": "^3.3.0", 693 | "tslib": "^2.6.2" 694 | }, 695 | "engines": { 696 | "node": ">=16.0.0" 697 | }, 698 | "peerDependencies": { 699 | "@aws-sdk/client-sts": "^3.621.0" 700 | } 701 | }, 702 | "node_modules/@aws-sdk/middleware-bucket-endpoint": { 703 | "version": "3.620.0", 704 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.620.0.tgz", 705 | "integrity": "sha512-eGLL0W6L3HDb3OACyetZYOWpHJ+gLo0TehQKeQyy2G8vTYXqNTeqYhuI6up9HVjBzU9eQiULVQETmgQs7TFaRg==", 706 | "dev": true, 707 | "dependencies": { 708 | "@aws-sdk/types": "3.609.0", 709 | "@aws-sdk/util-arn-parser": "3.568.0", 710 | "@smithy/node-config-provider": "^3.1.4", 711 | "@smithy/protocol-http": "^4.1.0", 712 | "@smithy/types": "^3.3.0", 713 | "@smithy/util-config-provider": "^3.0.0", 714 | "tslib": "^2.6.2" 715 | }, 716 | "engines": { 717 | "node": ">=16.0.0" 718 | } 719 | }, 720 | "node_modules/@aws-sdk/middleware-expect-continue": { 721 | "version": "3.620.0", 722 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.620.0.tgz", 723 | "integrity": "sha512-QXeRFMLfyQ31nAHLbiTLtk0oHzG9QLMaof5jIfqcUwnOkO8YnQdeqzakrg1Alpy/VQ7aqzIi8qypkBe2KXZz0A==", 724 | "dev": true, 725 | "dependencies": { 726 | "@aws-sdk/types": "3.609.0", 727 | "@smithy/protocol-http": "^4.1.0", 728 | "@smithy/types": "^3.3.0", 729 | "tslib": "^2.6.2" 730 | }, 731 | "engines": { 732 | "node": ">=16.0.0" 733 | } 734 | }, 735 | "node_modules/@aws-sdk/middleware-flexible-checksums": { 736 | "version": "3.620.0", 737 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.620.0.tgz", 738 | "integrity": "sha512-ftz+NW7qka2sVuwnnO1IzBku5ccP+s5qZGeRTPgrKB7OzRW85gthvIo1vQR2w+OwHFk7WJbbhhWwbCbktnP4UA==", 739 | "dev": true, 740 | "dependencies": { 741 | "@aws-crypto/crc32": "5.2.0", 742 | "@aws-crypto/crc32c": "5.2.0", 743 | "@aws-sdk/types": "3.609.0", 744 | "@smithy/is-array-buffer": "^3.0.0", 745 | "@smithy/protocol-http": "^4.1.0", 746 | "@smithy/types": "^3.3.0", 747 | "@smithy/util-utf8": "^3.0.0", 748 | "tslib": "^2.6.2" 749 | }, 750 | "engines": { 751 | "node": ">=16.0.0" 752 | } 753 | }, 754 | "node_modules/@aws-sdk/middleware-host-header": { 755 | "version": "3.620.0", 756 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", 757 | "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", 758 | "dev": true, 759 | "dependencies": { 760 | "@aws-sdk/types": "3.609.0", 761 | "@smithy/protocol-http": "^4.1.0", 762 | "@smithy/types": "^3.3.0", 763 | "tslib": "^2.6.2" 764 | }, 765 | "engines": { 766 | "node": ">=16.0.0" 767 | } 768 | }, 769 | "node_modules/@aws-sdk/middleware-location-constraint": { 770 | "version": "3.609.0", 771 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.609.0.tgz", 772 | "integrity": "sha512-xzsdoTkszGVqGVPjUmgoP7TORiByLueMHieI1fhQL888WPdqctwAx3ES6d/bA9Q/i8jnc6hs+Fjhy8UvBTkE9A==", 773 | "dev": true, 774 | "dependencies": { 775 | "@aws-sdk/types": "3.609.0", 776 | "@smithy/types": "^3.3.0", 777 | "tslib": "^2.6.2" 778 | }, 779 | "engines": { 780 | "node": ">=16.0.0" 781 | } 782 | }, 783 | "node_modules/@aws-sdk/middleware-logger": { 784 | "version": "3.609.0", 785 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", 786 | "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", 787 | "dev": true, 788 | "dependencies": { 789 | "@aws-sdk/types": "3.609.0", 790 | "@smithy/types": "^3.3.0", 791 | "tslib": "^2.6.2" 792 | }, 793 | "engines": { 794 | "node": ">=16.0.0" 795 | } 796 | }, 797 | "node_modules/@aws-sdk/middleware-recursion-detection": { 798 | "version": "3.620.0", 799 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", 800 | "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", 801 | "dev": true, 802 | "dependencies": { 803 | "@aws-sdk/types": "3.609.0", 804 | "@smithy/protocol-http": "^4.1.0", 805 | "@smithy/types": "^3.3.0", 806 | "tslib": "^2.6.2" 807 | }, 808 | "engines": { 809 | "node": ">=16.0.0" 810 | } 811 | }, 812 | "node_modules/@aws-sdk/middleware-sdk-s3": { 813 | "version": "3.626.0", 814 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.626.0.tgz", 815 | "integrity": "sha512-frFh6GQ1OEGueB0fL6Ft5rdHF+eu8JZUREjeBNEcg1qRqtMpPOlYkKzJ434d4zo+JHSK5xKFeb/Gu/kvB4LxEA==", 816 | "dev": true, 817 | "dependencies": { 818 | "@aws-sdk/core": "3.624.0", 819 | "@aws-sdk/types": "3.609.0", 820 | "@aws-sdk/util-arn-parser": "3.568.0", 821 | "@smithy/core": "^2.3.2", 822 | "@smithy/node-config-provider": "^3.1.4", 823 | "@smithy/protocol-http": "^4.1.0", 824 | "@smithy/signature-v4": "^4.1.0", 825 | "@smithy/smithy-client": "^3.1.12", 826 | "@smithy/types": "^3.3.0", 827 | "@smithy/util-config-provider": "^3.0.0", 828 | "@smithy/util-middleware": "^3.0.3", 829 | "@smithy/util-stream": "^3.1.3", 830 | "@smithy/util-utf8": "^3.0.0", 831 | "tslib": "^2.6.2" 832 | }, 833 | "engines": { 834 | "node": ">=16.0.0" 835 | } 836 | }, 837 | "node_modules/@aws-sdk/middleware-ssec": { 838 | "version": "3.609.0", 839 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.609.0.tgz", 840 | "integrity": "sha512-GZSD1s7+JswWOTamVap79QiDaIV7byJFssBW68GYjyRS5EBjNfwA/8s+6uE6g39R3ojyTbYOmvcANoZEhSULXg==", 841 | "dev": true, 842 | "dependencies": { 843 | "@aws-sdk/types": "3.609.0", 844 | "@smithy/types": "^3.3.0", 845 | "tslib": "^2.6.2" 846 | }, 847 | "engines": { 848 | "node": ">=16.0.0" 849 | } 850 | }, 851 | "node_modules/@aws-sdk/middleware-user-agent": { 852 | "version": "3.620.0", 853 | "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", 854 | "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", 855 | "dev": true, 856 | "dependencies": { 857 | "@aws-sdk/types": "3.609.0", 858 | "@aws-sdk/util-endpoints": "3.614.0", 859 | "@smithy/protocol-http": "^4.1.0", 860 | "@smithy/types": "^3.3.0", 861 | "tslib": "^2.6.2" 862 | }, 863 | "engines": { 864 | "node": ">=16.0.0" 865 | } 866 | }, 867 | "node_modules/@aws-sdk/region-config-resolver": { 868 | "version": "3.614.0", 869 | "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", 870 | "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", 871 | "dev": true, 872 | "dependencies": { 873 | "@aws-sdk/types": "3.609.0", 874 | "@smithy/node-config-provider": "^3.1.4", 875 | "@smithy/types": "^3.3.0", 876 | "@smithy/util-config-provider": "^3.0.0", 877 | "@smithy/util-middleware": "^3.0.3", 878 | "tslib": "^2.6.2" 879 | }, 880 | "engines": { 881 | "node": ">=16.0.0" 882 | } 883 | }, 884 | "node_modules/@aws-sdk/signature-v4-multi-region": { 885 | "version": "3.626.0", 886 | "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.626.0.tgz", 887 | "integrity": "sha512-n3yN668b2XLY6155y2KRCCDfA67Acxf/wUS60wGPNrJKk9O5AZzGQzZF8tLfMSng5YBS/CCHN40ooMhRwSLWUg==", 888 | "dev": true, 889 | "dependencies": { 890 | "@aws-sdk/middleware-sdk-s3": "3.626.0", 891 | "@aws-sdk/types": "3.609.0", 892 | "@smithy/protocol-http": "^4.1.0", 893 | "@smithy/signature-v4": "^4.1.0", 894 | "@smithy/types": "^3.3.0", 895 | "tslib": "^2.6.2" 896 | }, 897 | "engines": { 898 | "node": ">=16.0.0" 899 | } 900 | }, 901 | "node_modules/@aws-sdk/token-providers": { 902 | "version": "3.614.0", 903 | "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", 904 | "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", 905 | "dev": true, 906 | "dependencies": { 907 | "@aws-sdk/types": "3.609.0", 908 | "@smithy/property-provider": "^3.1.3", 909 | "@smithy/shared-ini-file-loader": "^3.1.4", 910 | "@smithy/types": "^3.3.0", 911 | "tslib": "^2.6.2" 912 | }, 913 | "engines": { 914 | "node": ">=16.0.0" 915 | }, 916 | "peerDependencies": { 917 | "@aws-sdk/client-sso-oidc": "^3.614.0" 918 | } 919 | }, 920 | "node_modules/@aws-sdk/types": { 921 | "version": "3.609.0", 922 | "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", 923 | "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", 924 | "dev": true, 925 | "dependencies": { 926 | "@smithy/types": "^3.3.0", 927 | "tslib": "^2.6.2" 928 | }, 929 | "engines": { 930 | "node": ">=16.0.0" 931 | } 932 | }, 933 | "node_modules/@aws-sdk/util-arn-parser": { 934 | "version": "3.568.0", 935 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz", 936 | "integrity": "sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==", 937 | "dev": true, 938 | "dependencies": { 939 | "tslib": "^2.6.2" 940 | }, 941 | "engines": { 942 | "node": ">=16.0.0" 943 | } 944 | }, 945 | "node_modules/@aws-sdk/util-endpoints": { 946 | "version": "3.614.0", 947 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", 948 | "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", 949 | "dev": true, 950 | "dependencies": { 951 | "@aws-sdk/types": "3.609.0", 952 | "@smithy/types": "^3.3.0", 953 | "@smithy/util-endpoints": "^2.0.5", 954 | "tslib": "^2.6.2" 955 | }, 956 | "engines": { 957 | "node": ">=16.0.0" 958 | } 959 | }, 960 | "node_modules/@aws-sdk/util-locate-window": { 961 | "version": "3.568.0", 962 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", 963 | "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", 964 | "dev": true, 965 | "dependencies": { 966 | "tslib": "^2.6.2" 967 | }, 968 | "engines": { 969 | "node": ">=16.0.0" 970 | } 971 | }, 972 | "node_modules/@aws-sdk/util-user-agent-browser": { 973 | "version": "3.609.0", 974 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", 975 | "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", 976 | "dev": true, 977 | "dependencies": { 978 | "@aws-sdk/types": "3.609.0", 979 | "@smithy/types": "^3.3.0", 980 | "bowser": "^2.11.0", 981 | "tslib": "^2.6.2" 982 | } 983 | }, 984 | "node_modules/@aws-sdk/util-user-agent-node": { 985 | "version": "3.614.0", 986 | "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", 987 | "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", 988 | "dev": true, 989 | "dependencies": { 990 | "@aws-sdk/types": "3.609.0", 991 | "@smithy/node-config-provider": "^3.1.4", 992 | "@smithy/types": "^3.3.0", 993 | "tslib": "^2.6.2" 994 | }, 995 | "engines": { 996 | "node": ">=16.0.0" 997 | }, 998 | "peerDependencies": { 999 | "aws-crt": ">=1.0.0" 1000 | }, 1001 | "peerDependenciesMeta": { 1002 | "aws-crt": { 1003 | "optional": true 1004 | } 1005 | } 1006 | }, 1007 | "node_modules/@aws-sdk/xml-builder": { 1008 | "version": "3.609.0", 1009 | "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.609.0.tgz", 1010 | "integrity": "sha512-l9XxNcA4HX98rwCC2/KoiWcmEiRfZe4G+mYwDbCFT87JIMj6GBhLDkAzr/W8KAaA2IDr8Vc6J8fZPgVulxxfMA==", 1011 | "dev": true, 1012 | "dependencies": { 1013 | "@smithy/types": "^3.3.0", 1014 | "tslib": "^2.6.2" 1015 | }, 1016 | "engines": { 1017 | "node": ">=16.0.0" 1018 | } 1019 | }, 1020 | "node_modules/@smithy/abort-controller": { 1021 | "version": "3.1.1", 1022 | "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", 1023 | "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", 1024 | "dev": true, 1025 | "dependencies": { 1026 | "@smithy/types": "^3.3.0", 1027 | "tslib": "^2.6.2" 1028 | }, 1029 | "engines": { 1030 | "node": ">=16.0.0" 1031 | } 1032 | }, 1033 | "node_modules/@smithy/chunked-blob-reader": { 1034 | "version": "3.0.0", 1035 | "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-3.0.0.tgz", 1036 | "integrity": "sha512-sbnURCwjF0gSToGlsBiAmd1lRCmSn72nu9axfJu5lIx6RUEgHu6GwTMbqCdhQSi0Pumcm5vFxsi9XWXb2mTaoA==", 1037 | "dev": true, 1038 | "dependencies": { 1039 | "tslib": "^2.6.2" 1040 | } 1041 | }, 1042 | "node_modules/@smithy/chunked-blob-reader-native": { 1043 | "version": "3.0.0", 1044 | "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-3.0.0.tgz", 1045 | "integrity": "sha512-VDkpCYW+peSuM4zJip5WDfqvg2Mo/e8yxOv3VF1m11y7B8KKMKVFtmZWDe36Fvk8rGuWrPZHHXZ7rR7uM5yWyg==", 1046 | "dev": true, 1047 | "dependencies": { 1048 | "@smithy/util-base64": "^3.0.0", 1049 | "tslib": "^2.6.2" 1050 | } 1051 | }, 1052 | "node_modules/@smithy/config-resolver": { 1053 | "version": "3.0.5", 1054 | "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", 1055 | "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", 1056 | "dev": true, 1057 | "dependencies": { 1058 | "@smithy/node-config-provider": "^3.1.4", 1059 | "@smithy/types": "^3.3.0", 1060 | "@smithy/util-config-provider": "^3.0.0", 1061 | "@smithy/util-middleware": "^3.0.3", 1062 | "tslib": "^2.6.2" 1063 | }, 1064 | "engines": { 1065 | "node": ">=16.0.0" 1066 | } 1067 | }, 1068 | "node_modules/@smithy/core": { 1069 | "version": "2.3.2", 1070 | "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", 1071 | "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", 1072 | "dev": true, 1073 | "dependencies": { 1074 | "@smithy/middleware-endpoint": "^3.1.0", 1075 | "@smithy/middleware-retry": "^3.0.14", 1076 | "@smithy/middleware-serde": "^3.0.3", 1077 | "@smithy/protocol-http": "^4.1.0", 1078 | "@smithy/smithy-client": "^3.1.12", 1079 | "@smithy/types": "^3.3.0", 1080 | "@smithy/util-middleware": "^3.0.3", 1081 | "tslib": "^2.6.2" 1082 | }, 1083 | "engines": { 1084 | "node": ">=16.0.0" 1085 | } 1086 | }, 1087 | "node_modules/@smithy/credential-provider-imds": { 1088 | "version": "3.2.0", 1089 | "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", 1090 | "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", 1091 | "dev": true, 1092 | "dependencies": { 1093 | "@smithy/node-config-provider": "^3.1.4", 1094 | "@smithy/property-provider": "^3.1.3", 1095 | "@smithy/types": "^3.3.0", 1096 | "@smithy/url-parser": "^3.0.3", 1097 | "tslib": "^2.6.2" 1098 | }, 1099 | "engines": { 1100 | "node": ">=16.0.0" 1101 | } 1102 | }, 1103 | "node_modules/@smithy/eventstream-codec": { 1104 | "version": "3.1.2", 1105 | "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-3.1.2.tgz", 1106 | "integrity": "sha512-0mBcu49JWt4MXhrhRAlxASNy0IjDRFU+aWNDRal9OtUJvJNiwDuyKMUONSOjLjSCeGwZaE0wOErdqULer8r7yw==", 1107 | "dev": true, 1108 | "dependencies": { 1109 | "@aws-crypto/crc32": "5.2.0", 1110 | "@smithy/types": "^3.3.0", 1111 | "@smithy/util-hex-encoding": "^3.0.0", 1112 | "tslib": "^2.6.2" 1113 | } 1114 | }, 1115 | "node_modules/@smithy/eventstream-serde-browser": { 1116 | "version": "3.0.6", 1117 | "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-3.0.6.tgz", 1118 | "integrity": "sha512-2hM54UWQUOrki4BtsUI1WzmD13/SeaqT/AB3EUJKbcver/WgKNaiJ5y5F5XXuVe6UekffVzuUDrBZVAA3AWRpQ==", 1119 | "dev": true, 1120 | "dependencies": { 1121 | "@smithy/eventstream-serde-universal": "^3.0.5", 1122 | "@smithy/types": "^3.3.0", 1123 | "tslib": "^2.6.2" 1124 | }, 1125 | "engines": { 1126 | "node": ">=16.0.0" 1127 | } 1128 | }, 1129 | "node_modules/@smithy/eventstream-serde-config-resolver": { 1130 | "version": "3.0.3", 1131 | "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-3.0.3.tgz", 1132 | "integrity": "sha512-NVTYjOuYpGfrN/VbRQgn31x73KDLfCXCsFdad8DiIc3IcdxL+dYA9zEQPyOP7Fy2QL8CPy2WE4WCUD+ZsLNfaQ==", 1133 | "dev": true, 1134 | "dependencies": { 1135 | "@smithy/types": "^3.3.0", 1136 | "tslib": "^2.6.2" 1137 | }, 1138 | "engines": { 1139 | "node": ">=16.0.0" 1140 | } 1141 | }, 1142 | "node_modules/@smithy/eventstream-serde-node": { 1143 | "version": "3.0.5", 1144 | "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-3.0.5.tgz", 1145 | "integrity": "sha512-+upXvnHNyZP095s11jF5dhGw/Ihzqwl5G+/KtMnoQOpdfC3B5HYCcDVG9EmgkhJMXJlM64PyN5gjJl0uXFQehQ==", 1146 | "dev": true, 1147 | "dependencies": { 1148 | "@smithy/eventstream-serde-universal": "^3.0.5", 1149 | "@smithy/types": "^3.3.0", 1150 | "tslib": "^2.6.2" 1151 | }, 1152 | "engines": { 1153 | "node": ">=16.0.0" 1154 | } 1155 | }, 1156 | "node_modules/@smithy/eventstream-serde-universal": { 1157 | "version": "3.0.5", 1158 | "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-3.0.5.tgz", 1159 | "integrity": "sha512-5u/nXbyoh1s4QxrvNre9V6vfyoLWuiVvvd5TlZjGThIikc3G+uNiG9uOTCWweSRjv1asdDIWK7nOmN7le4RYHQ==", 1160 | "dev": true, 1161 | "dependencies": { 1162 | "@smithy/eventstream-codec": "^3.1.2", 1163 | "@smithy/types": "^3.3.0", 1164 | "tslib": "^2.6.2" 1165 | }, 1166 | "engines": { 1167 | "node": ">=16.0.0" 1168 | } 1169 | }, 1170 | "node_modules/@smithy/fetch-http-handler": { 1171 | "version": "3.2.4", 1172 | "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", 1173 | "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", 1174 | "dev": true, 1175 | "dependencies": { 1176 | "@smithy/protocol-http": "^4.1.0", 1177 | "@smithy/querystring-builder": "^3.0.3", 1178 | "@smithy/types": "^3.3.0", 1179 | "@smithy/util-base64": "^3.0.0", 1180 | "tslib": "^2.6.2" 1181 | } 1182 | }, 1183 | "node_modules/@smithy/hash-blob-browser": { 1184 | "version": "3.1.2", 1185 | "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-3.1.2.tgz", 1186 | "integrity": "sha512-hAbfqN2UbISltakCC2TP0kx4LqXBttEv2MqSPE98gVuDFMf05lU+TpC41QtqGP3Ff5A3GwZMPfKnEy0VmEUpmg==", 1187 | "dev": true, 1188 | "dependencies": { 1189 | "@smithy/chunked-blob-reader": "^3.0.0", 1190 | "@smithy/chunked-blob-reader-native": "^3.0.0", 1191 | "@smithy/types": "^3.3.0", 1192 | "tslib": "^2.6.2" 1193 | } 1194 | }, 1195 | "node_modules/@smithy/hash-node": { 1196 | "version": "3.0.3", 1197 | "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", 1198 | "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", 1199 | "dev": true, 1200 | "dependencies": { 1201 | "@smithy/types": "^3.3.0", 1202 | "@smithy/util-buffer-from": "^3.0.0", 1203 | "@smithy/util-utf8": "^3.0.0", 1204 | "tslib": "^2.6.2" 1205 | }, 1206 | "engines": { 1207 | "node": ">=16.0.0" 1208 | } 1209 | }, 1210 | "node_modules/@smithy/hash-stream-node": { 1211 | "version": "3.1.2", 1212 | "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-3.1.2.tgz", 1213 | "integrity": "sha512-PBgDMeEdDzi6JxKwbfBtwQG9eT9cVwsf0dZzLXoJF4sHKHs5HEo/3lJWpn6jibfJwT34I1EBXpBnZE8AxAft6g==", 1214 | "dev": true, 1215 | "dependencies": { 1216 | "@smithy/types": "^3.3.0", 1217 | "@smithy/util-utf8": "^3.0.0", 1218 | "tslib": "^2.6.2" 1219 | }, 1220 | "engines": { 1221 | "node": ">=16.0.0" 1222 | } 1223 | }, 1224 | "node_modules/@smithy/invalid-dependency": { 1225 | "version": "3.0.3", 1226 | "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", 1227 | "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", 1228 | "dev": true, 1229 | "dependencies": { 1230 | "@smithy/types": "^3.3.0", 1231 | "tslib": "^2.6.2" 1232 | } 1233 | }, 1234 | "node_modules/@smithy/is-array-buffer": { 1235 | "version": "3.0.0", 1236 | "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", 1237 | "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", 1238 | "dev": true, 1239 | "dependencies": { 1240 | "tslib": "^2.6.2" 1241 | }, 1242 | "engines": { 1243 | "node": ">=16.0.0" 1244 | } 1245 | }, 1246 | "node_modules/@smithy/md5-js": { 1247 | "version": "3.0.3", 1248 | "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-3.0.3.tgz", 1249 | "integrity": "sha512-O/SAkGVwpWmelpj/8yDtsaVe6sINHLB1q8YE/+ZQbDxIw3SRLbTZuRaI10K12sVoENdnHqzPp5i3/H+BcZ3m3Q==", 1250 | "dev": true, 1251 | "dependencies": { 1252 | "@smithy/types": "^3.3.0", 1253 | "@smithy/util-utf8": "^3.0.0", 1254 | "tslib": "^2.6.2" 1255 | } 1256 | }, 1257 | "node_modules/@smithy/middleware-content-length": { 1258 | "version": "3.0.5", 1259 | "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", 1260 | "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", 1261 | "dev": true, 1262 | "dependencies": { 1263 | "@smithy/protocol-http": "^4.1.0", 1264 | "@smithy/types": "^3.3.0", 1265 | "tslib": "^2.6.2" 1266 | }, 1267 | "engines": { 1268 | "node": ">=16.0.0" 1269 | } 1270 | }, 1271 | "node_modules/@smithy/middleware-endpoint": { 1272 | "version": "3.1.0", 1273 | "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", 1274 | "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", 1275 | "dev": true, 1276 | "dependencies": { 1277 | "@smithy/middleware-serde": "^3.0.3", 1278 | "@smithy/node-config-provider": "^3.1.4", 1279 | "@smithy/shared-ini-file-loader": "^3.1.4", 1280 | "@smithy/types": "^3.3.0", 1281 | "@smithy/url-parser": "^3.0.3", 1282 | "@smithy/util-middleware": "^3.0.3", 1283 | "tslib": "^2.6.2" 1284 | }, 1285 | "engines": { 1286 | "node": ">=16.0.0" 1287 | } 1288 | }, 1289 | "node_modules/@smithy/middleware-retry": { 1290 | "version": "3.0.14", 1291 | "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", 1292 | "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", 1293 | "dev": true, 1294 | "dependencies": { 1295 | "@smithy/node-config-provider": "^3.1.4", 1296 | "@smithy/protocol-http": "^4.1.0", 1297 | "@smithy/service-error-classification": "^3.0.3", 1298 | "@smithy/smithy-client": "^3.1.12", 1299 | "@smithy/types": "^3.3.0", 1300 | "@smithy/util-middleware": "^3.0.3", 1301 | "@smithy/util-retry": "^3.0.3", 1302 | "tslib": "^2.6.2", 1303 | "uuid": "^9.0.1" 1304 | }, 1305 | "engines": { 1306 | "node": ">=16.0.0" 1307 | } 1308 | }, 1309 | "node_modules/@smithy/middleware-serde": { 1310 | "version": "3.0.3", 1311 | "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", 1312 | "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", 1313 | "dev": true, 1314 | "dependencies": { 1315 | "@smithy/types": "^3.3.0", 1316 | "tslib": "^2.6.2" 1317 | }, 1318 | "engines": { 1319 | "node": ">=16.0.0" 1320 | } 1321 | }, 1322 | "node_modules/@smithy/middleware-stack": { 1323 | "version": "3.0.3", 1324 | "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", 1325 | "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", 1326 | "dev": true, 1327 | "dependencies": { 1328 | "@smithy/types": "^3.3.0", 1329 | "tslib": "^2.6.2" 1330 | }, 1331 | "engines": { 1332 | "node": ">=16.0.0" 1333 | } 1334 | }, 1335 | "node_modules/@smithy/node-config-provider": { 1336 | "version": "3.1.4", 1337 | "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", 1338 | "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", 1339 | "dev": true, 1340 | "dependencies": { 1341 | "@smithy/property-provider": "^3.1.3", 1342 | "@smithy/shared-ini-file-loader": "^3.1.4", 1343 | "@smithy/types": "^3.3.0", 1344 | "tslib": "^2.6.2" 1345 | }, 1346 | "engines": { 1347 | "node": ">=16.0.0" 1348 | } 1349 | }, 1350 | "node_modules/@smithy/node-http-handler": { 1351 | "version": "3.1.4", 1352 | "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", 1353 | "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", 1354 | "dev": true, 1355 | "dependencies": { 1356 | "@smithy/abort-controller": "^3.1.1", 1357 | "@smithy/protocol-http": "^4.1.0", 1358 | "@smithy/querystring-builder": "^3.0.3", 1359 | "@smithy/types": "^3.3.0", 1360 | "tslib": "^2.6.2" 1361 | }, 1362 | "engines": { 1363 | "node": ">=16.0.0" 1364 | } 1365 | }, 1366 | "node_modules/@smithy/property-provider": { 1367 | "version": "3.1.3", 1368 | "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", 1369 | "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", 1370 | "dev": true, 1371 | "dependencies": { 1372 | "@smithy/types": "^3.3.0", 1373 | "tslib": "^2.6.2" 1374 | }, 1375 | "engines": { 1376 | "node": ">=16.0.0" 1377 | } 1378 | }, 1379 | "node_modules/@smithy/protocol-http": { 1380 | "version": "4.1.0", 1381 | "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", 1382 | "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", 1383 | "dev": true, 1384 | "dependencies": { 1385 | "@smithy/types": "^3.3.0", 1386 | "tslib": "^2.6.2" 1387 | }, 1388 | "engines": { 1389 | "node": ">=16.0.0" 1390 | } 1391 | }, 1392 | "node_modules/@smithy/querystring-builder": { 1393 | "version": "3.0.3", 1394 | "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", 1395 | "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", 1396 | "dev": true, 1397 | "dependencies": { 1398 | "@smithy/types": "^3.3.0", 1399 | "@smithy/util-uri-escape": "^3.0.0", 1400 | "tslib": "^2.6.2" 1401 | }, 1402 | "engines": { 1403 | "node": ">=16.0.0" 1404 | } 1405 | }, 1406 | "node_modules/@smithy/querystring-parser": { 1407 | "version": "3.0.3", 1408 | "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", 1409 | "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", 1410 | "dev": true, 1411 | "dependencies": { 1412 | "@smithy/types": "^3.3.0", 1413 | "tslib": "^2.6.2" 1414 | }, 1415 | "engines": { 1416 | "node": ">=16.0.0" 1417 | } 1418 | }, 1419 | "node_modules/@smithy/service-error-classification": { 1420 | "version": "3.0.3", 1421 | "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", 1422 | "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", 1423 | "dev": true, 1424 | "dependencies": { 1425 | "@smithy/types": "^3.3.0" 1426 | }, 1427 | "engines": { 1428 | "node": ">=16.0.0" 1429 | } 1430 | }, 1431 | "node_modules/@smithy/shared-ini-file-loader": { 1432 | "version": "3.1.4", 1433 | "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", 1434 | "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", 1435 | "dev": true, 1436 | "dependencies": { 1437 | "@smithy/types": "^3.3.0", 1438 | "tslib": "^2.6.2" 1439 | }, 1440 | "engines": { 1441 | "node": ">=16.0.0" 1442 | } 1443 | }, 1444 | "node_modules/@smithy/signature-v4": { 1445 | "version": "4.1.0", 1446 | "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", 1447 | "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", 1448 | "dev": true, 1449 | "dependencies": { 1450 | "@smithy/is-array-buffer": "^3.0.0", 1451 | "@smithy/protocol-http": "^4.1.0", 1452 | "@smithy/types": "^3.3.0", 1453 | "@smithy/util-hex-encoding": "^3.0.0", 1454 | "@smithy/util-middleware": "^3.0.3", 1455 | "@smithy/util-uri-escape": "^3.0.0", 1456 | "@smithy/util-utf8": "^3.0.0", 1457 | "tslib": "^2.6.2" 1458 | }, 1459 | "engines": { 1460 | "node": ">=16.0.0" 1461 | } 1462 | }, 1463 | "node_modules/@smithy/smithy-client": { 1464 | "version": "3.1.12", 1465 | "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", 1466 | "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", 1467 | "dev": true, 1468 | "dependencies": { 1469 | "@smithy/middleware-endpoint": "^3.1.0", 1470 | "@smithy/middleware-stack": "^3.0.3", 1471 | "@smithy/protocol-http": "^4.1.0", 1472 | "@smithy/types": "^3.3.0", 1473 | "@smithy/util-stream": "^3.1.3", 1474 | "tslib": "^2.6.2" 1475 | }, 1476 | "engines": { 1477 | "node": ">=16.0.0" 1478 | } 1479 | }, 1480 | "node_modules/@smithy/types": { 1481 | "version": "3.3.0", 1482 | "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", 1483 | "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", 1484 | "dev": true, 1485 | "dependencies": { 1486 | "tslib": "^2.6.2" 1487 | }, 1488 | "engines": { 1489 | "node": ">=16.0.0" 1490 | } 1491 | }, 1492 | "node_modules/@smithy/url-parser": { 1493 | "version": "3.0.3", 1494 | "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", 1495 | "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", 1496 | "dev": true, 1497 | "dependencies": { 1498 | "@smithy/querystring-parser": "^3.0.3", 1499 | "@smithy/types": "^3.3.0", 1500 | "tslib": "^2.6.2" 1501 | } 1502 | }, 1503 | "node_modules/@smithy/util-base64": { 1504 | "version": "3.0.0", 1505 | "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", 1506 | "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", 1507 | "dev": true, 1508 | "dependencies": { 1509 | "@smithy/util-buffer-from": "^3.0.0", 1510 | "@smithy/util-utf8": "^3.0.0", 1511 | "tslib": "^2.6.2" 1512 | }, 1513 | "engines": { 1514 | "node": ">=16.0.0" 1515 | } 1516 | }, 1517 | "node_modules/@smithy/util-body-length-browser": { 1518 | "version": "3.0.0", 1519 | "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", 1520 | "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", 1521 | "dev": true, 1522 | "dependencies": { 1523 | "tslib": "^2.6.2" 1524 | } 1525 | }, 1526 | "node_modules/@smithy/util-body-length-node": { 1527 | "version": "3.0.0", 1528 | "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", 1529 | "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", 1530 | "dev": true, 1531 | "dependencies": { 1532 | "tslib": "^2.6.2" 1533 | }, 1534 | "engines": { 1535 | "node": ">=16.0.0" 1536 | } 1537 | }, 1538 | "node_modules/@smithy/util-buffer-from": { 1539 | "version": "3.0.0", 1540 | "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", 1541 | "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", 1542 | "dev": true, 1543 | "dependencies": { 1544 | "@smithy/is-array-buffer": "^3.0.0", 1545 | "tslib": "^2.6.2" 1546 | }, 1547 | "engines": { 1548 | "node": ">=16.0.0" 1549 | } 1550 | }, 1551 | "node_modules/@smithy/util-config-provider": { 1552 | "version": "3.0.0", 1553 | "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", 1554 | "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", 1555 | "dev": true, 1556 | "dependencies": { 1557 | "tslib": "^2.6.2" 1558 | }, 1559 | "engines": { 1560 | "node": ">=16.0.0" 1561 | } 1562 | }, 1563 | "node_modules/@smithy/util-defaults-mode-browser": { 1564 | "version": "3.0.14", 1565 | "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", 1566 | "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", 1567 | "dev": true, 1568 | "dependencies": { 1569 | "@smithy/property-provider": "^3.1.3", 1570 | "@smithy/smithy-client": "^3.1.12", 1571 | "@smithy/types": "^3.3.0", 1572 | "bowser": "^2.11.0", 1573 | "tslib": "^2.6.2" 1574 | }, 1575 | "engines": { 1576 | "node": ">= 10.0.0" 1577 | } 1578 | }, 1579 | "node_modules/@smithy/util-defaults-mode-node": { 1580 | "version": "3.0.14", 1581 | "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", 1582 | "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", 1583 | "dev": true, 1584 | "dependencies": { 1585 | "@smithy/config-resolver": "^3.0.5", 1586 | "@smithy/credential-provider-imds": "^3.2.0", 1587 | "@smithy/node-config-provider": "^3.1.4", 1588 | "@smithy/property-provider": "^3.1.3", 1589 | "@smithy/smithy-client": "^3.1.12", 1590 | "@smithy/types": "^3.3.0", 1591 | "tslib": "^2.6.2" 1592 | }, 1593 | "engines": { 1594 | "node": ">= 10.0.0" 1595 | } 1596 | }, 1597 | "node_modules/@smithy/util-endpoints": { 1598 | "version": "2.0.5", 1599 | "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", 1600 | "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", 1601 | "dev": true, 1602 | "dependencies": { 1603 | "@smithy/node-config-provider": "^3.1.4", 1604 | "@smithy/types": "^3.3.0", 1605 | "tslib": "^2.6.2" 1606 | }, 1607 | "engines": { 1608 | "node": ">=16.0.0" 1609 | } 1610 | }, 1611 | "node_modules/@smithy/util-hex-encoding": { 1612 | "version": "3.0.0", 1613 | "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", 1614 | "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", 1615 | "dev": true, 1616 | "dependencies": { 1617 | "tslib": "^2.6.2" 1618 | }, 1619 | "engines": { 1620 | "node": ">=16.0.0" 1621 | } 1622 | }, 1623 | "node_modules/@smithy/util-middleware": { 1624 | "version": "3.0.3", 1625 | "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", 1626 | "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", 1627 | "dev": true, 1628 | "dependencies": { 1629 | "@smithy/types": "^3.3.0", 1630 | "tslib": "^2.6.2" 1631 | }, 1632 | "engines": { 1633 | "node": ">=16.0.0" 1634 | } 1635 | }, 1636 | "node_modules/@smithy/util-retry": { 1637 | "version": "3.0.3", 1638 | "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", 1639 | "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", 1640 | "dev": true, 1641 | "dependencies": { 1642 | "@smithy/service-error-classification": "^3.0.3", 1643 | "@smithy/types": "^3.3.0", 1644 | "tslib": "^2.6.2" 1645 | }, 1646 | "engines": { 1647 | "node": ">=16.0.0" 1648 | } 1649 | }, 1650 | "node_modules/@smithy/util-stream": { 1651 | "version": "3.1.3", 1652 | "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", 1653 | "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", 1654 | "dev": true, 1655 | "dependencies": { 1656 | "@smithy/fetch-http-handler": "^3.2.4", 1657 | "@smithy/node-http-handler": "^3.1.4", 1658 | "@smithy/types": "^3.3.0", 1659 | "@smithy/util-base64": "^3.0.0", 1660 | "@smithy/util-buffer-from": "^3.0.0", 1661 | "@smithy/util-hex-encoding": "^3.0.0", 1662 | "@smithy/util-utf8": "^3.0.0", 1663 | "tslib": "^2.6.2" 1664 | }, 1665 | "engines": { 1666 | "node": ">=16.0.0" 1667 | } 1668 | }, 1669 | "node_modules/@smithy/util-uri-escape": { 1670 | "version": "3.0.0", 1671 | "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", 1672 | "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", 1673 | "dev": true, 1674 | "dependencies": { 1675 | "tslib": "^2.6.2" 1676 | }, 1677 | "engines": { 1678 | "node": ">=16.0.0" 1679 | } 1680 | }, 1681 | "node_modules/@smithy/util-utf8": { 1682 | "version": "3.0.0", 1683 | "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", 1684 | "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", 1685 | "dev": true, 1686 | "dependencies": { 1687 | "@smithy/util-buffer-from": "^3.0.0", 1688 | "tslib": "^2.6.2" 1689 | }, 1690 | "engines": { 1691 | "node": ">=16.0.0" 1692 | } 1693 | }, 1694 | "node_modules/@smithy/util-waiter": { 1695 | "version": "3.1.2", 1696 | "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.1.2.tgz", 1697 | "integrity": "sha512-4pP0EV3iTsexDx+8PPGAKCQpd/6hsQBaQhqWzU4hqKPHN5epPsxKbvUTIiYIHTxaKt6/kEaqPBpu/ufvfbrRzw==", 1698 | "dev": true, 1699 | "dependencies": { 1700 | "@smithy/abort-controller": "^3.1.1", 1701 | "@smithy/types": "^3.3.0", 1702 | "tslib": "^2.6.2" 1703 | }, 1704 | "engines": { 1705 | "node": ">=16.0.0" 1706 | } 1707 | }, 1708 | "node_modules/bowser": { 1709 | "version": "2.11.0", 1710 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", 1711 | "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", 1712 | "dev": true 1713 | }, 1714 | "node_modules/fast-xml-parser": { 1715 | "version": "4.4.1", 1716 | "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", 1717 | "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", 1718 | "dev": true, 1719 | "funding": [ 1720 | { 1721 | "type": "github", 1722 | "url": "https://github.com/sponsors/NaturalIntelligence" 1723 | }, 1724 | { 1725 | "type": "paypal", 1726 | "url": "https://paypal.me/naturalintelligence" 1727 | } 1728 | ], 1729 | "dependencies": { 1730 | "strnum": "^1.0.5" 1731 | }, 1732 | "bin": { 1733 | "fxparser": "src/cli/cli.js" 1734 | } 1735 | }, 1736 | "node_modules/strnum": { 1737 | "version": "1.0.5", 1738 | "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", 1739 | "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", 1740 | "dev": true 1741 | }, 1742 | "node_modules/tslib": { 1743 | "version": "2.6.3", 1744 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", 1745 | "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", 1746 | "dev": true 1747 | }, 1748 | "node_modules/uuid": { 1749 | "version": "9.0.1", 1750 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", 1751 | "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", 1752 | "dev": true, 1753 | "funding": [ 1754 | "https://github.com/sponsors/broofa", 1755 | "https://github.com/sponsors/ctavan" 1756 | ], 1757 | "bin": { 1758 | "uuid": "dist/bin/uuid" 1759 | } 1760 | } 1761 | } 1762 | } 1763 | --------------------------------------------------------------------------------