From 3b9ae601b6de29fb8a6e08e6fa64f020550ea573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cristian=20Pallar=C3=A9s?= Date: Fri, 23 Feb 2024 11:58:13 +0100 Subject: [PATCH] feat: `bring dynamodb` --- .github/workflows/dynamodb-pull.yaml | 29 + .github/workflows/dynamodb-release.yaml | 56 + dynamodb/.gitignore | 2 + dynamodb/LICENSE | 21 + dynamodb/README.md | 58 + dynamodb/lib.mjs | 170 +++ dynamodb/lib.w | 467 ++++++++ dynamodb/package-lock.json | 1285 +++++++++++++++++++++++ dynamodb/package.json | 16 + dynamodb/tests/query.test.w | 61 ++ dynamodb/tests/scan.test.w | 31 + 11 files changed, 2196 insertions(+) create mode 100644 .github/workflows/dynamodb-pull.yaml create mode 100644 .github/workflows/dynamodb-release.yaml create mode 100644 dynamodb/.gitignore create mode 100644 dynamodb/LICENSE create mode 100644 dynamodb/README.md create mode 100644 dynamodb/lib.mjs create mode 100644 dynamodb/lib.w create mode 100644 dynamodb/package-lock.json create mode 100644 dynamodb/package.json create mode 100644 dynamodb/tests/query.test.w create mode 100644 dynamodb/tests/scan.test.w diff --git a/.github/workflows/dynamodb-pull.yaml b/.github/workflows/dynamodb-pull.yaml new file mode 100644 index 00000000..2a135467 --- /dev/null +++ b/.github/workflows/dynamodb-pull.yaml @@ -0,0 +1,29 @@ +name: dynamodb-pull +on: + pull_request: + paths: + - dynamodb/** +jobs: + build-dynamodb: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + sparse-checkout: dynamodb + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20.x + registry-url: https://registry.npmjs.org + - name: Install winglang + run: npm i -g winglang + - name: Install dependencies + run: npm install --include=dev + working-directory: dynamodb + - name: Test + run: wing test + working-directory: dynamodb + - name: Pack + run: wing pack + working-directory: dynamodb diff --git a/.github/workflows/dynamodb-release.yaml b/.github/workflows/dynamodb-release.yaml new file mode 100644 index 00000000..c150791a --- /dev/null +++ b/.github/workflows/dynamodb-release.yaml @@ -0,0 +1,56 @@ +name: dynamodb-release +on: + push: + branches: + - main + paths: + - dynamodb/** + - "!dynamodb/package-lock.json" +jobs: + build-dynamodb: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + sparse-checkout: dynamodb + - name: Setup Node.js + uses: actions/setup-node@v3 + with: + node-version: 20.x + registry-url: https://registry.npmjs.org + - name: Install winglang + run: npm i -g winglang + - name: Install dependencies + run: npm install --include=dev + working-directory: dynamodb + - name: Test + run: wing test + working-directory: dynamodb + - name: Pack + run: wing pack + working-directory: dynamodb + - name: Get package version + run: + echo WINGLIB_VERSION=$(node -p "require('./package.json').version") >> + "$GITHUB_ENV" + working-directory: dynamodb + - name: Publish + run: + npm publish --access=public --registry https://registry.npmjs.org --tag + latest *.tgz + working-directory: dynamodb + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + - name: Tag commit + uses: tvdias/github-tagger@v0.0.1 + with: + repo-token: ${{ secrets.PROJEN_GITHUB_TOKEN }} + tag: dynamodb-v${{ env.WINGLIB_VERSION }} + - name: GitHub release + uses: softprops/action-gh-release@v1 + with: + name: dynamodb v${{ env.WINGLIB_VERSION }} + tag_name: dynamodb-v${{ env.WINGLIB_VERSION }} + files: "*.tgz" + token: ${{ secrets.PROJEN_GITHUB_TOKEN }} diff --git a/dynamodb/.gitignore b/dynamodb/.gitignore new file mode 100644 index 00000000..297fdef9 --- /dev/null +++ b/dynamodb/.gitignore @@ -0,0 +1,2 @@ +target/ +node_modules/ diff --git a/dynamodb/LICENSE b/dynamodb/LICENSE new file mode 100644 index 00000000..a875f479 --- /dev/null +++ b/dynamodb/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Wing + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dynamodb/README.md b/dynamodb/README.md new file mode 100644 index 00000000..7a1e4271 --- /dev/null +++ b/dynamodb/README.md @@ -0,0 +1,58 @@ +# dynamodb + +## Prerequisites + +- [winglang](https://winglang.io). + +## Installation + +```sh +npm i @winglibs/dynamodb +``` + +## Usage + +```js +bring dynamodb; + +let table = new dynamodb.Table( + attributeDefinitions: [ + { + attributeName: "id", + attributeType: "S", + }, + ], + keySchema: [ + { + attributeName: "id", + keyType: "HASH", + }, + ], +); + +// Streams. +table.setStreamConsumer(inflight (record) => { + log("record processed = {Json.stringify(record)}"); +}); + +// Put and query. +test "put and query" { + table.put( + item: { + id: "1", + body: "hello", + }, + ); + let response = table.query( + keyConditionExpression: "id = :id", + expressionAttributeValues: {":id": "1"}, + ); + assert(response.count == 1); + assert(response.items.at(0).get("id").asStr() == "1"); + assert(response.items.at(0).get("body").asStr() == "hello"); +} +``` + +## License + +This library is licensed under the [MIT License](./LICENSE). diff --git a/dynamodb/lib.mjs b/dynamodb/lib.mjs new file mode 100644 index 00000000..f3259c1a --- /dev/null +++ b/dynamodb/lib.mjs @@ -0,0 +1,170 @@ +export { default as getPort } from "get-port"; + +import * as child_process from "node:child_process"; + +export const spawn = async (options) => { + let child = child_process.spawn(options.command, options.arguments, { + cwd: options.cwd, + env: options.env, + }); + + child.stdout.on("data", (data) => options.onData?.(data.toString())); + child.stderr.on("data", (data) => options.onData?.(data.toString())); + + return { + kill() { + child.kill("SIGINT"); + }, + }; +}; + +import * as dynamodb from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocument } from "@aws-sdk/lib-dynamodb"; + +// export interface CreateClientOptions { +// endpoint: string; +// } + +export const createClient = (endpoint) => { + return new dynamodb.DynamoDB({ + region: "local", + credentials: { + accessKeyId: "local", + secretAccessKey: "local", + }, + endpoint, + }); +}; + +export const createDocumentClient = (endpoint) => { + const client = createClient(endpoint); + return DynamoDBDocument.from(client, { + marshallOptions: { + removeUndefinedValues: true, + convertEmptyValues: true, + }, + unmarshallOptions: { + wrapNumbers: true, + }, + }); +}; + +// const x = DynamoDBDocument.from(); +// x.transactWrite({ +// TransactItems: [ +// { +// Put: {} +// } +// ] +// }) + +import * as streams from "@aws-sdk/client-dynamodb-streams"; + +// export const createStreamsClient = (endpoint) => { +// return new streams.DynamoDBStreams({ +// region: "local", +// credentials: { +// accessKeyId: "local", +// secretAccessKey: "local", +// }, +// endpoint, +// }); +// }; + +/** + * @param {import("@aws-sdk/client-dynamodb-streams").DynamoDBStreams} client + * @param {string} StreamArn + * @param {(record: any) => void|Promise} handler + */ +const processStreamRecords = async (client, StreamArn, handler) => { + // while (true) { + // try { + const { StreamDescription } = await client.describeStream({ StreamArn }); + + for (const { ShardId } of StreamDescription.Shards) { + const shardIteratorData = await client.getShardIterator({ + StreamArn, + ShardId, + ShardIteratorType: "TRIM_HORIZON", + }); + + let shardIterator = shardIteratorData.ShardIterator; + while (shardIterator) { + const recordsData = await client.getRecords({ + ShardIterator: shardIterator, + }); + + for (const record of recordsData.Records) { + try { + await handler(record); + } catch (error) { + console.error("Error processing stream record:", error, record); + } + } + + shardIterator = recordsData.NextShardIterator; + + // AWS DynamoDB fetches records 4 times a second. + await new Promise((resolve) => setTimeout(resolve, 250)); + } + } + // } catch (error) { + // console.error("Error processing stream records:", error); + // console.error("error name", error.name); + // // if (error.name === "TrimmedDataAccessException") { + // // // Ignore... + // // } else { + // // throw error; + // // } + // } + + // console.log("something went wrong"); + // await new Promise((resolve) => setTimeout(resolve, 250)); + // } +}; + +const processRecords = async (endpoint, tableName, handler) => { + while (true) { + const client = new streams.DynamoDBStreams({ + region: "local", + credentials: { + accessKeyId: "local", + secretAccessKey: "local", + }, + endpoint, + }); + + try { + const { Streams } = await client.listStreams({ TableName: tableName }); + await Promise.all( + Streams.map(({ StreamArn }) => + processStreamRecords(client, StreamArn, handler) + ) + ); + } catch (error) { + if (error.message.includes("ECONNREFUSED")) { + // Stop processing records when the host is down. + throw error; + } else if (error.name === "TrimmedDataAccessException") { + // Ignore. This error seems to be a bug in DynamoDB Local. + // The desired behavior is to retry processing the records. + } else if (error.name === "ExpiredIteratorException") { + // Ignore. This error happens after the computer wakes up from sleep. + } else { + throw error; + } + await new Promise((resolve) => setTimeout(resolve, 250)); + } + } +}; + +export const processRecordsAsync = async (endpoint, tableName, handler) => { + processRecords(endpoint, tableName, handler).catch((error) => { + if (error.message.includes("ECONNREFUSED")) { + // Ignore. This error happens when reloading the console. + // We can safely end the execution here. + } else { + console.error(error); + } + }); +}; diff --git a/dynamodb/lib.w b/dynamodb/lib.w new file mode 100644 index 00000000..e3914068 --- /dev/null +++ b/dynamodb/lib.w @@ -0,0 +1,467 @@ +bring sim; +bring util; +bring cloud; +bring ui; + +interface Process { + inflight kill(): void; +} + +struct SpawnOptions { + command: str; + arguments: Array; + onData: inflight (str): void; +} + +interface Client { + inflight createTable(input: Json): Json; + inflight deleteTable(input: Json): Json; + inflight updateTimeToLive(input: Json): Json; +} + +interface DocumentClient { + inflight batchExecuteStatement(input: Json): Json; + inflight batchGet(input: Json): Json; + inflight batchWrite(input: Json): Json; + inflight delete(input: Json): Json; + inflight executeStatement(input: Json): Json; + inflight executeTransaction(input: Json): Json; + inflight get(input: Json): Json; + inflight put(input: Json): Json; + inflight query(input: Json): Json; + inflight scan(input: Json): Json; + inflight transactGet(input: Json): Json; + inflight transactWrite(input: Json): Json; + inflight update(input: Json): Json; +} + +struct StreamRecordDynamodb { + ApproximateCreationDateTime: str; + Keys: Json; + NewImage: Json?; + OldImage: Json?; + SequenceNumber: str; + SizeBytes: num; + StreamViewType: str; +} + +struct StreamRecord { + dynamodb: StreamRecordDynamodb; + eventName: str; + eventID: str; +} + +class Util { + extern "./lib.mjs" pub static inflight getPort(): num; + extern "./lib.mjs" pub static inflight spawn(options: SpawnOptions): Process; + extern "./lib.mjs" pub static inflight createClient(endpoint: str): Client; + extern "./lib.mjs" pub static inflight createDocumentClient(endpoint: str): DocumentClient; + extern "./lib.mjs" pub static inflight processRecordsAsync(endpoint: str, tableName: str, handler: inflight (StreamRecord): void): void; +} + +class Host { + pub endpoint: str; + + new() { + let containerName = "winglibs-dynamodb-{util.uuidv4()}"; + + let state = new sim.State(); + this.endpoint = state.token("endpoint"); + + new cloud.Service(inflight () => { + let port = Util.getPort(); + + let docker = Util.spawn( + command: "docker", + arguments: [ + "run", + "--rm", + "--name", + containerName, + "-p", + "{port}:8000", + "amazon/dynamodb-local", + ], + onData: (data) => { + if data.contains("Initializing DynamoDB Local with the following configuration") { + state.set("endpoint", "http://0.0.0.0:{port}"); + } + }, + ); + + return () => { + docker.kill(); + }; + }); + + // The host will be ready when the endpoint is set. + new cloud.Service(inflight () => { + util.waitUntil(() => { + return state.tryGet("endpoint")?; + }); + }) as "Wait Until"; + + // std.Node.of(this).hidden = true; + } + + pub static of(scope: std.IResource): Host { + let uid = "DynamodbHost-7JOQ92VWh6OavMXYpWx9O"; + let root = std.Node.of(scope).root; + let rootNode = std.Node.of(root); + return unsafeCast(rootNode.tryFindChild(uid)) ?? new Host() as uid in root; + } +} + +struct GetOptions { + key: Json; +} + +struct GetOutput { + item: Json?; +} + +struct PutOptions { + item: Json; + conditionExpression: str?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + // returnValues: str?; + // returnValuesOnConditionCheckFailure: str?; +} + +struct PutOutput { + // attributes: Json?; +} + +struct TransactWriteItemConditionCheck { + key: Json; + conditionExpression: str?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + returnValuesOnConditionCheckFailure: bool?; +} + +struct TransactWriteItemPut { + item: Json; + conditionExpression: str?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + returnValuesOnConditionCheckFailure: bool?; +} + +struct TransactWriteItemDelete { + key: Json; + conditionExpression: str?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + returnValuesOnConditionCheckFailure: bool?; +} + +struct TransactWriteItemUpdate { + key: Json; + conditionExpression: str?; + updateExpression: str?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + returnValuesOnConditionCheckFailure: bool?; +} + +struct TransactWriteItem { + conditionCheck: TransactWriteItemConditionCheck?; + put: TransactWriteItemPut?; + delete: TransactWriteItemDelete?; + update: TransactWriteItemUpdate?; +} + +struct TransactWriteOptions { + transactItems: Array; +} + +struct TransactWriteOutput {} + +struct ScanOptions { + consistentRead: bool?; + exclusiveStartKey: Json?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + filterExpression: str?; + indexName: str?; + limit: num?; + projectionExpression: str?; + returnConsumedCapacity: str?; + select: str?; + segment: num?; + totalSegments: num?; +} + +struct ScanOutput { + items: Array; + count: num; + scannedCount: num; + lastEvaluatedKey: Json?; + consumedCapacity: Json?; +} + +struct QueryOptions { + consistentRead: bool?; + exclusiveStartKey: Json?; + expressionAttributeNames: Map?; + expressionAttributeValues: Map?; + filterExpression: str?; + indexName: str?; + keyConditionExpression: str; + limit: num?; + projectionExpression: str?; + returnConsumedCapacity: str?; + scanIndexForward: bool?; + select: str?; +} + +struct QueryOutput { + items: Array; + count: num; + scannedCount: num; + lastEvaluatedKey: Json?; + consumedCapacity: Json?; +} + +struct AttributeDefinition { + attributeName: str; + attributeType: str; +} + +struct KeySchema { + attributeName: str; + keyType: str; +} + +struct TableProps { + attributeDefinitions: Array; + keySchema: Array; + timeToLiveAttribute: str?; +} + +pub class Table { + host: Host; + // var usesStreams: bool; + + tableName: str; + + new(props: TableProps) { + this.host = Host.of(this); + // this.usesStreams = false; + + let tableName = this.node.addr; + let state = new sim.State(); + this.tableName = state.token("tableName"); + + new ui.Field( + "Key Schema", + inflight () => { + return Json.stringify(props.keySchema, indent: 2); + }, + ); + + new cloud.Service(inflight () => { + let client = Util.createClient(this.host.endpoint); + + let attributeDefinitions = MutArray []; + for attributeDefinition in props.attributeDefinitions { + attributeDefinitions.push({ + AttributeName: attributeDefinition.attributeName, + AttributeType: attributeDefinition.attributeType, + }); + } + + let keySchemas = MutArray []; + for keySchema in props.keySchema { + keySchemas.push({ + AttributeName: keySchema.attributeName, + KeyType: keySchema.keyType, + }); + } + + util.waitUntil(() => { + try { + client.createTable({ + TableName: tableName, + AttributeDefinitions: attributeDefinitions.copy(), + KeySchema: keySchemas.copy(), + BillingMode: "PAY_PER_REQUEST", + StreamSpecification: { + StreamEnabled: true, + StreamViewType: "NEW_AND_OLD_IMAGES", + }, + }); + + if let timeToLiveAttribute = props.timeToLiveAttribute { + client.updateTimeToLive({ + TableName: tableName, + TimeToLiveSpecification: { + AttributeName: timeToLiveAttribute, + Enabled: true, + }, + }); + } + + state.set("tableName", tableName); + return true; + } catch error { + return false; + } + }); + + // return () => { + // try { + // client.deleteTable({ + // TableName: tableName, + // }); + // } catch {} + // }; + }); + } + + pub setStreamConsumer(handler: inflight (StreamRecord): void) { + // if this.usesStreams { + // throw "Table.onStream can only be called once"; + // } + // this.usesStreams = true; + new cloud.Service(inflight () => { + Util.processRecordsAsync(this.host.endpoint, this.tableName, handler); + }) as "StreamConsumer"; + } + + inflight client: DocumentClient; + + inflight new() { + this.client = Util.createDocumentClient(this.host.endpoint); + } + + pub inflight get(options: GetOptions): GetOutput { + let response = this.client.get({ + TableName: this.tableName, + Key: options.key, + }); + return { + item: unsafeCast(response)?.Item, + }; + } + + pub inflight put(options: PutOptions): PutOutput { + let response = this.client.put({ + TableName: this.tableName, + Item: options.item, + ConditionExpression: options.conditionExpression, + ExpressionAttributeNames: options.expressionAttributeNames, + ExpressionAttributeValues: options.expressionAttributeValues, + }); + return {}; + } + + pub inflight transactWrite(options: TransactWriteOptions): TransactWriteOutput { + let transactItems = MutArray []; + for item in options.transactItems { + if let operation = item.conditionCheck { + transactItems.push({ + ConditionCheck: { + TableName: this.tableName, + Key: operation.key, + ConditionExpression: operation.conditionExpression, + ExpressionAttributeNames: operation.expressionAttributeNames, + ExpressionAttributeValues: operation.expressionAttributeValues, + ReturnValuesOnConditionCheckFailure: operation.returnValuesOnConditionCheckFailure, + }, + }); + } elif let operation = item.delete { + transactItems.push({ + Delete: { + TableName: this.tableName, + Key: operation.key, + ConditionExpression: operation.conditionExpression, + ExpressionAttributeNames: operation.expressionAttributeNames, + ExpressionAttributeValues: operation.expressionAttributeValues, + ReturnValuesOnConditionCheckFailure: operation.returnValuesOnConditionCheckFailure, + }, + }); + } elif let operation = item.put { + transactItems.push({ + Put: { + TableName: this.tableName, + Item: operation.item, + ConditionExpression: operation.conditionExpression, + ExpressionAttributeNames: operation.expressionAttributeNames, + ExpressionAttributeValues: operation.expressionAttributeValues, + ReturnValuesOnConditionCheckFailure: operation.returnValuesOnConditionCheckFailure, + }, + }); + } elif let operation = item.update { + transactItems.push({ + Update: { + TableName: this.tableName, + Key: operation.key, + ConditionExpression: operation.conditionExpression, + ExpressionAttributeNames: operation.expressionAttributeNames, + ExpressionAttributeValues: operation.expressionAttributeValues, + ReturnValuesOnConditionCheckFailure: operation.returnValuesOnConditionCheckFailure, + }, + }); + } else { + throw "Invalid transact item"; + } + } + this.client.transactWrite({ + TransactItems: transactItems.copy(), + }); + return {}; + } + + pub inflight scan(options: ScanOptions?): ScanOutput { + let response = this.client.scan({ + TableName: this.tableName, + ConsistentRead: options?.consistentRead, + ExclusiveStartKey: options?.exclusiveStartKey, + ExpressionAttributeNames: options?.expressionAttributeNames, + ExpressionAttributeValues: options?.expressionAttributeValues, + FilterExpression: options?.filterExpression, + IndexName: options?.indexName, + Limit: options?.limit, + ProjectionExpression: options?.projectionExpression, + ReturnConsumedCapacity: options?.returnConsumedCapacity, + Select: options?.select, + Segment: options?.segment, + TotalSegments: options?.totalSegments, + }); + return { + items: unsafeCast(response)?.Items, + count: unsafeCast(response)?.Count, + scannedCount: unsafeCast(response)?.ScannedCount, + lastEvaluatedKey: unsafeCast(response)?.LastEvaluatedKey, + consumedCapacity: unsafeCast(response)?.ConsumedCapacity, + }; + } + + pub inflight query(options: QueryOptions): QueryOutput { + let response = this.client.query({ + TableName: this.tableName, + ConsistentRead: options.consistentRead, + ExclusiveStartKey: options.exclusiveStartKey, + ExpressionAttributeNames: options.expressionAttributeNames, + ExpressionAttributeValues: options.expressionAttributeValues, + FilterExpression: options.filterExpression, + IndexName: options.indexName, + KeyConditionExpression: options.keyConditionExpression, + Limit: options.limit, + ProjectionExpression: options.projectionExpression, + ReturnConsumedCapacity: options.returnConsumedCapacity, + ScanIndexForward: options.scanIndexForward, + Select: options.select, + }); + return { + items: unsafeCast(response)?.Items, + count: unsafeCast(response)?.Count, + scannedCount: unsafeCast(response)?.ScannedCount, + lastEvaluatedKey: unsafeCast(response)?.LastEvaluatedKey, + consumedCapacity: unsafeCast(response)?.ConsumedCapacity, + }; + } +} diff --git a/dynamodb/package-lock.json b/dynamodb/package-lock.json new file mode 100644 index 00000000..6c8a5086 --- /dev/null +++ b/dynamodb/package-lock.json @@ -0,0 +1,1285 @@ +{ + "name": "@winglibs/dynamodb", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@winglibs/dynamodb", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.461.0", + "@aws-sdk/client-dynamodb-streams": "^3.461.0", + "@aws-sdk/lib-dynamodb": "^3.462.0", + "get-port": "^7.0.0" + } + }, + "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/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/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-dynamodb": { + "version": "3.461.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.461.0.tgz", + "integrity": "sha512-TiticmxDYxlS76HXNDOO9XgTTZZcpLg79EuBZGXBEGlFT5ZHwsrvsvkbGHDm6uYsvndme4W04CsxvxWHG4Jm4w==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.461.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.460.0", + "@aws-sdk/middleware-endpoint-discovery": "3.460.0", + "@aws-sdk/middleware-host-header": "3.460.0", + "@aws-sdk/middleware-logger": "3.460.0", + "@aws-sdk/middleware-recursion-detection": "3.460.0", + "@aws-sdk/middleware-signing": "3.461.0", + "@aws-sdk/middleware-user-agent": "3.460.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.460.0", + "@aws-sdk/util-endpoints": "3.460.0", + "@aws-sdk/util-user-agent-browser": "3.460.0", + "@aws-sdk/util-user-agent-node": "3.460.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "@smithy/util-waiter": "^2.0.13", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb-streams": { + "version": "3.461.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb-streams/-/client-dynamodb-streams-3.461.0.tgz", + "integrity": "sha512-HxaewibiO/xvsobOCIHd0gLlOvwJ3JUmufR37kv6NQbcZwrEvinZ2zDhKeRGJFwcm75oMHkuUfYuM2eonb0tKA==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.461.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.460.0", + "@aws-sdk/middleware-host-header": "3.460.0", + "@aws-sdk/middleware-logger": "3.460.0", + "@aws-sdk/middleware-recursion-detection": "3.460.0", + "@aws-sdk/middleware-signing": "3.461.0", + "@aws-sdk/middleware-user-agent": "3.460.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.460.0", + "@aws-sdk/util-endpoints": "3.460.0", + "@aws-sdk/util-user-agent-browser": "3.460.0", + "@aws-sdk/util-user-agent-node": "3.460.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.460.0.tgz", + "integrity": "sha512-p5D9C8LKJs5yoBn5cCs2Wqzrp5YP5BYcP774bhGMFEu/LCIUyWzudwN3+/AObSiq8R8SSvBY2zQD4h+k3NjgTQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/middleware-host-header": "3.460.0", + "@aws-sdk/middleware-logger": "3.460.0", + "@aws-sdk/middleware-recursion-detection": "3.460.0", + "@aws-sdk/middleware-user-agent": "3.460.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.460.0", + "@aws-sdk/util-endpoints": "3.460.0", + "@aws-sdk/util-user-agent-browser": "3.460.0", + "@aws-sdk/util-user-agent-node": "3.460.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.461.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.461.0.tgz", + "integrity": "sha512-1u+t31m23vuc9zkiUk51L4QbwuRQEuBeMArHK/thmq4V+A0VmjoAr/x2D0eQ0deOuBqG5YC62oaqUfIhj03SIw==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/core": "3.451.0", + "@aws-sdk/credential-provider-node": "3.460.0", + "@aws-sdk/middleware-host-header": "3.460.0", + "@aws-sdk/middleware-logger": "3.460.0", + "@aws-sdk/middleware-recursion-detection": "3.460.0", + "@aws-sdk/middleware-sdk-sts": "3.461.0", + "@aws-sdk/middleware-signing": "3.461.0", + "@aws-sdk/middleware-user-agent": "3.460.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.460.0", + "@aws-sdk/util-endpoints": "3.460.0", + "@aws-sdk/util-user-agent-browser": "3.460.0", + "@aws-sdk/util-user-agent-node": "3.460.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/protocol-http": "^3.0.9", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.451.0.tgz", + "integrity": "sha512-SamWW2zHEf1ZKe3j1w0Piauryl8BQIlej0TBS18A4ACzhjhWXhCs13bO1S88LvPR5mBFXok3XOT6zPOnKDFktw==", + "dependencies": { + "@smithy/smithy-client": "^2.1.15", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.460.0.tgz", + "integrity": "sha512-WWdaRJFuYRc2Ue9NKDy2NIf8pQRNx/QRVmrsk6EkIID8uWlQIOePk3SWTVV0TZIyPrbfSEaSnJRZoShphJ6PAg==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.460.0.tgz", + "integrity": "sha512-1IEUmyaWzt2M3mONO8QyZtPy0f9ccaEjCo48ZQLgptWxUI+Ohga9gPK0mqu1kTJOjv4JJGACYHzLwEnnpltGlA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.460.0", + "@aws-sdk/credential-provider-process": "3.460.0", + "@aws-sdk/credential-provider-sso": "3.460.0", + "@aws-sdk/credential-provider-web-identity": "3.460.0", + "@aws-sdk/types": "3.460.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.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.460.0.tgz", + "integrity": "sha512-PbPo92WIgNlF6V4eWKehYGYjTqf0gU9vr09LeQUc3bTm1DJhJw1j+HU/3PfQ8LwTkBQePO7MbJ5A2n6ckMwfMg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.460.0", + "@aws-sdk/credential-provider-ini": "3.460.0", + "@aws-sdk/credential-provider-process": "3.460.0", + "@aws-sdk/credential-provider-sso": "3.460.0", + "@aws-sdk/credential-provider-web-identity": "3.460.0", + "@aws-sdk/types": "3.460.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.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.460.0.tgz", + "integrity": "sha512-ng+0FMc4EaxLAwdttCwf2nzNf4AgcqAHZ8pKXUf8qF/KVkoyTt3UZKW7P2FJI01zxwP+V4yAwVt95PBUKGn4YQ==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.460.0.tgz", + "integrity": "sha512-KnrQieOw17+aHEzE3SwfxjeSQ5ZTe2HeAzxkaZF++GxhNul/PkVnLzjGpIuB9bn71T9a2oNfG3peDUA+m2l2kw==", + "dependencies": { + "@aws-sdk/client-sso": "3.460.0", + "@aws-sdk/token-providers": "3.460.0", + "@aws-sdk/types": "3.460.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.460.0.tgz", + "integrity": "sha512-7OeaZgC3HmJZGE0I0ZiKInUMF2LyA0IZiW85AYFnAZzAIfv1cXk/1UnDAoFIQhOZfnUBXivStagz892s480ryw==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/endpoint-cache": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.310.0.tgz", + "integrity": "sha512-y3wipforet41EDTI0vnzxILqwAGll1KfI5qcdX9pXF/WF1f+3frcOtPiWtQEZQpy4czRogKm3BHo70QBYAZxlQ==", + "dependencies": { + "mnemonist": "0.38.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.462.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.462.0.tgz", + "integrity": "sha512-74WOZNv+LjoVIrkKcSgr7bQv1tNheKpUJ86iIGpYG0tIYzd9pIB1THyc/divLk8fRlayuGkT96c2bBO7xqGwKg==", + "dependencies": { + "@aws-sdk/util-dynamodb": "3.462.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.0.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.460.0.tgz", + "integrity": "sha512-bhf1RS43azJPkrEWcVnD9lCsOrhetKWjiCjr/6eUsDZlb2XLDuGa9KCnvbHC76bij+1bFhtA294inwOKLOOV5w==", + "dependencies": { + "@aws-sdk/endpoint-cache": "3.310.0", + "@aws-sdk/types": "3.460.0", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.460.0.tgz", + "integrity": "sha512-qBeDyuJkEuHe87Xk6unvFO9Zg5j6zM8bQOOZITocTLfu9JN0u5V4GQ/yopvpv+nQHmC/MGr0G7p+kIXMrg/Q2A==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.460.0.tgz", + "integrity": "sha512-w2AJ6HOJ+Ggx9+VDKuWBHk5S0ZxYEo2EY2IFh0qtCQ1RDix/ur1QEzOOL5vNjHlZKPv/dseIwhgsTCac8UHXbQ==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.460.0.tgz", + "integrity": "sha512-wmzm1/2NzpcCVCAsGqqiTBK+xNyLmQwTOq63rcW6eeq6gYOO0cyTZROOkVRrrsKWPBigrSFFHvDrEvonOMtKAg==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.461.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.461.0.tgz", + "integrity": "sha512-sgNxkwKdJ/NZm7SJZBnbYPkbspmzn3lDyRSJH7PTCvyzDBzY2PB6yS/dfnGkitR+PYwromuOYMha37W4su2SOw==", + "dependencies": { + "@aws-sdk/middleware-signing": "3.461.0", + "@aws-sdk/types": "3.460.0", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.461.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.461.0.tgz", + "integrity": "sha512-aM/7VupHlsgeRG1UZSAQMWJX+2Jam4GG8ZGVAbLfBr9yh9cBwnUUndpUpYI9rU7atA8n+vISr162EbR7WTiFhQ==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.5.0", + "@smithy/util-middleware": "^2.0.6", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.460.0.tgz", + "integrity": "sha512-0gBSOCr+RtwRUCSRLn9H3RVnj9ercvk/QKTHIr33CgfEdyZtIGpHWUSs6uqiQydPTRzjCm5SfUa6ESGhRVMM6A==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@aws-sdk/util-endpoints": "3.460.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.451.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.451.0.tgz", + "integrity": "sha512-3iMf4OwzrFb4tAAmoROXaiORUk2FvSejnHIw/XHvf/jjR4EqGGF95NZP/n/MeFZMizJWVssrwS412GmoEyoqhg==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.6", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.460.0.tgz", + "integrity": "sha512-EvSIPMI1gXk3gEkdtbZCW+p3Bjmt2gOR1m7ibQD7qLj4l0dKXhp4URgTqB1ExH3S4qUq0M/XSGKbGLZpvunHNg==", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.460.0", + "@aws-sdk/middleware-logger": "3.460.0", + "@aws-sdk/middleware-recursion-detection": "3.460.0", + "@aws-sdk/middleware-user-agent": "3.460.0", + "@aws-sdk/region-config-resolver": "3.451.0", + "@aws-sdk/types": "3.460.0", + "@aws-sdk/util-endpoints": "3.460.0", + "@aws-sdk/util-user-agent-browser": "3.460.0", + "@aws-sdk/util-user-agent-node": "3.460.0", + "@smithy/config-resolver": "^2.0.18", + "@smithy/fetch-http-handler": "^2.2.6", + "@smithy/hash-node": "^2.0.15", + "@smithy/invalid-dependency": "^2.0.13", + "@smithy/middleware-content-length": "^2.0.15", + "@smithy/middleware-endpoint": "^2.2.0", + "@smithy/middleware-retry": "^2.0.20", + "@smithy/middleware-serde": "^2.0.13", + "@smithy/middleware-stack": "^2.0.7", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/node-http-handler": "^2.1.9", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.9", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.15", + "@smithy/types": "^2.5.0", + "@smithy/url-parser": "^2.0.13", + "@smithy/util-base64": "^2.0.1", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.19", + "@smithy/util-defaults-mode-node": "^2.0.25", + "@smithy/util-endpoints": "^1.0.4", + "@smithy/util-retry": "^2.0.6", + "@smithy/util-utf8": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.460.0.tgz", + "integrity": "sha512-MyZSWS/FV8Bnux5eD9en7KLgVxevlVrGNEP3X2D7fpnUlLhl0a7k8+OpSI2ozEQB8hIU2DLc/XXTKRerHSefxQ==", + "dependencies": { + "@smithy/types": "^2.5.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-dynamodb": { + "version": "3.462.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.462.0.tgz", + "integrity": "sha512-4/GfLrR/C36l+fcBucWxd3AJCmcuoiaLbUzhvNLGvEDlWzGL40SEVnKt9oVqrkYlroqHaw/C41LOqOdYtiJ4uA==", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.460.0.tgz", + "integrity": "sha512-myH6kM5WP4IWULHDHMYf2Q+BCYVGlzqJgiBmO10kQEtJSeAGZZ49eoFFYgKW8ZAYB5VnJ+XhXVB1TRA+vR4l5A==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/util-endpoints": "^1.0.4", + "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.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.460.0.tgz", + "integrity": "sha512-FRCzW+TyjKnvxsargPVrjayBfp/rvObYHZyZ2OSqrVw8lkkPCb4e/WZOeIiXZuhdhhoah7wMuo6zGwtFF3bYKg==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/types": "^2.5.0", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.460.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.460.0.tgz", + "integrity": "sha512-+kSoR9ABGpJ5Xc7v0VwpgTQbgyI4zuezC8K4pmKAGZsSsVWg4yxptoy2bDqoFL7qfRlWviMVTkQRMvR4D44WxA==", + "dependencies": { + "@aws-sdk/types": "3.460.0", + "@smithy/node-config-provider": "^2.1.5", + "@smithy/types": "^2.5.0", + "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/@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/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/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/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/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/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-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-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/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": "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/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-endpoints": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.0.5.tgz", + "integrity": "sha512-K7qNuCOD5K/90MjHvHm9kJldrfm40UxWYQxNEShMFxV/lCCCRIg8R4uu1PFAxRvPxNpIdcrh1uK6I1ISjDXZJw==", + "dependencies": { + "@smithy/node-config-provider": "^2.1.6", + "@smithy/types": "^2.6.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.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/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/get-port": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-7.0.0.tgz", + "integrity": "sha512-mDHFgApoQd+azgMdwylJrv2DX47ywGq1i5VFJE7fZ0dttNq3iQMfsU4IvEgBHojA3KqEudyu7Vq+oN8kNaNkWw==", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mnemonist": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.38.3.tgz", + "integrity": "sha512-2K9QYubXx/NAjv4VLq1d1Ly8pWNC5L3BrixtdkyTegXWJIqY+zLNDhhX/A+ZwWt70tB1S8H4BE8FLYEFyNoOBw==", + "dependencies": { + "obliterator": "^1.6.1" + } + }, + "node_modules/obliterator": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-1.6.1.tgz", + "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==" + }, + "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/dynamodb/package.json b/dynamodb/package.json new file mode 100644 index 00000000..f84bb4dc --- /dev/null +++ b/dynamodb/package.json @@ -0,0 +1,16 @@ +{ + "name": "@winglibs/dynamodb", + "version": "0.0.1", + "repository": { + "type": "git", + "url": "https://github.com/winglang/winglibs.git", + "directory": "dynamodb" + }, + "license": "MIT", + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.461.0", + "@aws-sdk/client-dynamodb-streams": "^3.461.0", + "@aws-sdk/lib-dynamodb": "^3.462.0", + "get-port": "^7.0.0" + } +} diff --git a/dynamodb/tests/query.test.w b/dynamodb/tests/query.test.w new file mode 100644 index 00000000..94b0f9a6 --- /dev/null +++ b/dynamodb/tests/query.test.w @@ -0,0 +1,61 @@ +bring cloud; +bring "../lib.w" as lib; + +let table = new lib.Table( + attributeDefinitions: [ + { + attributeName: "id", + attributeType: "S", + }, + { + attributeName: "sk", + attributeType: "S", + }, + ], + keySchema: [ + { + attributeName: "id", + keyType: "HASH", + }, + { + attributeName: "sk", + keyType: "RANGE", + }, + ], +) as "query table"; + +test "query" { + table.put( + item: { + id: "1", + sk: "a", + body: "hello a", + }, + ); + table.put( + item: { + id: "2", + sk: "a", + body: "hello a", + }, + ); + table.put( + item: { + id: "1", + sk: "b", + body: "hello b", + }, + ); + + let response = table.query( + keyConditionExpression: "id = :id", + expressionAttributeValues: {":id": "1"}, + ); + assert(response.count == 2); + assert(response.items.at(0).get("id").asStr() == "1"); + assert(response.items.at(0).get("sk").asStr() == "a"); + assert(response.items.at(0).get("body").asStr() == "hello a"); + assert(response.items.at(1).get("id").asStr() == "1"); + assert(response.items.at(1).get("sk").asStr() == "b"); + assert(response.items.at(1).get("body").asStr() == "hello b"); +} diff --git a/dynamodb/tests/scan.test.w b/dynamodb/tests/scan.test.w new file mode 100644 index 00000000..5294717b --- /dev/null +++ b/dynamodb/tests/scan.test.w @@ -0,0 +1,31 @@ +bring cloud; +bring "../lib.w" as lib; + +let table = new lib.Table( + attributeDefinitions: [ + { + attributeName: "id", + attributeType: "S", + }, + ], + keySchema: [ + { + attributeName: "id", + keyType: "HASH", + }, + ], +); + +test "scan" { + table.put( + item: { + id: "1", + body: "hello", + }, + ); + + let response = table.scan(); + assert(response.count == 1); + assert(response.items.at(0).get("id").asStr() == "1"); + assert(response.items.at(0).get("body").asStr() == "hello"); +}