diff --git a/dev/test.ts b/dev/test.ts index 02bce22..27b5009 100644 --- a/dev/test.ts +++ b/dev/test.ts @@ -51,7 +51,7 @@ async function makeTestObject( async function createTestData() { const sourceObjects = { - [`${testFolderSrc}/1.bin`]: StorageClass.STANDARD, + [`${testFolderSrc}/1.bin`]: StorageClass.DEEP_ARCHIVE, [`${testFolderSrc}/2.bin`]: StorageClass.STANDARD, [`${testFolderSrc}/3.bin`]: StorageClass.GLACIER, }; diff --git a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda-step-construct.ts b/packages/aws-copy-out-sharer/construct/thaw-objects-lambda-step-construct.ts deleted file mode 100644 index 15add7c..0000000 --- a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda-step-construct.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Construct } from "constructs"; -import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam"; -import { Duration, Stack } from "aws-cdk-lib"; -import { LambdaInvoke } from "aws-cdk-lib/aws-stepfunctions-tasks"; -import { Runtime } from "aws-cdk-lib/aws-lambda"; -import { IVpc, SubnetType } from "aws-cdk-lib/aws-ec2"; -import { JsonPath } from "aws-cdk-lib/aws-stepfunctions"; -import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; -import { join } from "path"; - -type ThawObjectsLambdaStepProps = { - vpc: IVpc; - vpcSubnetSelection: SubnetType; - - requiredRegion: string; - - /** - * If true, will allow this CanWrite lambda to test a bucket that is - * in the same account. Otherwise, and by default, the CanWrite lambda - * is set up to not be able to test a bucket in the same account as it - * is installed. This is a security mechanism as writes to buckets in the - * same account is allowed implictly but is dangerous. This should only - * be set to true for development/testing. - */ - allowWriteToThisAccount?: boolean; -}; - -/** - * A construct for a Steps function that tests whether an S3 - * bucket exists, is in the correct region, and is writeable - * by us. Throws an exception if any of these conditions is not met. - */ -export class ThawObjectsLambdaStepConstruct extends Construct { - public readonly invocableLambda; - - constructor(scope: Construct, id: string, props: ThawObjectsLambdaStepProps) { - super(scope, id); - - const canWriteLambda = new NodejsFunction(this, "CanWriteFunction", { - vpc: props.vpc, - entry: join(__dirname, "can-write-lambda", "can-write-lambda.js"), - // by specifying the precise runtime - the bundler knows exactly what packages are already in - // the base image - and for us can skip bundling @aws-sdk - // if we need to move this forward beyond node 18 - then we may need to revisit this - runtime: Runtime.NODEJS_18_X, - handler: "handler", - vpcSubnets: { - subnetType: props.vpcSubnetSelection, - }, - // this seems like plenty of seconds to do a few API calls to S3 - timeout: Duration.seconds(30), - }); - - canWriteLambda.addToRolePolicy( - new PolicyStatement({ - effect: Effect.ALLOW, - actions: ["s3:PutObject"], - resources: ["*"], - // yes - that's right - we want to give this lambda the ability to attempt the writes anywhere - // EXCEPT where we are deployed - // (under the assumption that buckets outside our account must be giving us explicit write permission, - // whilst within our account we get implicit access - in this case we don't want that ability) - conditions: props.allowWriteToThisAccount - ? undefined - : { - StringNotEquals: { - "s3:ResourceAccount": [Stack.of(this).account], - }, - }, - }), - ); - - this.invocableLambda = new LambdaInvoke( - this, - `Can Write To Destination Bucket?`, - { - lambdaFunction: canWriteLambda, - resultPath: JsonPath.DISCARD, - }, - ); - } -} diff --git a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/package.json b/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/package.json deleted file mode 100644 index c97b73b..0000000 --- a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/package.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "can-write-lambda", - "version": "1.0.0", - "main": "thaw-objects-lambda.js", - "dependencies": { - "@aws-sdk/client-s3": "^3.405.0" - } -} diff --git a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/thaw-objects-lambda.js b/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/thaw-objects-lambda.js deleted file mode 100644 index e4646e6..0000000 --- a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/thaw-objects-lambda.js +++ /dev/null @@ -1,52 +0,0 @@ -const { PutObjectCommand, S3Client } = require("@aws-sdk/client-s3"); - -export const handler = async (event) => { - function WrongRegionError(message) { - this.name = "WrongRegionError"; - this.message = message; - } - WrongRegionError.prototype = new Error(); - - function AccessDeniedError(message) { - this.name = "AccessDeniedError"; - this.message = message; - } - AccessDeniedError.prototype = new Error(); - - console.log(event.requiredRegion); - console.log(event.destinationBucket); - - // we are being super specific here - the required region is where we are going - // to make our client - in order to ensure we get 301 Redirects for buckets outside our location - const client = new S3Client({ region: event.requiredRegion }); - - try { - const putCommand = new PutObjectCommand({ - Bucket: event.destinationBucket, - Key: "ELSA_DATA_STARTED_TRANSFER.txt", - Body: "A file created by Elsa Data copy out to ensure correct permissions", - }); - - const response = await client.send(putCommand); - } catch (e) { - if (e.Code === "PermanentRedirect") - throw new WrongRegionError( - "S3 Put failed because bucket was in the wrong region", - ); - - if (e.Code === "AccessDenied") - throw new AccessDeniedError("S3 Put failed with access denied error"); - - throw e; - } -}; - -/*handler({ - requiredRegion: "ap-southeast-2", - //destinationBucket: "elsa-data-tmp" - //destinationBucket: "cdk-hnb659fds-assets-843407916570-us-east-1" - //destinationBucket: "elsa-data-replication-target-foo" - destinationBucket: "elsa-data-replication-target" - // destinationBucket: "elsa-data-copy-target-sydney" - // destinationBucket: "elsa-data-copy-target-tokyo" -}) */ diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/.dockerignore b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/.dockerignore similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/.dockerignore rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/.dockerignore diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/.gitignore b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/.gitignore similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/.gitignore rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/.gitignore diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/Dockerfile b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/Dockerfile similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/Dockerfile rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/Dockerfile diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/README.md b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/README.md similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/README.md rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/README.md diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/go.mod b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/go.mod similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/go.mod rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/go.mod diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/go.sum b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/go.sum similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/go.sum rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/go.sum diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/rclone-batch.go b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/rclone-batch.go similarity index 51% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/rclone-batch.go rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/rclone-batch.go index 9baee7a..198b03e 100644 --- a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/rclone-batch.go +++ b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/rclone-batch.go @@ -11,15 +11,24 @@ import ( "os" "os/exec" "os/signal" + "strconv" "strings" "syscall" + "time" ) // NOTE: we use a prefix of RB (rclone-batch) just so we don't accidentally clash with a real // env variable that has meaning to rclone (for example) + const rcloneBinaryEnvName = "RB_RCLONE_BINARY" const destinationEnvName = "RB_DESTINATION" +// our parent ECS task (when a SPOT instance) can be sent a TERM signal - we then have a hard +// limit of 120 seconds before the process is hard killed +// this value here is the seconds to wait after receiving the TERM in the hope that our +// jobs might finish +const postTermCleanupSeconds = 90 + /** * A ternaryish operator */ @@ -72,21 +81,23 @@ func main() { // a task token that ECS/Steps can pass us so we can return data taskToken, taskTokenOk := os.LookupEnv("RB_TASK_TOKEN") - // now that we know whether we want to use the task token - we will definitely need AWS config to work - // - so no need starting copying if we will fail at the end - cfg, cfgErr := config.LoadDefaultConfig(context.TODO()) + // now that we know whether we want to use the task token - we will definitely need AWS config to work + // - so no need starting copying if we will fail at the end + cfg, err := config.LoadDefaultConfig(context.TODO()) - if taskTokenOk { - if cfgErr != nil { - log.Fatalf("Unable to load AWS config, %v", cfgErr) - } - } + if taskTokenOk { + if err != nil { + log.Fatalf("Unable to load AWS config, %v", err) + } + } // special environment variables that we can use for some debug/testing debugBandwidth, debugBandwidthOk := os.LookupEnv("RB_DEBUG_BANDWIDTH") + debugSignalWait, debugSignalWaitOk := os.LookupEnv("RB_DEBUG_SIGNAL_WAIT") // we end up with a result array entry for each object we have been asked to copy results := make([]any, len(os.Args)-1) + var resultErrorCount int64 = 0 signalChannel := make(chan os.Signal) @@ -123,52 +134,136 @@ func main() { sig := <-signalChannel switch sig { case syscall.SIGTERM: - // terminate the currently running rclone - cmd.Process.Signal(syscall.SIGTERM) // indicate we don't want future rclones to run interrupted = true + + // we do however have a 120 second (hard) window in which we might want + // to let the current rclone finish + // so lets sleep for a bit before we self-terminate + // (we have a little debug settable value here to make our tests run quicker) + if debugSignalWaitOk { + i, err := strconv.Atoi(debugSignalWait) + if err == nil { + time.Sleep(time.Duration(i) * time.Second) + } + } else { + time.Sleep(postTermCleanupSeconds * time.Second) + } + + // terminate the currently running rclone + // NOTE we ignore the error here - if the process has already gone away then the + // signal possibly fails (by which point we should be exiting the process anyhow) + cmd.Process.Signal(syscall.SIGTERM) } }() - err := cmd.Run() + runErr := cmd.Run() - if err != nil { - log.Printf("rclone Run() failed with %v", err) - results[which] = map[string]any{ - "lastError": "Interrupted by SIGTERM", - "systemError": fmt.Sprintf("%v", err), - "source": source} + if runErr != nil { + log.Printf("rclone Run() failed with %v", runErr) } else { log.Printf("rclone Run() succeeded") } + foundStats := false + + // no matter what the exit code/status of the run is - we are going to (safely!) trawl + // through the stderr // each line of stderr output is stats in JSON format or possibly other random messages stderrStringLines := strings.Split(strings.TrimSuffix(stderrStringBuilder.String(), "\n"), "\n") - // attempt to process each line of log output to stderr as JSON (if not then ignore) + // attempt to process each line of log output to stderr as JSON (if not then log it ourselves) for _, line := range stderrStringLines { var logLineJson map[string]any - logLineJsonErr := json.Unmarshal([]byte(line), &logLineJson) + decoder := json.NewDecoder(strings.NewReader(line)) + decoder.UseNumber() - if logLineJsonErr == nil { + decoderErr := decoder.Decode(&logLineJson) + if decoderErr == nil { statsValue, statsOk := logLineJson["stats"].(map[string]any) if statsOk { - // insert information about the file we were copying - statsValue["source"] = source - results[which] = statsValue + // an rclone stats block will definitely have a "errors" count + // so we test for this and then use it + errorsValue, errorsOk := statsValue["errors"].(json.Number) + + if errorsOk { + errorsIntValue, errorsIntOk := errorsValue.Int64() + + if errorsIntOk == nil { + resultErrorCount += errorsIntValue + + // insert information about the file we were copying into the rclone stats block + statsValue["source"] = source + + // record the stats block + results[which] = statsValue + + foundStats = true + } + } + } + } else { + // we couldn't parse the line as JSON so it is probably a stderr msg from rclone + log.Printf("rclone stderr -> %s", line) + } + } + + // if`no valid stats block was output by rclone we need to make our own "compatible" one + if !foundStats { + // if we get a well structured runtime error result we can work out some + // specific error messages + + // keep in mind we *only* get here if rclone itself didn't provide JSON stats + // (which is itself a bug - as rclone does provide stats on every copy) + if runErr != nil { + if runExitErr, runExitOk := runErr.(*exec.ExitError); runExitOk { + // https://rclone.org/docs/#list-of-exit-codes + switch runExitErr.ExitCode() { + case 143: + results[which] = map[string]any{ + "errors": 1, + "lastError": "Interrupted by SIGTERM", + "source": source} + resultErrorCount++ + default: + results[which] = map[string]any{ + "errors": 1, + "lastError": fmt.Sprintf("Exit of rclone with code %v but no JSON statistics block generated", runExitErr.ExitCode()), + "systemError": fmt.Sprintf("%#v", runExitErr), + "source": source} + resultErrorCount++ + } } } } + } else { + // if we have previously received a SIGTERM - then for the rest we have been asked to copy we just need to skip + // create a fake "compatible" stats block results[which] = map[string]any{ - "lastError": "Skipped due to SIGTERM received", + "errors": 1, + "lastError": "Skipped due to previous SIGTERM received", + "source": source} + resultErrorCount++ + } + + // if we have fallen through all the way to here without any details then we put in + // something generic - but we want to make sure every copy operation has a "result" block + if results[which] == nil { + results[which] = map[string]any{ + "errors": 1, + "lastError": "Exit of rclone but no JSON statistics block generated or reason detected", "source": source} + resultErrorCount++ } } + // we have now attempted to copy every file and generated a stats dictionary in results[] + + // we need to report this back as JSON though resultsJson, err := json.MarshalIndent(results, "", " ") if err != nil { @@ -186,12 +281,24 @@ func main() { // The JSON output of the task. Length constraints apply to the payload size, and are expressed as bytes in UTF-8 encoding. // Type: String // Length Constraints: Maximum length of 262144. - sfnSvc.SendTaskSuccess(context.TODO(), &sfn.SendTaskSuccessInput{ - Output: aws.String(resultsString), - TaskToken: aws.String(taskToken), - }) + + // if we got any errors - we want to signal that up to the steps + //if resultErrorCount > 0 { + // sfnSvc.SendTaskFailure(context.TODO(), &sfn.SendTaskFailureInput{ + // Output: aws.String(resultsString), + // TaskToken: aws.String(taskToken), + // }) + //} else { + sfnSvc.SendTaskSuccess(context.TODO(), &sfn.SendTaskSuccessInput{ + Output: aws.String(resultsString), + TaskToken: aws.String(taskToken), + }) + //} + } else { // if no task token was given then we just print the results fmt.Println(resultsString) } + + os.Exit(int(resultErrorCount)) } diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-assert.sh b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-assert.sh similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-assert.sh rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-assert.sh diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-docker-direct.sh b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-docker-direct.sh similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-docker-direct.sh rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-docker-direct.sh diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-go-direct.sh b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-go-direct.sh similarity index 81% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-go-direct.sh rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-go-direct.sh index bc6538b..c91a67a 100755 --- a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/test-go-direct.sh +++ b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/test-go-direct.sh @@ -25,6 +25,9 @@ fi export RB_RCLONE_BINARY +# our tests do return exit codes so we need to *not* fail on error +set +e + # # Test 1 # @@ -32,8 +35,11 @@ echo "Test 1 - copying two files" RB_DESTINATION="$TEMPD/test1" ./rclone-batch ./testfile1.txt ./testfile2.txt > "$TEMPD/result.json" +test1_exit=$? + cat "$TEMPD/result.json" +assert " echo $test1_exit " "0" assert " find $TEMPD/test1 -type f | awk 'END{print NR}' " "2" assert " cat $TEMPD/result.json | jq -r '.[0] | .bytes' " "20" assert " cat $TEMPD/result.json | jq -r '.[1] | .bytes' " "37" @@ -47,8 +53,11 @@ echo "Test 2 - copying two files but one not present/fails" RB_DESTINATION="$TEMPD/test2" ./rclone-batch ./afilethatdoesnotexist.txt ./testfile2.txt > "$TEMPD/result.json" +test2_exit=$? + cat "$TEMPD/result.json" +assert " echo $test2_exit " "1" assert "find $TEMPD/test2 -type f | awk 'END{print NR}'" "1" assert " cat $TEMPD/result.json | jq -r '.[0] | .lastError' " "directory not found" assert " cat $TEMPD/result.json | jq -r '.[0] | .bytes' " "0" @@ -66,8 +75,9 @@ rm "$TEMPD/result.json" echo "Test 3 - copying two files but signals tells us to stop" # we set the bandwidth to 1B so that it is slow enough that our TERM signal will come mid-process +# we set the signal wait because otherwise the test will run for more than a minute # we start this execution in the background -RB_DESTINATION="$TEMPD/test3" RB_DEBUG_BANDWIDTH="1B" ./rclone-batch ./testfile1.txt ./testfile2.txt > "$TEMPD/result.json" & +RB_DESTINATION="$TEMPD/test3" RB_DEBUG_BANDWIDTH="1B" RB_DEBUG_SIGNAL_WAIT="5" ./rclone-batch ./testfile1.txt ./testfile2.txt > "$TEMPD/result.json" & # wait a small amount sleep 1 @@ -75,10 +85,13 @@ sleep 1 # now send a SIGTERM to the launched job kill %1 +# but still wait for it to finish as it intercepts the SIGTERM +wait %1 + cat "$TEMPD/result.json" assert " cat $TEMPD/result.json | jq -r '.[0] | .lastError' " "Interrupted by SIGTERM" -assert " cat $TEMPD/result.json | jq -r '.[1] | .lastError' " "Skipped due to SIGTERM received" +assert " cat $TEMPD/result.json | jq -r '.[1] | .lastError' " "Skipped due to previous SIGTERM received" rm "$TEMPD/result.json" diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/testfile1.txt b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/testfile1.txt similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/testfile1.txt rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/testfile1.txt diff --git a/packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/testfile2.txt b/packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/testfile2.txt similarity index 100% rename from packages/aws-copy-out-sharer/construct/rclone-batch-docker-image/testfile2.txt rename to packages/aws-copy-out-sharer/docker/rclone-batch-docker-image/testfile2.txt diff --git a/packages/aws-copy-out-sharer/construct/can-write-lambda/.gitignore b/packages/aws-copy-out-sharer/lambda/can-write-lambda/.gitignore similarity index 100% rename from packages/aws-copy-out-sharer/construct/can-write-lambda/.gitignore rename to packages/aws-copy-out-sharer/lambda/can-write-lambda/.gitignore diff --git a/packages/aws-copy-out-sharer/construct/can-write-lambda/can-write-lambda.ts b/packages/aws-copy-out-sharer/lambda/can-write-lambda/can-write-lambda.ts similarity index 88% rename from packages/aws-copy-out-sharer/construct/can-write-lambda/can-write-lambda.ts rename to packages/aws-copy-out-sharer/lambda/can-write-lambda/can-write-lambda.ts index c3e3836..85efc55 100644 --- a/packages/aws-copy-out-sharer/construct/can-write-lambda/can-write-lambda.ts +++ b/packages/aws-copy-out-sharer/lambda/can-write-lambda/can-write-lambda.ts @@ -7,10 +7,10 @@ interface InvokeEvent { } export async function handler(event: InvokeEvent) { - console.log(event.requiredRegion); - console.log(event.destinationBucket); + console.log(JSON.stringify(event, null, 2)); - // we are being super specific here - the required region is where we are going + // we are being super specific here - more so than our normal client creation + // the "required region" is where we are going // to make our client - in order to ensure we get 301 Redirects for buckets outside our location const client = new S3Client({ region: event.requiredRegion }); diff --git a/packages/aws-copy-out-sharer/construct/can-write-lambda/errors.ts b/packages/aws-copy-out-sharer/lambda/can-write-lambda/errors.ts similarity index 100% rename from packages/aws-copy-out-sharer/construct/can-write-lambda/errors.ts rename to packages/aws-copy-out-sharer/lambda/can-write-lambda/errors.ts diff --git a/packages/aws-copy-out-sharer/construct/can-write-lambda/package-lock.json b/packages/aws-copy-out-sharer/lambda/can-write-lambda/package-lock.json similarity index 100% rename from packages/aws-copy-out-sharer/construct/can-write-lambda/package-lock.json rename to packages/aws-copy-out-sharer/lambda/can-write-lambda/package-lock.json diff --git a/packages/aws-copy-out-sharer/construct/can-write-lambda/package.json b/packages/aws-copy-out-sharer/lambda/can-write-lambda/package.json similarity index 100% rename from packages/aws-copy-out-sharer/construct/can-write-lambda/package.json rename to packages/aws-copy-out-sharer/lambda/can-write-lambda/package.json diff --git a/packages/aws-copy-out-sharer/construct/thaw-objects-lambda/.gitignore b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/.gitignore similarity index 100% rename from packages/aws-copy-out-sharer/construct/thaw-objects-lambda/.gitignore rename to packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/.gitignore diff --git a/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/errors.ts b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/errors.ts new file mode 100644 index 0000000..87ed69b --- /dev/null +++ b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/errors.ts @@ -0,0 +1,7 @@ +export class IsThawingError extends Error { + constructor(message: string) { + super(); + this.name = "IsThawingError"; + this.message = message; + } +} diff --git a/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/package-lock.json b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/package-lock.json new file mode 100644 index 0000000..e874f44 --- /dev/null +++ b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/package-lock.json @@ -0,0 +1,1438 @@ +{ + "name": "can-write-lambda", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "can-write-lambda", + "version": "1.0.0", + "dependencies": { + "@aws-sdk/client-s3": "3.405.0", + "@types/aws-lambda": "8.10.93" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/crc32c": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-3.0.0.tgz", + "integrity": "sha512-ENNPPManmnVJ4BTXlOjAgD7URidbAznURqD0KvfREyc4o20DPYdEldU1f5cQ7Jbj0CJJSPaMIk/9ZshdB3210w==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32c/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha1-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-3.0.0.tgz", + "integrity": "sha512-NJth5c997GLHs6nOYTzFKTbYdMNA6/1XlKVgnZoaZcQ7z7UJlOgj2JdbHE8tiYLS3fzXNCguct77SPGat2raSw==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha1-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/@aws-sdk/client-s3": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.405.0.tgz", + "integrity": "sha512-+LK6OCbKplR51zBZAtK/+RxaPsXcEklsA1+mmUA3M1h4KHl6GMiK5r/D9dlKht5DRntmmjCn3SI99QbfckqKXg==", + "dependencies": { + "@aws-crypto/sha1-browser": "3.0.0", + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.405.0", + "@aws-sdk/credential-provider-node": "3.405.0", + "@aws-sdk/middleware-bucket-endpoint": "3.405.0", + "@aws-sdk/middleware-expect-continue": "3.398.0", + "@aws-sdk/middleware-flexible-checksums": "3.400.0", + "@aws-sdk/middleware-host-header": "3.398.0", + "@aws-sdk/middleware-location-constraint": "3.398.0", + "@aws-sdk/middleware-logger": "3.398.0", + "@aws-sdk/middleware-recursion-detection": "3.398.0", + "@aws-sdk/middleware-sdk-s3": "3.398.0", + "@aws-sdk/middleware-signing": "3.398.0", + "@aws-sdk/middleware-ssec": "3.398.0", + "@aws-sdk/middleware-user-agent": "3.398.0", + "@aws-sdk/signature-v4-multi-region": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-endpoints": "3.398.0", + "@aws-sdk/util-user-agent-browser": "3.398.0", + "@aws-sdk/util-user-agent-node": "3.405.0", + "@aws-sdk/xml-builder": "3.310.0", + "@smithy/config-resolver": "^2.0.5", + "@smithy/eventstream-serde-browser": "^2.0.5", + "@smithy/eventstream-serde-config-resolver": "^2.0.5", + "@smithy/eventstream-serde-node": "^2.0.5", + "@smithy/fetch-http-handler": "^2.0.5", + "@smithy/hash-blob-browser": "^2.0.5", + "@smithy/hash-node": "^2.0.5", + "@smithy/hash-stream-node": "^2.0.5", + "@smithy/invalid-dependency": "^2.0.5", + "@smithy/md5-js": "^2.0.5", + "@smithy/middleware-content-length": "^2.0.5", + "@smithy/middleware-endpoint": "^2.0.5", + "@smithy/middleware-retry": "^2.0.5", + "@smithy/middleware-serde": "^2.0.5", + "@smithy/middleware-stack": "^2.0.0", + "@smithy/node-config-provider": "^2.0.6", + "@smithy/node-http-handler": "^2.0.5", + "@smithy/protocol-http": "^2.0.5", + "@smithy/smithy-client": "^2.0.5", + "@smithy/types": "^2.2.2", + "@smithy/url-parser": "^2.0.5", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.6", + "@smithy/util-defaults-mode-node": "^2.0.6", + "@smithy/util-retry": "^2.0.0", + "@smithy/util-stream": "^2.0.5", + "@smithy/util-utf8": "^2.0.0", + "@smithy/util-waiter": "^2.0.5", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.405.0.tgz", + "integrity": "sha512-z1ssydU07bDhe0tNXQwVO+rWh/iSfK48JI8s8vgpBNwH+NejMzIJ9r3AkjCiJ+LSAwlBZItUsNWwR0veIfgBiw==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.398.0", + "@aws-sdk/middleware-logger": "3.398.0", + "@aws-sdk/middleware-recursion-detection": "3.398.0", + "@aws-sdk/middleware-user-agent": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-endpoints": "3.398.0", + "@aws-sdk/util-user-agent-browser": "3.398.0", + "@aws-sdk/util-user-agent-node": "3.405.0", + "@smithy/config-resolver": "^2.0.5", + "@smithy/fetch-http-handler": "^2.0.5", + "@smithy/hash-node": "^2.0.5", + "@smithy/invalid-dependency": "^2.0.5", + "@smithy/middleware-content-length": "^2.0.5", + "@smithy/middleware-endpoint": "^2.0.5", + "@smithy/middleware-retry": "^2.0.5", + "@smithy/middleware-serde": "^2.0.5", + "@smithy/middleware-stack": "^2.0.0", + "@smithy/node-config-provider": "^2.0.6", + "@smithy/node-http-handler": "^2.0.5", + "@smithy/protocol-http": "^2.0.5", + "@smithy/smithy-client": "^2.0.5", + "@smithy/types": "^2.2.2", + "@smithy/url-parser": "^2.0.5", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.6", + "@smithy/util-defaults-mode-node": "^2.0.6", + "@smithy/util-retry": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.405.0.tgz", + "integrity": "sha512-asVEpda3zu5QUO5ZNNjbLBS0718IhxxyUDVrNmVTKZoOhK1pMNouGZf+l49v0Lb5cOPbUds8cxsNaInj2MvIKw==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.405.0", + "@aws-sdk/middleware-host-header": "3.398.0", + "@aws-sdk/middleware-logger": "3.398.0", + "@aws-sdk/middleware-recursion-detection": "3.398.0", + "@aws-sdk/middleware-sdk-sts": "3.398.0", + "@aws-sdk/middleware-signing": "3.398.0", + "@aws-sdk/middleware-user-agent": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-endpoints": "3.398.0", + "@aws-sdk/util-user-agent-browser": "3.398.0", + "@aws-sdk/util-user-agent-node": "3.405.0", + "@smithy/config-resolver": "^2.0.5", + "@smithy/fetch-http-handler": "^2.0.5", + "@smithy/hash-node": "^2.0.5", + "@smithy/invalid-dependency": "^2.0.5", + "@smithy/middleware-content-length": "^2.0.5", + "@smithy/middleware-endpoint": "^2.0.5", + "@smithy/middleware-retry": "^2.0.5", + "@smithy/middleware-serde": "^2.0.5", + "@smithy/middleware-stack": "^2.0.0", + "@smithy/node-config-provider": "^2.0.6", + "@smithy/node-http-handler": "^2.0.5", + "@smithy/protocol-http": "^2.0.5", + "@smithy/smithy-client": "^2.0.5", + "@smithy/types": "^2.2.2", + "@smithy/url-parser": "^2.0.5", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.6", + "@smithy/util-defaults-mode-node": "^2.0.6", + "@smithy/util-retry": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.398.0.tgz", + "integrity": "sha512-Z8Yj5z7FroAsR6UVML+XUdlpoqEe9Dnle8c2h8/xWwIC2feTfIBhjLhRVxfbpbM1pLgBSNEcZ7U8fwq5l7ESVQ==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.405.0.tgz", + "integrity": "sha512-b4TqVsM4WQM96GDVs+TYOhU2/0SnUWzz6NH55qY1y2xyF8/pZEhc0XXdpvZtQQBLGdROhXCbxhBVye8GmTpgcg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.398.0", + "@aws-sdk/credential-provider-process": "3.405.0", + "@aws-sdk/credential-provider-sso": "3.405.0", + "@aws-sdk/credential-provider-web-identity": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.405.0.tgz", + "integrity": "sha512-AMmRP09nwYsft0MXDlHIxMQe7IloWW8As0lbZmPrG7Y7mK5RDmCIwD2yMDz77Zqlv09FsYt+9+cOK2fTNhim+Q==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.398.0", + "@aws-sdk/credential-provider-ini": "3.405.0", + "@aws-sdk/credential-provider-process": "3.405.0", + "@aws-sdk/credential-provider-sso": "3.405.0", + "@aws-sdk/credential-provider-web-identity": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.405.0.tgz", + "integrity": "sha512-EqAMcUVeZAICYHHL8x5Fi5CYPgCo9UCE7ScWmU5Sa2wAFY4XLyQ1mMxX3lKGYx9lBxWk3dqnhmvlcqdzN7AjyQ==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.405.0.tgz", + "integrity": "sha512-fXqSgQHz7qcmIWMVguwSMSjqFkVfN2+XiNgiskcmeYiCS7mIGAgUnKABZc9Ds2+YW9ATYiY0BOD5aWxc8TX5fA==", + "dependencies": { + "@aws-sdk/client-sso": "3.405.0", + "@aws-sdk/token-providers": "3.405.0", + "@aws-sdk/types": "3.398.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.398.0.tgz", + "integrity": "sha512-iG3905Alv9pINbQ8/MIsshgqYMbWx+NDQWpxbIW3W0MkSH3iAqdVpSCteYidYX9G/jv2Um1nW3y360ib20bvNg==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-bucket-endpoint": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.405.0.tgz", + "integrity": "sha512-wKmHZi44NkbaGXXbMwassUm06/wDtSYucPbM4paU2cMbBUOnwFpndHWlrRYCNmj5Ty5A2HjdkGlhgla8nifHzQ==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "@smithy/util-config-provider": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-expect-continue": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.398.0.tgz", + "integrity": "sha512-d6he+Qqwh1yqml9duXSv5iKJ2lS0PVrF2UEsVew2GFxfUif0E/davTZJjvWtnelbuIGcTP+wDKVVjLwBN2sN/g==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-flexible-checksums": { + "version": "3.400.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.400.0.tgz", + "integrity": "sha512-lpsumd5/G+eAMTr61h/cJQZ8+i+xzC6OG3bvUcbRHqcjN49XgeNLcPfYcr6Rzf0QHxmuCN4te/4XGU3Fif2YVA==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@aws-crypto/crc32c": "3.0.0", + "@aws-sdk/types": "3.398.0", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.398.0.tgz", + "integrity": "sha512-m+5laWdBaxIZK2ko0OwcCHJZJ5V1MgEIt8QVQ3k4/kOkN9ICjevOYmba751pHoTnbOYB7zQd6D2OT3EYEEsUcA==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-location-constraint": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.398.0.tgz", + "integrity": "sha512-it+olJf1Lf2bmH8OL/N1jMOFB0zEVYs4rIzgFrluTRCuPatRuDi4LsXS8zqYxkBa05JE8JmqwW5gCzAmWyLLqw==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.398.0.tgz", + "integrity": "sha512-CiJjW+FL12elS6Pn7/UVjVK8HWHhXMfvHZvOwx/Qkpy340sIhkuzOO6fZEruECDTZhl2Wqn81XdJ1ZQ4pRKpCg==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.398.0.tgz", + "integrity": "sha512-7QpOqPQAZNXDXv6vsRex4R8dLniL0E/80OPK4PPFsrCh9btEyhN9Begh4i1T+5lL28hmYkztLOkTQ2N5J3hgRQ==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-s3": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.398.0.tgz", + "integrity": "sha512-yweSMc/TyiFtqc52hFMKQJvTm3i1KCoW5mB3o/Sla6zsHBh+nS6TTaBmo+2kcDIR7AKODwW+FLCTHWiazb7J3Q==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-arn-parser": "3.310.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.398.0.tgz", + "integrity": "sha512-+JH76XHEgfVihkY+GurohOQ5Z83zVN1nYcQzwCFnCDTh4dG4KwhnZKG+WPw6XJECocY0R+H0ivofeALHvVWJtQ==", + "dependencies": { + "@aws-sdk/middleware-signing": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.398.0.tgz", + "integrity": "sha512-O0KqXAix1TcvZBFt1qoFkHMUNJOSgjJTYS7lFTRKSwgsD27bdW2TM2r9R8DAccWFt5Amjkdt+eOwQMIXPGTm8w==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.2.2", + "@smithy/util-middleware": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-ssec": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.398.0.tgz", + "integrity": "sha512-QtKr/hPcRugKSIZAH4+7hbUfdW7Lg+OQvD25nJn7ic1JHRZ+eDctEFxdsmnt68lE6aZxOcHCWHAW6/umcA93Dw==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.398.0.tgz", + "integrity": "sha512-nF1jg0L+18b5HvTcYzwyFgfZQQMELJINFqI0mi4yRKaX7T5a3aGp5RVLGGju/6tAGTuFbfBoEhkhU3kkxexPYQ==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-endpoints": "3.398.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.398.0.tgz", + "integrity": "sha512-8fTqTxRDWE03T7ClaWlCfbwuSae//01XMNVy2a9g5QgaelQh7ZZyU3ZIJiV8gIj8v6ZM0NGn9Bz1liI/vmNmcw==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/signature-v4-crt": "^3.118.0" + }, + "peerDependenciesMeta": { + "@aws-sdk/signature-v4-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.405.0.tgz", + "integrity": "sha512-rVzC7ptf7TlV84M9w+Ds9isio1EY7bs1MRFv/6lmYstsyTri+DaZG10TwXSGfzIMwB0yVh11niCxO9wSjQ36zg==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.398.0", + "@aws-sdk/middleware-logger": "3.398.0", + "@aws-sdk/middleware-recursion-detection": "3.398.0", + "@aws-sdk/middleware-user-agent": "3.398.0", + "@aws-sdk/types": "3.398.0", + "@aws-sdk/util-endpoints": "3.398.0", + "@aws-sdk/util-user-agent-browser": "3.398.0", + "@aws-sdk/util-user-agent-node": "3.405.0", + "@smithy/config-resolver": "^2.0.5", + "@smithy/fetch-http-handler": "^2.0.5", + "@smithy/hash-node": "^2.0.5", + "@smithy/invalid-dependency": "^2.0.5", + "@smithy/middleware-content-length": "^2.0.5", + "@smithy/middleware-endpoint": "^2.0.5", + "@smithy/middleware-retry": "^2.0.5", + "@smithy/middleware-serde": "^2.0.5", + "@smithy/middleware-stack": "^2.0.0", + "@smithy/node-config-provider": "^2.0.6", + "@smithy/node-http-handler": "^2.0.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^2.0.5", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.0.5", + "@smithy/types": "^2.2.2", + "@smithy/url-parser": "^2.0.5", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.6", + "@smithy/util-defaults-mode-node": "^2.0.6", + "@smithy/util-retry": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.398.0.tgz", + "integrity": "sha512-r44fkS+vsEgKCuEuTV+TIk0t0m5ZlXHNjSDYEUvzLStbbfUFiNus/YG4UCa0wOk9R7VuQI67badsvvPeVPCGDQ==", + "dependencies": { + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-arn-parser": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.310.0.tgz", + "integrity": "sha512-jL8509owp/xB9+Or0pvn3Fe+b94qfklc2yPowZZIFAkFcCSIdkIglz18cPDWnYAcy9JGewpMS1COXKIUhZkJsA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.398.0.tgz", + "integrity": "sha512-Fy0gLYAei/Rd6BrXG4baspCnWTUSd0NdokU1pZh4KlfEAEN1i8SPPgfiO5hLk7+2inqtCmqxVJlfqbMVe9k4bw==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.398.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.398.0.tgz", + "integrity": "sha512-A3Tzx1tkDHlBT+IgxmsMCHbV8LM7SwwCozq2ZjJRx0nqw3MCrrcxQFXldHeX/gdUMO+0Oocb7HGSnVODTq+0EA==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/types": "^2.2.2", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.405.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.405.0.tgz", + "integrity": "sha512-6Ssld7aalKCnW6lSGfiiWpqwo2L+AmYq2oV3P9yYAo9ZL+Q78dXquabwj3uq3plJ4l2xE4Gfcf2FJ/1PZpqDvQ==", + "dependencies": { + "@aws-sdk/types": "3.398.0", + "@smithy/node-config-provider": "^2.0.6", + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.310.0.tgz", + "integrity": "sha512-TqELu4mOuSIKQCqj63fGVs86Yh+vBx5nHRpWKNUNhB2nPTpfbziTs5c1X358be3peVWA4wPxW7Nt53KIg1tnNw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.14.tgz", + "integrity": "sha512-zXtteuYLWbSXnzI3O6xq3FYvigYZFW8mdytGibfarLL2lxHto9L3ILtGVnVGmFZa7SDh62l39EnU5hesLN87Fw==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/chunked-blob-reader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-2.0.0.tgz", + "integrity": "sha512-k+J4GHJsMSAIQPChGBrjEmGS+WbPonCXesoqP9fynIqjn7rdOThdH8FAeCmokP9mxTYKQAKoHCLPzNlm6gh7Wg==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/chunked-blob-reader-native": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-2.0.1.tgz", + "integrity": "sha512-N2oCZRglhWKm7iMBu7S6wDzXirjAofi7tAd26cxmgibRYOBS4D3hGfmkwCpHdASZzwZDD8rluh0Rcqw1JeZDRw==", + "dependencies": { + "@smithy/util-base64": "^2.0.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.19.tgz", + "integrity": "sha512-JsghnQ5zjWmjEVY8TFOulLdEOCj09SjRLugrHlkPZTIBBm7PQitCFVLThbsKPZQOP7N3ME1DU1nKUc1UaVnBog==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.6", + "@smithy/types": "^2.6.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.7", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.1.2.tgz", + "integrity": "sha512-Y62jBWdoLPSYjr9fFvJf+KwTa1EunjVr6NryTEWCnwIY93OJxwV4t0qxjwdPl/XMsUkq79ppNJSEQN6Ohnhxjw==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.6", + "@smithy/property-provider": "^2.0.15", + "@smithy/types": "^2.6.0", + "@smithy/url-parser": "^2.0.14", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.14.tgz", + "integrity": "sha512-g/OU/MeWGfHDygoXgMWfG/Xb0QqDnAGcM9t2FRrVAhleXYRddGOEnfanR5cmHgB9ue52MJsyorqFjckzXsylaA==", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.6.0", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/eventstream-serde-browser": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-2.0.14.tgz", + "integrity": "sha512-41wmYE9smDGJi1ZXp+LogH6BR7MkSsQD91wneIFISF/mupKULvoOJUkv/Nf0NMRxWlM3Bf1Vvi9FlR2oV4KU8Q==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.14", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-config-resolver": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-2.0.14.tgz", + "integrity": "sha512-43IyRIzQ82s+5X+t/3Ood00CcWtAXQdmUIUKMed2Qg9REPk8SVIHhpm3rwewLwg+3G2Nh8NOxXlEQu6DsPUcMw==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-node": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-2.0.14.tgz", + "integrity": "sha512-jVh9E2qAr6DxH5tWfCAl9HV6tI0pEQ3JVmu85JknDvYTC66djcjDdhctPV2EHuKWf2kjRiFJcMIn0eercW4THA==", + "dependencies": { + "@smithy/eventstream-serde-universal": "^2.0.14", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-serde-universal": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-2.0.14.tgz", + "integrity": "sha512-Ie35+AISNn1NmEjn5b2SchIE49pvKp4Q74bE9ME5RULWI1MgXyGkQUajWd5E6OBSr/sqGcs+rD3IjPErXnCm9g==", + "dependencies": { + "@smithy/eventstream-codec": "^2.0.14", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.2.7.tgz", + "integrity": "sha512-iSDBjxuH9TgrtMYAr7j5evjvkvgwLY3y+9D547uep+JNkZ1ZT+BaeU20j6I/bO/i26ilCWFImrlXTPsfQtZdIQ==", + "dependencies": { + "@smithy/protocol-http": "^3.0.10", + "@smithy/querystring-builder": "^2.0.14", + "@smithy/types": "^2.6.0", + "@smithy/util-base64": "^2.0.1", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/protocol-http": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.10.tgz", + "integrity": "sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-blob-browser": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-2.0.15.tgz", + "integrity": "sha512-HX/7GIyPUT/HDWVYe2HYQu0iRnSYpF4uZVNhAhZsObPRawk5Mv0PbyluBgIFI2DDCCKgL/tloCYYwycff1GtQg==", + "dependencies": { + "@smithy/chunked-blob-reader": "^2.0.0", + "@smithy/chunked-blob-reader-native": "^2.0.1", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.16.tgz", + "integrity": "sha512-Wbi9A0PacMYUOwjAulQP90Wl3mQ6NDwnyrZQzFjDz+UzjXOSyQMgBrTkUBz+pVoYVlX3DUu24gWMZBcit+wOGg==", + "dependencies": { + "@smithy/types": "^2.6.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/hash-stream-node": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-2.0.16.tgz", + "integrity": "sha512-4x24GFdeWos1Z49MC5sYdM1j+z32zcUr6oWM9Ggm3WudFAcRIcbG9uDQ1XgJ0Kl+ZTjpqLKniG0iuWvQb2Ud1A==", + "dependencies": { + "@smithy/types": "^2.6.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.14.tgz", + "integrity": "sha512-d8ohpwZo9RzTpGlAfsWtfm1SHBSU7+N4iuZ6MzR10xDTujJJWtmXYHK1uzcr7rggbpUTaWyHpPFgnf91q0EFqQ==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/md5-js": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-2.0.16.tgz", + "integrity": "sha512-YhWt9aKl+EMSNXyUTUo7I01WHf3HcCkPu/Hl2QmTNwrHT49eWaY7hptAMaERZuHFH0V5xHgPKgKZo2I93DFtgQ==", + "dependencies": { + "@smithy/types": "^2.6.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.16.tgz", + "integrity": "sha512-9ddDia3pp1d3XzLXKcm7QebGxLq9iwKf+J1LapvlSOhpF8EM9SjMeSrMOOFgG+2TfW5K3+qz4IAJYYm7INYCng==", + "dependencies": { + "@smithy/protocol-http": "^3.0.10", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-content-length/node_modules/@smithy/protocol-http": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.10.tgz", + "integrity": "sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.2.1.tgz", + "integrity": "sha512-dVDS7HNJl/wb0lpByXor6whqDbb1YlLoaoWYoelyYzLHioXOE7y/0iDwJWtDcN36/tVCw9EPBFZ3aans84jLpg==", + "dependencies": { + "@smithy/middleware-serde": "^2.0.14", + "@smithy/node-config-provider": "^2.1.6", + "@smithy/shared-ini-file-loader": "^2.2.5", + "@smithy/types": "^2.6.0", + "@smithy/url-parser": "^2.0.14", + "@smithy/util-middleware": "^2.0.7", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.21.tgz", + "integrity": "sha512-EZS1EXv1k6IJX6hyu/0yNQuPcPaXwG8SWljQHYueyRbOxmqYgoWMWPtfZj0xRRQ4YtLawQSpBgAeiJltq8/MPw==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.6", + "@smithy/protocol-http": "^3.0.10", + "@smithy/service-error-classification": "^2.0.7", + "@smithy/types": "^2.6.0", + "@smithy/util-middleware": "^2.0.7", + "@smithy/util-retry": "^2.0.7", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry/node_modules/@smithy/protocol-http": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.10.tgz", + "integrity": "sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.14.tgz", + "integrity": "sha512-hFi3FqoYWDntCYA2IGY6gJ6FKjq2gye+1tfxF2HnIJB5uW8y2DhpRNBSUMoqP+qvYzRqZ6ntv4kgbG+o3pX57g==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.8.tgz", + "integrity": "sha512-7/N59j0zWqVEKExJcA14MrLDZ/IeN+d6nbkN8ucs+eURyaDUXWYlZrQmMOd/TyptcQv0+RDlgag/zSTTV62y/Q==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.1.6.tgz", + "integrity": "sha512-HLqTs6O78m3M3z1cPLFxddxhEPv5MkVatfPuxoVO3A+cHZanNd/H5I6btcdHy6N2CB1MJ/lihJC92h30SESsBA==", + "dependencies": { + "@smithy/property-provider": "^2.0.15", + "@smithy/shared-ini-file-loader": "^2.2.5", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.10.tgz", + "integrity": "sha512-lkALAwtN6odygIM4nB8aHDahINM6WXXjNrZmWQAh0RSossySRT2qa31cFv0ZBuAYVWeprskRk13AFvvLmf1WLw==", + "dependencies": { + "@smithy/abort-controller": "^2.0.14", + "@smithy/protocol-http": "^3.0.10", + "@smithy/querystring-builder": "^2.0.14", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler/node_modules/@smithy/protocol-http": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.10.tgz", + "integrity": "sha512-6+tjNk7rXW7YTeGo9qwxXj/2BFpJTe37kTj3EnZCoX/nH+NP/WLA7O83fz8XhkGqsaAhLUPo/bB12vvd47nsmg==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.15.tgz", + "integrity": "sha512-YbRFBn8oiiC3o1Kn3a4KjGa6k47rCM9++5W9cWqYn9WnkyH+hBWgfJAckuxpyA2Hq6Ys4eFrWzXq6fqHEw7iew==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-2.0.5.tgz", + "integrity": "sha512-d2hhHj34mA2V86doiDfrsy2fNTnUOowGaf9hKb0hIPHqvcnShU4/OSc4Uf1FwHkAdYF3cFXTrj5VGUYbEuvMdw==", + "dependencies": { + "@smithy/types": "^2.2.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.14.tgz", + "integrity": "sha512-lQ4pm9vTv9nIhl5jt6uVMPludr6syE2FyJmHsIJJuOD7QPIJnrf9HhUGf1iHh9KJ4CUv21tpOU3X6s0rB6uJ0g==", + "dependencies": { + "@smithy/types": "^2.6.0", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.14.tgz", + "integrity": "sha512-+cbtXWI9tNtQjlgQg3CA+pvL3zKTAxPnG3Pj6MP89CR3vi3QMmD0SOWoq84tqZDnJCxlsusbgIXk1ngMReXo+A==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.7.tgz", + "integrity": "sha512-LLxgW12qGz8doYto15kZ4x1rHjtXl0BnCG6T6Wb8z2DI4PT9cJfOSvzbuLzy7+5I24PAepKgFeWHRd9GYy3Z9w==", + "dependencies": { + "@smithy/types": "^2.6.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.2.5.tgz", + "integrity": "sha512-LHA68Iu7SmNwfAVe8egmjDCy648/7iJR/fK1UnVw+iAOUJoEYhX2DLgVd5pWllqdDiRbQQzgaHLcRokM+UFR1w==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.16.tgz", + "integrity": "sha512-ilLY85xS2kZZzTb83diQKYLIYALvart0KnBaKnIRnMBHAGEio5aHSlANQoxVn0VsonwmQ3CnWhnCT0sERD8uTg==", + "dependencies": { + "@smithy/eventstream-codec": "^2.0.14", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.6.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.7", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.16.tgz", + "integrity": "sha512-Lw67+yQSpLl4YkDLUzI2KgS8TXclXmbzSeOJUmRFS4ueT56B4pw3RZRF/SRzvgyxM/HxgkUan8oSHXCujPDafQ==", + "dependencies": { + "@smithy/middleware-stack": "^2.0.8", + "@smithy/types": "^2.6.0", + "@smithy/util-stream": "^2.0.21", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.6.0.tgz", + "integrity": "sha512-PgqxJq2IcdMF9iAasxcqZqqoOXBHufEfmbEUdN1pmJrJltT42b0Sc8UiYSWWzKkciIp9/mZDpzYi4qYG1qqg6g==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.14.tgz", + "integrity": "sha512-kbu17Y1AFXi5lNlySdDj7ZzmvupyWKCX/0jNZ8ffquRyGdbDZb+eBh0QnWqsSmnZa/ctyWaTf7n4l/pXLExrnw==", + "dependencies": { + "@smithy/querystring-parser": "^2.0.14", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.1.tgz", + "integrity": "sha512-DlI6XFYDMsIVN+GH9JtcRp3j02JEVuWIn/QOZisVzpIAprdsxGveFed0bjbMRCqmIFe8uetn5rxzNrBtIGrPIQ==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.20.tgz", + "integrity": "sha512-QJtnbTIl0/BbEASkx1MUFf6EaoWqWW1/IM90N++8NNscePvPf77GheYfpoPis6CBQawUWq8QepTP2QUSAdrVkw==", + "dependencies": { + "@smithy/property-provider": "^2.0.15", + "@smithy/smithy-client": "^2.1.16", + "@smithy/types": "^2.6.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.26", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.26.tgz", + "integrity": "sha512-lGFPOFCHv1ql019oegYqa54BZH7HREw6EBqjDLbAr0wquMX0BDi2sg8TJ6Eq+JGLijkZbJB73m4+aK8OFAapMg==", + "dependencies": { + "@smithy/config-resolver": "^2.0.19", + "@smithy/credential-provider-imds": "^2.1.2", + "@smithy/node-config-provider": "^2.1.6", + "@smithy/property-provider": "^2.0.15", + "@smithy/smithy-client": "^2.1.16", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.7.tgz", + "integrity": "sha512-tRINOTlf1G9B0ECarFQAtTgMhpnrMPSa+5j4ZEwEawCLfTFTavk6757sxhE4RY5RMlD/I3x+DCS8ZUiR8ho9Pw==", + "dependencies": { + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.7.tgz", + "integrity": "sha512-fIe5yARaF0+xVT1XKcrdnHKTJ1Vc4+3e3tLDjCuIcE9b6fkBzzGFY7AFiX4M+vj6yM98DrwkuZeHf7/hmtVp0Q==", + "dependencies": { + "@smithy/service-error-classification": "^2.0.7", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.0.21", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.21.tgz", + "integrity": "sha512-0BUE16d7n1x7pi1YluXJdB33jOTyBChT0j/BlOkFa9uxfg6YqXieHxjHNuCdJRARa7AZEj32LLLEPJ1fSa4inA==", + "dependencies": { + "@smithy/fetch-http-handler": "^2.2.7", + "@smithy/node-http-handler": "^2.1.10", + "@smithy/types": "^2.6.0", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.2.tgz", + "integrity": "sha512-qOiVORSPm6Ce4/Yu6hbSgNHABLP2VMv8QOC3tTDNHHlWY19pPyc++fBTbZPtx6egPXi4HQxKDnMxVxpbtX2GoA==", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.14.tgz", + "integrity": "sha512-Q6gSz4GUNjNGhrfNg+2Mjy+7K4pEI3r82x1b/+3dSc03MQqobMiUrRVN/YK/4nHVagvBELCoXsiHAFQJNQ5BeA==", + "dependencies": { + "@smithy/abort-controller": "^2.0.14", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@types/aws-lambda": { + "version": "8.10.93", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.93.tgz", + "integrity": "sha512-Vsyi9ogDAY3REZDjYnXMRJJa62SDvxHXxJI5nGDQdZW058dDE+av/anynN2rLKbCKXDRNw3D/sQmqxVflZFi4A==" + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + } + } +} diff --git a/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/package.json b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/package.json new file mode 100644 index 0000000..3e82df7 --- /dev/null +++ b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/package.json @@ -0,0 +1,9 @@ +{ + "name": "thaw-objects-lambda", + "version": "1.0.0", + "main": "thaw-objects-lambda.ts", + "dependencies": { + "@aws-sdk/client-s3": "3.405.0", + "@types/aws-lambda": "8.10.93" + } +} diff --git a/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/thaw-objects-lambda.ts b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/thaw-objects-lambda.ts new file mode 100644 index 0000000..3f7be51 --- /dev/null +++ b/packages/aws-copy-out-sharer/lambda/thaw-objects-lambda/thaw-objects-lambda.ts @@ -0,0 +1,160 @@ +import { + HeadObjectCommand, + RestoreObjectCommand, + S3Client, +} from "@aws-sdk/client-s3"; +import { IsThawingError } from "./errors"; + +interface ThawObjectsEvent { + Items: { + bucket: string; + key: string; + }[]; + + BatchInput: { + // ... + // there are other fields in the batch input that we are not interested in - we pass them on + // ... + + glacierFlexibleRetrievalThawDays: number; + glacierFlexibleRetrievalThawSpeed: string; + + glacierDeepArchiveThawDays: number; + glacierDeepArchiveThawSpeed: string; + + intelligentTieringArchiveThawDays: number; + intelligentTieringArchiveThawSpeed: string; + + intelligentTieringDeepArchiveThawDays: number; + intelligentTieringDeepArchiveThawSpeed: string; + }; +} + +/** + * A function to initiate restore/monitor any S3 objects that are in storage + * classes that do not allow immediate access. + * + * Note that restoring objects is the *sole* purpose of this lambda - so even + * though it could detect invalid objects / permissions errors etc - that is + * not what it is going to do. + * + * It attempts to find any objects that need thawing and initiates a restore. + * And it detects if any of in the process of thawing. In those cases it + * throws an Error. In *all other cases* it passes on data for the Fargate + * rclone step (even if there were exceptions it gobbled up). + * + * We do this because rclone has better mechanism for detecting errors and + * we don't want to redo the work here. Also this means error reporting + * out of the overall Steps orchestration will be consistent for "missing files" + * etc. + * + * @param event + */ +export async function handler(event: ThawObjectsEvent) { + console.log("thawObjects()"); + console.log(JSON.stringify(event, null, 2)); + + const client = new S3Client({}); + + // count of how many of the passed in objects we are thawing + let isThawing = 0; + + for (const o of event.Items || []) { + try { + // need to find out if the object is in a "needs restore" or "currently restoring" or "restored" category + const headCommand = new HeadObjectCommand({ + Bucket: o.bucket, + Key: o.key, + }); + + const headResult = await client.send(headCommand); + + if (headResult.Restore) { + // the object is still being thawed + if (headResult.Restore.includes('ongoing-request="true"')) isThawing++; + + // otherwise it may successfully have been restored - in which case we can just continue + // as if the file was in S3 active + // TODO are there other states we should check here? + // the only one I've found is ongoing-request=\"false\", expiry-date=\"Sat, 02 Dec 2023 00:00:00 GMT\" + continue; + } + + // now deal with the objects we have detected that are in storage classes needing restoring but where it + // hasn't started yet + if ( + headResult.StorageClass == "GLACIER" || + headResult.StorageClass == "DEEP_ARCHIVE" || + headResult.StorageClass == "INTELLIGENT_TIERING" + ) { + // some sensible defaults - that we retain if any of the expected parameter values is not present + let days: number = 1; + let tier: string = "Bulk"; + + if (headResult.StorageClass == "GLACIER") { + days = event.BatchInput.glacierFlexibleRetrievalThawDays ?? days; + tier = event.BatchInput.glacierFlexibleRetrievalThawSpeed ?? tier; + } + if (headResult.StorageClass == "DEEP_ARCHIVE") { + days = event.BatchInput.glacierDeepArchiveThawDays ?? days; + tier = event.BatchInput.glacierDeepArchiveThawSpeed ?? tier; + } + if (headResult.StorageClass == "INTELLIGENT_TIERING") { + if (headResult.ArchiveStatus == "ARCHIVE_ACCESS") { + days = event.BatchInput.intelligentTieringArchiveThawDays ?? days; + tier = event.BatchInput.intelligentTieringArchiveThawSpeed ?? tier; + } + if (headResult.ArchiveStatus == "DEEP_ARCHIVE_ACCESS") { + days = + event.BatchInput.intelligentTieringDeepArchiveThawDays ?? days; + tier = + event.BatchInput.intelligentTieringDeepArchiveThawSpeed ?? tier; + } + } + + const restoreObjectCommand = new RestoreObjectCommand({ + Bucket: o.bucket, + Key: o.key, + RestoreRequest: { + Days: days, + GlacierJobParameters: { + Tier: tier, + }, + }, + }); + + const restoreObjectResult = await client.send(restoreObjectCommand); + + // note: if the restore operation itself fails - then above line will throw an exception + // which means this will not count for "isThawing" + // which I think is the correct logic - if there is a permanent reason we can't unthaw an object - it will + // fall through out of this and the rclone will fail (at which point we will get an error and + // we can investigate) + + isThawing++; + } + } catch (e: any) { + // we actually gobble up any errors here (with just a print) + // see the top of this method for details + console.error(e); + } + } + + // the *only* way this method can fail via error is this path + // where we tell the Steps we are in the process of thawing + // *all* other paths should continue on (where they can fail in the rclone) + if (isThawing > 0) + throw new IsThawingError( + `${isThawing}/${event.Items.length} are in the process of thawing`, + ); + + return { + // Note we are converting the objects to rclone format here + // A better spot would be in the Fargate run task but the JsonPath + // for that would be a nightmare + Items: event.Items.map((a) => ({ + rcloneSource: `s3:${a.bucket}/${a.key}`, + })), + BatchInput: event.BatchInput, + }; +} diff --git a/packages/aws-copy-out-sharer/package.json b/packages/aws-copy-out-sharer/package.json index b6e7ef2..c7bdcbf 100644 --- a/packages/aws-copy-out-sharer/package.json +++ b/packages/aws-copy-out-sharer/package.json @@ -27,7 +27,8 @@ "outdir": "dist", "targets": {}, "tsc": { - "outDir": "out" + "outDir": "out", + "rootDir": "src" } }, "dependencies": { diff --git a/packages/aws-copy-out-sharer/construct/can-write-lambda-step-construct.ts b/packages/aws-copy-out-sharer/src/can-write-lambda-step-construct.ts similarity index 95% rename from packages/aws-copy-out-sharer/construct/can-write-lambda-step-construct.ts rename to packages/aws-copy-out-sharer/src/can-write-lambda-step-construct.ts index da2b011..1236c01 100644 --- a/packages/aws-copy-out-sharer/construct/can-write-lambda-step-construct.ts +++ b/packages/aws-copy-out-sharer/src/can-write-lambda-step-construct.ts @@ -38,7 +38,13 @@ export class CanWriteLambdaStepConstruct extends Construct { const canWriteLambda = new NodejsFunction(this, "CanWriteFunction", { vpc: props.vpc, - entry: join(__dirname, "can-write-lambda", "can-write-lambda.ts"), + entry: join( + __dirname, + "..", + "lambda", + "can-write-lambda", + "can-write-lambda.ts", + ), // by specifying the precise runtime - the bundler knows exactly what packages are already in // the base image - and for us can skip bundling @aws-sdk // if we need to move this forward beyond node 18 - then we may need to revisit this diff --git a/packages/aws-copy-out-sharer/copy-out-stack-props.ts b/packages/aws-copy-out-sharer/src/copy-out-stack-props.ts similarity index 100% rename from packages/aws-copy-out-sharer/copy-out-stack-props.ts rename to packages/aws-copy-out-sharer/src/copy-out-stack-props.ts diff --git a/packages/aws-copy-out-sharer/copy-out-stack.ts b/packages/aws-copy-out-sharer/src/copy-out-stack.ts similarity index 94% rename from packages/aws-copy-out-sharer/copy-out-stack.ts rename to packages/aws-copy-out-sharer/src/copy-out-stack.ts index aecc5f5..9068949 100644 --- a/packages/aws-copy-out-sharer/copy-out-stack.ts +++ b/packages/aws-copy-out-sharer/src/copy-out-stack.ts @@ -2,7 +2,7 @@ import { Stack } from "aws-cdk-lib"; import { Construct } from "constructs"; import { CopyOutStackProps } from "./copy-out-stack-props"; import { Cluster } from "aws-cdk-lib/aws-ecs"; -import { CopyOutStateMachineConstruct } from "./construct/copy-out-state-machine-construct"; +import { CopyOutStateMachineConstruct } from "./copy-out-state-machine-construct"; import { Service } from "aws-cdk-lib/aws-servicediscovery"; import { InfrastructureClient } from "@elsa-data/aws-infrastructure"; diff --git a/packages/aws-copy-out-sharer/construct/copy-out-state-machine-construct.ts b/packages/aws-copy-out-sharer/src/copy-out-state-machine-construct.ts similarity index 91% rename from packages/aws-copy-out-sharer/construct/copy-out-state-machine-construct.ts rename to packages/aws-copy-out-sharer/src/copy-out-state-machine-construct.ts index ba23e97..5410263 100644 --- a/packages/aws-copy-out-sharer/construct/copy-out-state-machine-construct.ts +++ b/packages/aws-copy-out-sharer/src/copy-out-state-machine-construct.ts @@ -15,6 +15,7 @@ import { CanWriteLambdaStepConstruct } from "./can-write-lambda-step-construct"; import { IVpc, SubnetType } from "aws-cdk-lib/aws-ec2"; import { DistributedMapStepConstruct } from "./distributed-map-step-construct"; import { FargateRunTaskConstruct } from "./fargate-run-task-construct"; +import { ThawObjectsLambdaStepConstruct } from "./thaw-objects-lambda-step-construct"; export type CopyOutStateMachineProps = { vpc: IVpc; @@ -53,6 +54,22 @@ export class CopyOutStateMachineConstruct extends Construct { }, ); + const thawObjectsLambdaStep = new ThawObjectsLambdaStepConstruct( + this, + "ThawObjects", + { + vpc: props.vpc, + vpcSubnetSelection: props.vpcSubnetSelection, + }, + ); + + thawObjectsLambdaStep.invocableLambda.addRetry({ + errors: ["IsThawingError"], + interval: Duration.minutes(1), + backoffRate: 1, + maxAttempts: 15, + }); + const rcloneRunTask = new FargateRunTaskConstruct( this, "RcloneFargateTask", @@ -69,11 +86,14 @@ export class CopyOutStateMachineConstruct extends Construct { maxAttempts: 3, }); + const distributedStepsChain = + thawObjectsLambdaStep.invocableLambda.next(rcloneRunTask); + const distributedMapStep = new DistributedMapStepConstruct( this, "MapStep", { - task: rcloneRunTask, + task: distributedStepsChain, //rcloneRunTask, }, ).distributedMapStep; diff --git a/packages/aws-copy-out-sharer/construct/distributed-map-step-construct.ts b/packages/aws-copy-out-sharer/src/distributed-map-step-construct.ts similarity index 80% rename from packages/aws-copy-out-sharer/construct/distributed-map-step-construct.ts rename to packages/aws-copy-out-sharer/src/distributed-map-step-construct.ts index 0cb473b..89db4e4 100644 --- a/packages/aws-copy-out-sharer/construct/distributed-map-step-construct.ts +++ b/packages/aws-copy-out-sharer/src/distributed-map-step-construct.ts @@ -31,6 +31,7 @@ export class DistributedMapStepConstruct extends Construct { // }, // "Items": [ // { + // "protocol: "s3", // "source": "s3:bucket/1.fastq.gz" // }, // { @@ -51,7 +52,7 @@ export class DistributedMapStepConstruct extends Construct { // not sure distributed map knows how to handle back-off?? // https://docs.aws.amazon.com/AmazonECS/latest/userguide/throttling.html MaxConcurrency: 80, - ToleratedFailurePercentage: 25, + ToleratedFailurePercentage: 100, ItemReader: { ReaderConfig: { InputType: "CSV", @@ -68,11 +69,19 @@ export class DistributedMapStepConstruct extends Construct { ItemBatcher: { MaxItemsPerBatchPath: JsonPath.stringAt("$.maxItemsPerBatch"), BatchInput: { - "destinationForRclone.$": JsonPath.format( + "rcloneDestination.$": JsonPath.format( "s3:{}/{}", JsonPath.stringAt("$.destinationBucket"), JsonPath.stringAt("$.destinationKey"), ), + glacierFlexibleRetrievalThawDays: 1, + glacierFlexibleRetrievalThawSpeed: "Expedited", + glacierDeepArchiveThawDays: 1, + glacierDeepArchiveThawSpeed: "Standard", + intelligentTieringArchiveThawDays: 1, + intelligentTieringArchiveThawSpeed: "Standard", + intelligentTieringDeepArchiveThawDays: 1, + intelligentTieringDeepArchiveThawSpeed: "Standard", }, }, ItemProcessor: { @@ -83,12 +92,10 @@ export class DistributedMapStepConstruct extends Construct { }, }, ItemSelector: { - "source.$": JsonPath.format( - // note: this is not an s3:// URL, it is the peculiar syntax used by rclone - "s3:{}/{}", - JsonPath.stringAt(`$$.Map.Item.Value.${bucketColumnName}`), - JsonPath.stringAt(`$$.Map.Item.Value.${keyColumnName}`), + "bucket.$": JsonPath.stringAt( + `$$.Map.Item.Value.${bucketColumnName}`, ), + "key.$": JsonPath.stringAt(`$$.Map.Item.Value.${keyColumnName}`), }, ResultWriter: { Resource: "arn:aws:states:::s3:putObject", diff --git a/packages/aws-copy-out-sharer/construct/fargate-run-task-construct.ts b/packages/aws-copy-out-sharer/src/fargate-run-task-construct.ts similarity index 89% rename from packages/aws-copy-out-sharer/construct/fargate-run-task-construct.ts rename to packages/aws-copy-out-sharer/src/fargate-run-task-construct.ts index 808aac4..4d71376 100644 --- a/packages/aws-copy-out-sharer/construct/fargate-run-task-construct.ts +++ b/packages/aws-copy-out-sharer/src/fargate-run-task-construct.ts @@ -1,7 +1,7 @@ import { Construct } from "constructs"; import { ManagedPolicy, PolicyStatement } from "aws-cdk-lib/aws-iam"; import { IntegrationPattern, JsonPath } from "aws-cdk-lib/aws-stepfunctions"; -import { Duration, Stack, Tags } from "aws-cdk-lib"; +import { Duration, Stack } from "aws-cdk-lib"; import { AssetImage, CpuArchitecture, @@ -54,7 +54,7 @@ export class FargateRunTaskConstruct extends Construct { memoryLimitMiB: 512, }); - Tags.of(taskDefinition).add("test", "tag"); + // Tags.of(taskDefinition).add("test", "tag"); // we need to give the rclone task the ability to do the copy out in S3 // TODO can we limit this to reading from our designated buckets and writing out @@ -74,13 +74,16 @@ export class FargateRunTaskConstruct extends Construct { ); const containerDefinition = taskDefinition.addContainer("RcloneContainer", { - // set the stop timeout to the maximum allowed under Fargate - as potentially this will let us finish - // our rclone operation + // set the stop timeout to the maximum allowed under Fargate Spot + // potentially this will let us finish our rclone operation (!!! - we don't actually try to let rclone finish - see Docker image - we should) stopTimeout: Duration.seconds(120), - image: new AssetImage(join(__dirname, "rclone-batch-copy-docker-image"), { - // note we are forcing the X86 platform because we want to use Fargate spot which is only available intel/x86 - platform: Platform.LINUX_AMD64, - }), + image: new AssetImage( + join(__dirname, "..", "docker", "rclone-batch-docker-image"), + { + // note we are forcing the X86 platform because we want to use Fargate spot which is only available intel/x86 + platform: Platform.LINUX_AMD64, + }, + ), logging: LogDriver.awsLogs({ streamPrefix: "elsa-data-copy-out", logRetention: RetentionDays.ONE_WEEK, @@ -109,28 +112,27 @@ export class FargateRunTaskConstruct extends Construct { subnets: { subnetType: props.vpcSubnetSelection, }, - resultSelector: { - // NOTE almost any amount of output can cause the joint result to overflow.. - // best to look up all this data at the ECS Task level - // have left these here to show how you can export ECS output if you want - // "capacityProviderName.$": JsonPath.stringAt("$.CapacityProviderName"), - // "stoppedAt.$": JsonPath.numberAt("$.StoppedAt"), - // "stoppedReason.$": JsonPath.stringAt("$.StoppedReason"), - }, + //resultSelector: { + // "rclone.$": JsonPath.objectAt("$"), + // "capacityProviderName.$": JsonPath.stringAt("$.CapacityProviderName"), + //"stoppedAt.$": JsonPath.numberAt("$.StoppedAt"), + //"stoppedReason.$": JsonPath.stringAt("$.StoppedReason"), + // }, + resultPath: "$.rcloneResult", containerOverrides: [ { containerDefinition: containerDefinition, - command: JsonPath.listAt("$.Items[*].source"), + command: JsonPath.listAt("$.Items[*].rcloneSource"), environment: [ { - name: "destination", + name: "RB_DESTINATION", // note this might be just a bucket name, or a bucket name with path // (that decision is made higher in the stack) // as far as rclone binary itself is concerned, it does not matter - value: JsonPath.stringAt("$.BatchInput.destinationForRclone"), + value: JsonPath.stringAt("$.BatchInput.rcloneDestination"), }, { - name: "tasktoken", + name: "RB_TASK_TOKEN", value: JsonPath.stringAt("$$.Task.Token"), }, ], diff --git a/packages/aws-copy-out-sharer/src/thaw-objects-lambda-step-construct.ts b/packages/aws-copy-out-sharer/src/thaw-objects-lambda-step-construct.ts new file mode 100644 index 0000000..d84d1ec --- /dev/null +++ b/packages/aws-copy-out-sharer/src/thaw-objects-lambda-step-construct.ts @@ -0,0 +1,65 @@ +import { Construct } from "constructs"; +import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam"; +import { Duration } from "aws-cdk-lib"; +import { LambdaInvoke } from "aws-cdk-lib/aws-stepfunctions-tasks"; +import { Runtime } from "aws-cdk-lib/aws-lambda"; +import { IVpc, SubnetType } from "aws-cdk-lib/aws-ec2"; +import { JsonPath } from "aws-cdk-lib/aws-stepfunctions"; +import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; +import { join } from "path"; + +type ThawObjectsLambdaStepProps = { + vpc: IVpc; + vpcSubnetSelection: SubnetType; +}; + +/** + * A construct for a Steps function that tests whether an S3 + * bucket exists, is in the correct region, and is writeable + * by us. Throws an exception if any of these conditions is not met. + */ +export class ThawObjectsLambdaStepConstruct extends Construct { + public readonly invocableLambda; + + constructor(scope: Construct, id: string, props: ThawObjectsLambdaStepProps) { + super(scope, id); + + const thawObjectsLambda = new NodejsFunction(this, "ThawObjectsFunction", { + vpc: props.vpc, + entry: join( + __dirname, + "..", + "lambda", + "thaw-objects-lambda", + "thaw-objects-lambda.ts", + ), + runtime: Runtime.NODEJS_20_X, + handler: "handler", + bundling: { + minify: false, + }, + vpcSubnets: { + subnetType: props.vpcSubnetSelection, + }, + // this seems like plenty of seconds to do a few API calls to S3 + timeout: Duration.seconds(300), + }); + + thawObjectsLambda.addToRolePolicy( + new PolicyStatement({ + effect: Effect.ALLOW, + actions: ["s3:*"], + resources: ["*"], + }), + ); + + this.invocableLambda = new LambdaInvoke( + this, + `Are The Objects Available To Copy?`, + { + lambdaFunction: thawObjectsLambda, + resultPath: JsonPath.DISCARD, + }, + ); + } +}