From 01652a8439fc422bc938084fdcf52a40796b6dbd Mon Sep 17 00:00:00 2001 From: Eric Bach <43318858+eric-bach@users.noreply.github.com> Date: Mon, 30 Dec 2024 14:49:42 -0700 Subject: [PATCH] Update Positions (#213) * Move unused labmda * Update * Test * Fix * Fix * Fix * Fix * Fix frontend * Fix * Add tests * Fixes * Fix --------- Co-authored-by: Eric Bach --- TODO.md | 12 +- backend/lib/api-stack.ts | 191 ++- backend/src/appsync/Event.publishEvent.ts | 36 + .../appsync/Mutation.createBankTransaction.ts | 38 + .../Mutation.createInvestmentTransaction.ts | 40 + .../appsync/Mutation.deleteBankTransaction.ts | 23 + .../Mutation.deleteInvestmentTransaction.ts | 23 + .../appsync/Mutation.updateBankTransaction.ts | 37 + .../Mutation.updateInvestmentTransaction.ts | 40 + backend/src/appsync/api/codegen/appsync.ts | 24 +- backend/src/appsync/api/types.ts | 5 +- backend/src/appsync/schema.graphql | 12 +- .../lambda/accountsResolver/createAccount.ts | 39 - .../lambda/accountsResolver/deleteAccount.ts | 59 - .../lambda/accountsResolver/getAccounts.ts | 145 -- .../helpers/dynamoDbCommand.ts | 21 - .../accountsResolver/helpers/eventBridge.ts | 33 - backend/src/lambda/accountsResolver/main.ts | 34 - .../lambda/accountsResolver/package-lock.json | 1253 --------------- .../src/lambda/accountsResolver/package.json | 20 - .../src/lambda/accountsResolver/tsconfig.json | 19 - .../lambda/accountsResolver/updateAccount.ts | 43 - .../createBankTransaction.ts | 46 - .../createInvestmentTransaction.ts | 48 - .../transactionsResolver/deleteTransaction.ts | 37 - .../helpers/dynamoDbCommand.ts | 21 - .../helpers/eventBridge.ts | 33 - .../src/lambda/transactionsResolver/main.ts | 46 - .../transactionsResolver/package-lock.json | 1399 ----------------- .../lambda/transactionsResolver/package.json | 22 - .../lambda/transactionsResolver/tsconfig.json | 16 - .../updateBankTransaction.ts | 49 - .../updateInvestmentTransaction.ts | 55 - backend/src/lambda/types/Account.ts | 57 - backend/src/lambda/types/Transaction.ts | 27 - .../src/lambda/updatePositions/package.json | 2 +- .../lambda/updatePositions/yahooFinance.ts | 7 + .../Mutation.createBankTransaction.test..ts | 64 + ...tation.createInvestmentTransaction.test.ts | 68 + .../Mutation.deleteBankTransaction.test.ts | 49 + ...tation.deleteInvestmentTransaction.test.ts | 49 + .../Mutation.updateBankTransaction.test.ts | 63 + ...tation.updateInvestmentTransaction.test.ts | 66 + frontend/src/actions/api/mutations.ts | 15 +- ...nsaction.ts => delete-bank-transaction.ts} | 12 +- .../actions/delete-investment-transaction.ts | 40 + frontend/src/actions/index.ts | 3 +- .../(bank-transactions)/banking-actions.tsx | 97 ++ .../banking-columns.tsx | 2 +- .../investment-actions.tsx} | 19 +- .../investment-columns.tsx | 2 +- frontend/src/components/data-table.tsx | 14 +- .../features/banking-transactions/index.tsx | 2 +- .../investment-transactions/index.tsx | 2 +- 54 files changed, 942 insertions(+), 3637 deletions(-) create mode 100644 backend/src/appsync/Event.publishEvent.ts create mode 100644 backend/src/appsync/Mutation.createBankTransaction.ts create mode 100644 backend/src/appsync/Mutation.createInvestmentTransaction.ts create mode 100644 backend/src/appsync/Mutation.deleteBankTransaction.ts create mode 100644 backend/src/appsync/Mutation.deleteInvestmentTransaction.ts create mode 100644 backend/src/appsync/Mutation.updateBankTransaction.ts create mode 100644 backend/src/appsync/Mutation.updateInvestmentTransaction.ts delete mode 100644 backend/src/lambda/accountsResolver/createAccount.ts delete mode 100644 backend/src/lambda/accountsResolver/deleteAccount.ts delete mode 100644 backend/src/lambda/accountsResolver/getAccounts.ts delete mode 100644 backend/src/lambda/accountsResolver/helpers/dynamoDbCommand.ts delete mode 100644 backend/src/lambda/accountsResolver/helpers/eventBridge.ts delete mode 100644 backend/src/lambda/accountsResolver/main.ts delete mode 100644 backend/src/lambda/accountsResolver/package-lock.json delete mode 100644 backend/src/lambda/accountsResolver/package.json delete mode 100644 backend/src/lambda/accountsResolver/tsconfig.json delete mode 100644 backend/src/lambda/accountsResolver/updateAccount.ts delete mode 100644 backend/src/lambda/transactionsResolver/createBankTransaction.ts delete mode 100644 backend/src/lambda/transactionsResolver/createInvestmentTransaction.ts delete mode 100644 backend/src/lambda/transactionsResolver/deleteTransaction.ts delete mode 100644 backend/src/lambda/transactionsResolver/helpers/dynamoDbCommand.ts delete mode 100644 backend/src/lambda/transactionsResolver/helpers/eventBridge.ts delete mode 100644 backend/src/lambda/transactionsResolver/main.ts delete mode 100644 backend/src/lambda/transactionsResolver/package-lock.json delete mode 100644 backend/src/lambda/transactionsResolver/package.json delete mode 100644 backend/src/lambda/transactionsResolver/tsconfig.json delete mode 100644 backend/src/lambda/transactionsResolver/updateBankTransaction.ts delete mode 100644 backend/src/lambda/transactionsResolver/updateInvestmentTransaction.ts delete mode 100644 backend/src/lambda/types/Account.ts delete mode 100644 backend/src/lambda/types/Transaction.ts create mode 100644 backend/test/appsync/Mutation.createBankTransaction.test..ts create mode 100644 backend/test/appsync/Mutation.createInvestmentTransaction.test.ts create mode 100644 backend/test/appsync/Mutation.deleteBankTransaction.test.ts create mode 100644 backend/test/appsync/Mutation.deleteInvestmentTransaction.test.ts create mode 100644 backend/test/appsync/Mutation.updateBankTransaction.test.ts create mode 100644 backend/test/appsync/Mutation.updateInvestmentTransaction.test.ts rename frontend/src/actions/{delete-transaction.ts => delete-bank-transaction.ts} (60%) create mode 100644 frontend/src/actions/delete-investment-transaction.ts create mode 100644 frontend/src/app/(main)/(bank-transactions)/banking-actions.tsx rename frontend/src/app/(main)/{(transactions) => (bank-transactions)}/banking-columns.tsx (97%) rename frontend/src/app/(main)/{(transactions)/actions.tsx => (investment-transactions)/investment-actions.tsx} (75%) rename frontend/src/app/(main)/{(transactions) => (investment-transactions)}/investment-columns.tsx (95%) diff --git a/TODO.md b/TODO.md index 7ab5edc8..18c0239b 100644 --- a/TODO.md +++ b/TODO.md @@ -39,8 +39,18 @@ X Switch to use ComboBox from budget-tracker tutorial X Switch to sonner X Add tests to validate APIs and workflows X Switch frontend to use NextJS 14 with turbo +X Switch transactionsResolver to use AppSync JS pipeline resolvers -- Ensure positions updates on transactions create/update, add tests to Lambdas +##### Current Task + +- Rearchitect updatePositions/updateBalances to use AppSync JS Resolvers +- Ensure updatePositions updates on investment transactions create/update - FAILING, add tests to Lambdas +- Create updateBalances updates on bank transactions create/update + +##### Future Task + +- create L3 constructs for AppSync CDK +- Update to nodejs 22 - Frontend - remove "Loading..." on screens, remove landing page for login page, improvements to FE - Events diff --git a/backend/lib/api-stack.ts b/backend/lib/api-stack.ts index cdacfc32..0d0b1ede 100644 --- a/backend/lib/api-stack.ts +++ b/backend/lib/api-stack.ts @@ -13,12 +13,12 @@ import { FieldLogLevel, InlineCode, AuthorizationType, - SchemaFile, DynamoDbDataSource, FunctionRuntime, AppsyncFunction, Resolver, Definition, + EventBridgeDataSource, } from 'aws-cdk-lib/aws-appsync'; import { EventBus, Rule } from 'aws-cdk-lib/aws-events'; import { LambdaFunction } from 'aws-cdk-lib/aws-events-targets'; @@ -130,7 +130,7 @@ export class ApiStack extends Stack { name: 'dynamoDBDataSource', serviceRole: new Role(this, `${props.appName}AppSyncServiceRole`, { assumedBy: new ServicePrincipal('appsync.amazonaws.com'), - roleName: `${props.appName}-appsync-service-role-${props.envName}`, + roleName: `${props.appName}-appsync-dynamodb-service-role-${props.envName}`, inlinePolicies: { name: new PolicyDocument({ statements: [ @@ -158,6 +158,29 @@ export class ApiStack extends Stack { }), }); + // AppSync EventBridge DataSource + const eventBridgeDataSource = new EventBridgeDataSource(this, 'EventBridgeDataSource', { + api, + eventBus: eventBus, + description: 'EventBridgeDataSource', + name: 'eventBridgeDataSource', + serviceRole: new Role(this, `${props.appName}AppSyncEventBridgeServiceRole`, { + assumedBy: new ServicePrincipal('appsync.amazonaws.com'), + roleName: `${props.appName}-appsync-event-bridge-service-role-${props.envName}`, + inlinePolicies: { + name: new PolicyDocument({ + statements: [ + new PolicyStatement({ + effect: Effect.ALLOW, + actions: ['events:PutEvents'], + resources: [eventBus.eventBusArn], + }), + ], + }), + }, + }), + }); + // AppSync JS Resolvers const createAccountFunction = new AppsyncFunction(this, 'createAccountFunction', { name: 'createAccount', @@ -271,6 +294,56 @@ export class ApiStack extends Stack { code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Query.getSymbols.js')), runtime: FunctionRuntime.JS_1_0_0, }); + const publishEvent = new AppsyncFunction(this, 'publishEvent', { + name: 'publishEvent', + api: api, + dataSource: eventBridgeDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Event.publishEvent.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); + + const createBankTransaction = new AppsyncFunction(this, 'createBankTransactionFunction', { + name: 'createBankTransaction', + api: api, + dataSource: dynamoDbDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Mutation.createBankTransaction.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); + const updateBankTransaction = new AppsyncFunction(this, 'updateBankTransactionFunction', { + name: 'updateBankTransaction', + api: api, + dataSource: dynamoDbDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Mutation.updateBankTransaction.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); + const deleteBankTransaction = new AppsyncFunction(this, 'deleteBankTransactionFunction', { + name: 'deleteBankTransaction', + api: api, + dataSource: dynamoDbDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Mutation.deleteBankTransaction.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); + const createInvestmentTransaction = new AppsyncFunction(this, 'createInvestmentTransactionFunction', { + name: 'createInvestmentTransaction', + api: api, + dataSource: dynamoDbDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Mutation.createInvestmentTransaction.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); + const updateInvestmentTransaction = new AppsyncFunction(this, 'updateInvestmentTransactionFunction', { + name: 'updateInvestmentTransaction', + api: api, + dataSource: dynamoDbDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Mutation.updateInvestmentTransaction.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); + const deleteInvestmentTransaction = new AppsyncFunction(this, 'deleteInvestmentTransactionFunction', { + name: 'deleteInvestmentTransaction', + api: api, + dataSource: dynamoDbDataSource, + code: Code.fromAsset(path.join(__dirname, '../src/appsync/build/Mutation.deleteInvestmentTransaction.js')), + runtime: FunctionRuntime.JS_1_0_0, + }); const passthrough = InlineCode.fromInline(` // The before step @@ -414,78 +487,66 @@ export class ApiStack extends Stack { pipelineConfig: [getSymbolsFunction], code: passthrough, }); - - /*** - *** AWS AppSync - Lambda Resolvers - ***/ - - // AWS ADOT Lambda layer - const adotLayer = LayerVersion.fromLayerVersionArn( - this, - 'adotLayer', - `arn:aws:lambda:${Stack.of(this).region}:901920570463:layer:aws-otel-nodejs-amd64-ver-1-18-1:4` - ); - - // AppSync Lambda DataSource - const transactionsReolverFunction = new NodejsFunction(this, 'TransactionsResolver', { - functionName: `${props.appName}-${props.envName}-TransactionsResolver`, - runtime: Runtime.NODEJS_20_X, - handler: 'handler', - entry: path.resolve(__dirname, '../src/lambda/transactionsResolver/main.ts'), - memorySize: 512, - timeout: Duration.seconds(10), - tracing: Tracing.ACTIVE, - layers: [adotLayer], - environment: { - DATA_TABLE_NAME: dataTable.tableName, - EVENTBUS_NAME: eventBus.eventBusName, - AWS_LAMBDA_EXEC_WRAPPER: '/opt/otel-handler', - }, - }); - transactionsReolverFunction.addToRolePolicy( - new PolicyStatement({ - effect: Effect.ALLOW, - actions: ['dynamodb:Query', 'dynamodb:PutItem', 'dynamodb:UpdateItem', 'dynamodb:DeleteItem'], - resources: [dataTable.tableArn], - }) - ); - transactionsReolverFunction.addToRolePolicy( - new PolicyStatement({ - effect: Effect.ALLOW, - actions: ['events:PutEvents'], - resources: [eventBus.eventBusArn], - }) - ); - const transactionsResolverDataSource = api.addLambdaDataSource('transactionsDataSource', transactionsReolverFunction, { - name: 'TransactionsLambdaDataSource', - }); - - // Lambda Resolvers - transactionsResolverDataSource.createResolver('createBankTransactionResolver', { + const createBankTransactionResolver = new Resolver(this, 'createBankTransaction', { + api: api, typeName: 'Mutation', fieldName: 'createBankTransaction', + runtime: FunctionRuntime.JS_1_0_0, + pipelineConfig: [createBankTransaction, publishEvent], + code: passthrough, }); - transactionsResolverDataSource.createResolver('updateBankTransactionResolver', { + const updateBankTransactionResolver = new Resolver(this, 'updateBankTransaction', { + api: api, typeName: 'Mutation', fieldName: 'updateBankTransaction', + runtime: FunctionRuntime.JS_1_0_0, + pipelineConfig: [updateBankTransaction, publishEvent], + code: passthrough, }); - transactionsResolverDataSource.createResolver('createInvestmentTransactionResolver', { + const deleteBankTransactionResolver = new Resolver(this, 'deleteBankTransaction', { + api: api, + typeName: 'Mutation', + fieldName: 'deleteBankTransaction', + runtime: FunctionRuntime.JS_1_0_0, + pipelineConfig: [deleteBankTransaction, publishEvent], + code: passthrough, + }); + const createInvestmentTransactionResolver = new Resolver(this, 'createInvestmentTransaction', { + api: api, typeName: 'Mutation', fieldName: 'createInvestmentTransaction', + runtime: FunctionRuntime.JS_1_0_0, + pipelineConfig: [createInvestmentTransaction, publishEvent], + code: passthrough, }); - transactionsResolverDataSource.createResolver('updateInvestmentTransactionResolver', { + const updateInvestmentTransactionResolver = new Resolver(this, 'updateInvestmentTransaction', { + api: api, typeName: 'Mutation', fieldName: 'updateInvestmentTransaction', + runtime: FunctionRuntime.JS_1_0_0, + pipelineConfig: [updateInvestmentTransaction, publishEvent], + code: passthrough, }); - transactionsResolverDataSource.createResolver('deleteTransactionResolver', { + const deleteInvestmentTransactionResolver = new Resolver(this, 'deleteInvestmentTransaction', { + api: api, typeName: 'Mutation', - fieldName: 'deleteTransaction', + fieldName: 'deleteInvestmentTransaction', + runtime: FunctionRuntime.JS_1_0_0, + pipelineConfig: [deleteInvestmentTransaction, publishEvent], + code: passthrough, }); /*** *** AWS Lambda - Event Handlers ***/ + // AWS ADOT Lambda layer + const adotLayer = LayerVersion.fromLayerVersionArn( + this, + 'adotLayer', + `arn:aws:lambda:${Stack.of(this).region}:901920570463:layer:aws-otel-nodejs-amd64-ver-1-18-1:4` + ); + const updatePositionsFunction = new NodejsFunction(this, 'UpdatePositions', { runtime: Runtime.NODEJS_18_X, functionName: `${props.appName}-${props.envName}-UpdatePositions`, @@ -496,6 +557,7 @@ export class ApiStack extends Stack { tracing: Tracing.ACTIVE, layers: [adotLayer], environment: { + REGION: Stack.of(this).region, DATA_TABLE_NAME: dataTable.tableName, EVENTBUS_PECUNIARY_NAME: eventBus.eventBusName, AWS_LAMBDA_EXEC_WRAPPER: '/opt/otel-handler', @@ -538,17 +600,17 @@ export class ApiStack extends Stack { *** AWS EventBridge - Event Bus Rules ***/ - // EventBus Rule - TransactionSavedEventRule - const transactionSavedEventRule = new Rule(this, 'TransactionSavedEventRule', { - ruleName: `${props.appName}-TransactionSavedEvent-${props.envName}`, - description: 'TransactionSavedEvent', + // EventBus Rule - InvestmentTransactionSavedEventRule + const investmentTransactionSavedRule = new Rule(this, 'InvestmentTransactionSavedEventRule', { + ruleName: `${props.appName}-InvestmentTransactionSavedEvent-${props.envName}`, + description: 'InvestmentTransactionSavedEvent', eventBus: eventBus, eventPattern: { source: ['custom.pecuniary'], - detailType: ['TransactionSavedEvent'], + detailType: ['InvestmentTransactionSavedEvent'], }, }); - transactionSavedEventRule.addTarget( + investmentTransactionSavedRule.addTarget( new LambdaFunction(updatePositionsFunction, { //deadLetterQueue: SqsQueue, maxEventAge: Duration.hours(2), @@ -574,14 +636,11 @@ export class ApiStack extends Stack { // EventBridge new CfnOutput(this, 'EventBusArn', { value: eventBus.eventBusArn }); - new CfnOutput(this, 'TransactionSavedEventRuleArn', { - value: transactionSavedEventRule.ruleArn, + new CfnOutput(this, 'InvestmentTransactionSavedRuleArn', { + value: investmentTransactionSavedRule.ruleArn, }); // Lambda functions - new CfnOutput(this, 'TransactionsResolverFunctionArn', { - value: transactionsReolverFunction.functionArn, - }); new CfnOutput(this, 'UpdatePositionsFunctionArn', { value: updatePositionsFunction.functionArn, }); diff --git a/backend/src/appsync/Event.publishEvent.ts b/backend/src/appsync/Event.publishEvent.ts new file mode 100644 index 00000000..f583d423 --- /dev/null +++ b/backend/src/appsync/Event.publishEvent.ts @@ -0,0 +1,36 @@ +import { AppSyncIdentityCognito, Context, util } from '@aws-appsync/utils'; +import { MutationCreateBankTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context) { + console.log('🔔 PublishEvent Request: ', ctx); + + const input = ctx.args.input; + const identity = ctx.identity as AppSyncIdentityCognito; + + const eventDetail = { + ...input, + userId: identity.username, + }; + + return { + operation: 'PutEvents', + events: [ + { + source: 'custom.pecuniary', + detailType: ctx.prev.result.detailType, + detail: eventDetail, + time: util.time.nowISO8601(), + }, + ], + }; +} + +export function response(ctx: Context) { + console.log('🔔 PublishEvent Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return ctx.prev.result; +} diff --git a/backend/src/appsync/Mutation.createBankTransaction.ts b/backend/src/appsync/Mutation.createBankTransaction.ts new file mode 100644 index 00000000..276f073e --- /dev/null +++ b/backend/src/appsync/Mutation.createBankTransaction.ts @@ -0,0 +1,38 @@ +import { AppSyncIdentityCognito, Context, DynamoDBPutItemRequest, util } from '@aws-appsync/utils'; +import { BankTransaction, MutationCreateBankTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context): DynamoDBPutItemRequest { + console.log('🔔 CreateBankTransaction Request: ', ctx); + + const transactionId = util.autoId(); + const datetime = util.time.nowISO8601(); + + return { + operation: 'PutItem', + key: { + pk: util.dynamodb.toDynamoDB(`trans#${transactionId}`), + }, + attributeValues: { + entity: util.dynamodb.toDynamoDB('bank-transaction'), + accountId: util.dynamodb.toDynamoDB(ctx.args.input.accountId), + transactionId: util.dynamodb.toDynamoDB(transactionId), + transactionDate: util.dynamodb.toDynamoDB(ctx.args.input.transactionDate), + payee: util.dynamodb.toDynamoDB(ctx.args.input.payee), + category: util.dynamodb.toDynamoDB(ctx.args.input.category), + amount: util.dynamodb.toDynamoDB(ctx.args.input.amount), + userId: util.dynamodb.toDynamoDB((ctx.identity as AppSyncIdentityCognito).username), + createdAt: util.dynamodb.toDynamoDB(datetime), + updatedAt: util.dynamodb.toDynamoDB(datetime), + }, + }; +} + +export function response(ctx: Context): BankTransaction { + console.log('🔔 CreateBankTransaction Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return { ...ctx.result, detailType: 'BankTransactionSavedEvent' }; +} diff --git a/backend/src/appsync/Mutation.createInvestmentTransaction.ts b/backend/src/appsync/Mutation.createInvestmentTransaction.ts new file mode 100644 index 00000000..b75de30c --- /dev/null +++ b/backend/src/appsync/Mutation.createInvestmentTransaction.ts @@ -0,0 +1,40 @@ +import { AppSyncIdentityCognito, Context, DynamoDBPutItemRequest, util } from '@aws-appsync/utils'; +import { InvestmentTransaction, MutationCreateInvestmentTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context): DynamoDBPutItemRequest { + console.log('🔔 CreateInvestmentTransaction Request: ', ctx); + + const transactionId = util.autoId(); + const datetime = util.time.nowISO8601(); + + return { + operation: 'PutItem', + key: { + pk: util.dynamodb.toDynamoDB(`trans#${transactionId}`), + }, + attributeValues: { + entity: util.dynamodb.toDynamoDB('investment-transaction'), + accountId: util.dynamodb.toDynamoDB(ctx.args.input.accountId), + transactionId: util.dynamodb.toDynamoDB(transactionId), + type: util.dynamodb.toDynamoDB(ctx.args.input.type), + transactionDate: util.dynamodb.toDynamoDB(ctx.args.input.transactionDate), + symbol: util.dynamodb.toDynamoDB(ctx.args.input.symbol), + shares: util.dynamodb.toDynamoDB(ctx.args.input.shares), + price: util.dynamodb.toDynamoDB(ctx.args.input.price), + commission: util.dynamodb.toDynamoDB(ctx.args.input.commission), + userId: util.dynamodb.toDynamoDB((ctx.identity as AppSyncIdentityCognito).username), + createdAt: util.dynamodb.toDynamoDB(datetime), + updatedAt: util.dynamodb.toDynamoDB(datetime), + }, + }; +} + +export function response(ctx: Context): InvestmentTransaction { + console.log('🔔 CreateInvestmentTransaction Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return { ...ctx.result, detailType: 'InvestmentTransactionSavedEvent' }; +} diff --git a/backend/src/appsync/Mutation.deleteBankTransaction.ts b/backend/src/appsync/Mutation.deleteBankTransaction.ts new file mode 100644 index 00000000..14198f07 --- /dev/null +++ b/backend/src/appsync/Mutation.deleteBankTransaction.ts @@ -0,0 +1,23 @@ +import { Context, DynamoDBDeleteItemRequest, util } from '@aws-appsync/utils'; +import { DeleteTransaction, MutationDeleteBankTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context): DynamoDBDeleteItemRequest { + console.log('🔔 DeleteBankTransaction Request: ', ctx); + + return { + operation: 'DeleteItem', + key: { + pk: util.dynamodb.toDynamoDB(ctx.args.input.pk), + }, + }; +} + +export function response(ctx: Context): DeleteTransaction { + console.log('🔔 DeleteBankTransaction Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return { ...ctx.result, detailType: 'BankTransactionSavedEvent' }; +} diff --git a/backend/src/appsync/Mutation.deleteInvestmentTransaction.ts b/backend/src/appsync/Mutation.deleteInvestmentTransaction.ts new file mode 100644 index 00000000..a8e5e8f9 --- /dev/null +++ b/backend/src/appsync/Mutation.deleteInvestmentTransaction.ts @@ -0,0 +1,23 @@ +import { Context, DynamoDBDeleteItemRequest, util } from '@aws-appsync/utils'; +import { DeleteTransaction, MutationDeleteInvestmentTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context): DynamoDBDeleteItemRequest { + console.log('🔔 DeleteInvestmentTransaction Request: ', ctx); + + return { + operation: 'DeleteItem', + key: { + pk: util.dynamodb.toDynamoDB(ctx.args.input.pk), + }, + }; +} + +export function response(ctx: Context): DeleteTransaction { + console.log('🔔 DeleteInvestmentTransaction Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return { ...ctx.result, detailType: 'InvestmentTransactionSavedEvent' }; +} diff --git a/backend/src/appsync/Mutation.updateBankTransaction.ts b/backend/src/appsync/Mutation.updateBankTransaction.ts new file mode 100644 index 00000000..fa938421 --- /dev/null +++ b/backend/src/appsync/Mutation.updateBankTransaction.ts @@ -0,0 +1,37 @@ +import { AppSyncIdentityCognito, Context, DynamoDBUpdateItemRequest, util } from '@aws-appsync/utils'; +import { BankTransaction, MutationUpdateBankTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context): DynamoDBUpdateItemRequest { + console.log('🔔 UpdateBankTransaction Request: ', ctx); + + const updatedAt = util.time.nowISO8601(); + + return { + operation: 'UpdateItem', + key: { + pk: util.dynamodb.toDynamoDB(`trans#${ctx.args.input.transactionId}`), + }, + update: { + expression: 'SET transactionDate=:transactionDate, payee=:payee, category=:category, amount=:amount, updatedAt=:updatedAt', + expressionValues: { + accountId: util.dynamodb.toDynamoDB(ctx.args.input.accountId), + transactionDate: util.dynamodb.toDynamoDB(ctx.args.input.transactionDate), + payee: util.dynamodb.toDynamoDB(ctx.args.input.payee), + category: util.dynamodb.toDynamoDB(ctx.args.input.category), + amount: util.dynamodb.toDynamoDB(ctx.args.input.amount), + userId: util.dynamodb.toDynamoDB((ctx.identity as AppSyncIdentityCognito).username), + updatedAt: util.dynamodb.toDynamoDB(updatedAt), + }, + }, + }; +} + +export function response(ctx: Context): BankTransaction { + console.log('🔔 UpdateBankTransaction Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return { ...ctx.result, detailType: 'BankTransactionSavedEvent' }; +} diff --git a/backend/src/appsync/Mutation.updateInvestmentTransaction.ts b/backend/src/appsync/Mutation.updateInvestmentTransaction.ts new file mode 100644 index 00000000..09dec862 --- /dev/null +++ b/backend/src/appsync/Mutation.updateInvestmentTransaction.ts @@ -0,0 +1,40 @@ +import { AppSyncIdentityCognito, Context, DynamoDBUpdateItemRequest, util } from '@aws-appsync/utils'; +import { InvestmentTransaction, MutationUpdateInvestmentTransactionArgs } from './api/codegen/appsync'; + +export function request(ctx: Context): DynamoDBUpdateItemRequest { + console.log('🔔 UpdateInvestmentTransaction Request: ', ctx); + + const updatedAt = util.time.nowISO8601(); + + return { + operation: 'UpdateItem', + key: { + pk: util.dynamodb.toDynamoDB(`trans#${ctx.args.input.transactionId}`), + }, + update: { + expression: + 'SET #type=:type, transactionDate=:transactionDate, symbol=:symbol, shares=:shares, price=:price, commission=:commission, updatedAt=:updatedAt', + expressionValues: { + accountId: util.dynamodb.toDynamoDB(ctx.args.input.accountId), + type: util.dynamodb.toDynamoDB(ctx.args.input.type), + transactionDate: util.dynamodb.toDynamoDB(ctx.args.input.transactionDate), + symbol: util.dynamodb.toDynamoDB(ctx.args.input.symbol), + shares: util.dynamodb.toDynamoDB(ctx.args.input.shares), + price: util.dynamodb.toDynamoDB(ctx.args.input.price), + commission: util.dynamodb.toDynamoDB(ctx.args.input.commission), + userId: util.dynamodb.toDynamoDB((ctx.identity as AppSyncIdentityCognito).username), + updatedAt: util.dynamodb.toDynamoDB(updatedAt), + }, + }, + }; +} + +export function response(ctx: Context): InvestmentTransaction { + console.log('🔔 UpdateInvestmentTransaction Response: ', ctx); + + if (ctx.error) { + util.error(ctx.error.message, ctx.error.type, ctx.result); + } + + return { ...ctx.result, detailType: 'InvestmentTransactionSavedEvent' }; +} diff --git a/backend/src/appsync/api/codegen/appsync.ts b/backend/src/appsync/api/codegen/appsync.ts index afacba7e..75acda78 100644 --- a/backend/src/appsync/api/codegen/appsync.ts +++ b/backend/src/appsync/api/codegen/appsync.ts @@ -114,15 +114,19 @@ export type Data = { userId: Scalars['String']['output']; }; -export type DeleteResponse = { - __typename?: 'DeleteResponse'; - pk?: Maybe; +export type DeleteBankTransactionInput = { + pk: Scalars['ID']['input']; }; -export type DeleteTransactionInput = { +export type DeleteInvestmentTransactionInput = { pk: Scalars['ID']['input']; }; +export type DeleteTransaction = { + __typename?: 'DeleteTransaction'; + pk?: Maybe; +}; + export type GetAccountsResponse = { __typename?: 'GetAccountsResponse'; items?: Maybe>>; @@ -191,7 +195,8 @@ export type Mutation = { createPayee?: Maybe; createSymbol?: Maybe; deleteAccount?: Maybe; - deleteTransaction?: Maybe; + deleteBankTransaction?: Maybe; + deleteInvestmentTransaction?: Maybe; updateAccount?: Maybe; updateBankTransaction?: Maybe; updateCategory?: Maybe; @@ -235,8 +240,13 @@ export type MutationDeleteAccountArgs = { }; -export type MutationDeleteTransactionArgs = { - input: DeleteTransactionInput; +export type MutationDeleteBankTransactionArgs = { + input: DeleteBankTransactionInput; +}; + + +export type MutationDeleteInvestmentTransactionArgs = { + input: DeleteInvestmentTransactionInput; }; diff --git a/backend/src/appsync/api/types.ts b/backend/src/appsync/api/types.ts index 9d011d65..d080b636 100644 --- a/backend/src/appsync/api/types.ts +++ b/backend/src/appsync/api/types.ts @@ -5,7 +5,7 @@ import { Aggregates, BankTransaction, Category, - DeleteResponse, + DeleteTransaction, GetAccountsResponse, GetBankTransactionsResponse, GetCategoriesResponse, @@ -14,6 +14,7 @@ import { GetSymbolsResponse, InvestmentTransaction, Payee, + Symbol, } from './codegen/appsync'; export type Query = string & { @@ -66,7 +67,7 @@ export type UpdateInvestmentTransactionMutation = { }; export type DeleteTransactionMutation = { - deleteTransaction: DeleteResponse; + deleteTransaction: DeleteTransaction; }; export type CreateCategoryMutation = { diff --git a/backend/src/appsync/schema.graphql b/backend/src/appsync/schema.graphql index 805e6e3d..47903c37 100644 --- a/backend/src/appsync/schema.graphql +++ b/backend/src/appsync/schema.graphql @@ -55,7 +55,7 @@ input UpdateBankTransactionInput { amount: Float! } -input DeleteTransactionInput { +input DeleteBankTransactionInput { pk: ID! } @@ -81,6 +81,10 @@ input UpdateInvestmentTransactionInput { commission: Float! } +input DeleteInvestmentTransactionInput { + pk: ID! +} + # Aggregate Response type Aggregates { items: [Data] @@ -196,7 +200,7 @@ type GetPositionsResponse { nextToken: String } -type DeleteResponse { +type DeleteTransaction { pk: String } @@ -245,11 +249,13 @@ type Mutation { createBankTransaction(input: CreateBankTransactionInput!): BankTransaction @aws_cognito_user_pools(cognito_groups: ["Users"]) updateBankTransaction(input: UpdateBankTransactionInput!): BankTransaction @aws_cognito_user_pools(cognito_groups: ["Users"]) + deleteBankTransaction(input: DeleteBankTransactionInput!): DeleteTransaction @aws_cognito_user_pools(cognito_groups: ["Users"]) createInvestmentTransaction(input: CreateInvestmentTransactionInput!): InvestmentTransaction @aws_cognito_user_pools(cognito_groups: ["Users"]) updateInvestmentTransaction(input: UpdateInvestmentTransactionInput!): InvestmentTransaction @aws_cognito_user_pools(cognito_groups: ["Users"]) - deleteTransaction(input: DeleteTransactionInput!): DeleteResponse @aws_cognito_user_pools(cognito_groups: ["Users"]) + deleteInvestmentTransaction(input: DeleteInvestmentTransactionInput!): DeleteTransaction + @aws_cognito_user_pools(cognito_groups: ["Users"]) } schema { diff --git a/backend/src/lambda/accountsResolver/createAccount.ts b/backend/src/lambda/accountsResolver/createAccount.ts deleted file mode 100644 index 914ef157..00000000 --- a/backend/src/lambda/accountsResolver/createAccount.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { PutItemCommand, PutItemCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall } from '@aws-sdk/util-dynamodb'; -const { v4: uuidv4 } = require('uuid'); - -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import { CreateAccountInput, AccountReadModel } from '../types/Account'; - -async function createAccount(input: CreateAccountInput) { - console.debug(`🕧 Create Account initialized`); - - var item: AccountReadModel = { - userId: input.userId, - sk: 'ACC#' + new Date().toISOString(), - aggregateId: uuidv4(), - entity: 'account', - type: input.type, - name: input.name, - description: input.description, - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }; - - const putItemCommandInput: PutItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Item: marshall(item), - }; - let result = await dynamoDbCommand(new PutItemCommand(putItemCommandInput)); - - if (result.$metadata.httpStatusCode === 200) { - console.log(`✅ Saved Account: ${JSON.stringify({ result: result, item: item })}`); - - return item; - } - - console.error(`🛑 Error saving Account:\n`, result); - return {}; -} - -export default createAccount; diff --git a/backend/src/lambda/accountsResolver/deleteAccount.ts b/backend/src/lambda/accountsResolver/deleteAccount.ts deleted file mode 100644 index 38760e27..00000000 --- a/backend/src/lambda/accountsResolver/deleteAccount.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { QueryCommand, QueryCommandInput, DeleteItemCommand, DeleteItemCommandInput } from '@aws-sdk/client-dynamodb'; - -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import { DeleteAccountInput } from '../types/Account'; - -async function deleteAccount(input: DeleteAccountInput) { - console.debug(`🕧 Delete Account initialized`); - - // Get all aggregates - console.debug(`🕧 Getting all aggregates related to Account ${input.aggregateId}`); - const queryCommandInput: QueryCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - IndexName: 'aggregateId-lsi', - // TODO Handle if more than 100 items - //Limit: 100, - KeyConditionExpression: 'userId = :v1 AND aggregateId = :v2', - ExpressionAttributeValues: { - ':v1': { S: input.userId }, - ':v2': { S: input.aggregateId }, - }, - }; - let result = await dynamoDbCommand(new QueryCommand(queryCommandInput)); - - if (result.$metadata.httpStatusCode === 200 && result.Count > 0) { - var error = false; - - // Delete each aggregate - for (const t of result.Items) { - const deleteItemCommandInput: DeleteItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Key: { - userId: t.userId, - sk: t.sk, - }, - ConditionExpression: 'aggregateId = :v1', - ExpressionAttributeValues: { - ':v1': t.aggregateId, - }, - }; - - let deleteResult = await dynamoDbCommand(new DeleteItemCommand(deleteItemCommandInput)); - - if (!deleteResult || deleteResult.$metadata.httpStatusCode !== 200) { - error = true; - break; - } - } - - if (!error) { - console.log(`✅ Deleted Account: { result: ${result}, item: ${input} }`); - return input; - } - } - - console.log('🛑 Could not delete Account', result); - return {}; -} - -export default deleteAccount; diff --git a/backend/src/lambda/accountsResolver/getAccounts.ts b/backend/src/lambda/accountsResolver/getAccounts.ts deleted file mode 100644 index ff0a5e9e..00000000 --- a/backend/src/lambda/accountsResolver/getAccounts.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { QueryCommand, QueryCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; - -import { LastEvaluatedKey } from '../types/Account'; -import dynamoDbCommand from './helpers/dynamoDbCommand'; - -async function getAccounts(userId: string, aggregateId: string, lastEvaluatedKey: LastEvaluatedKey) { - console.debug(`🕧 Get Accounts Initialized`); - - let queryCommandInput: QueryCommandInput; - if (aggregateId) { - // Get a single account - queryCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Limit: 1, - IndexName: 'aggregateId-lsi', - KeyConditionExpression: 'userId = :v1 AND aggregateId = :v2', - ExpressionAttributeValues: { - ':v1': { S: userId }, - ':v2': { S: aggregateId }, - }, - }; - } else { - queryCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - //TODO TEMP Limit to 10 - Limit: 10, - KeyConditionExpression: 'userId = :v1 AND begins_with(sk, :v2)', - ExpressionAttributeValues: { - ':v1': { S: userId }, - ':v2': { S: 'ACC#' }, - }, - }; - } - lastEvaluatedKey ? (queryCommandInput.ExclusiveStartKey = marshall(lastEvaluatedKey)) : lastEvaluatedKey; - - var result = await dynamoDbCommand(new QueryCommand(queryCommandInput)); - - if (result && result.$metadata.httpStatusCode === 200) { - console.log(`🔔 Found Accounts and Positions: ${JSON.stringify(result)}`); - - // Check for LastEvaluatedKey - var lastEvalKey; - if (result.LastEvaluatedKey) { - let lek = unmarshall(result.LastEvaluatedKey); - lastEvalKey = lek ? lek : ''; - } - - // Unmarshall results - var results: any = []; - for (const item of result.Items) { - console.debug('ℹī¸ Item: ', JSON.stringify(item)); - - var uItem = unmarshall(item); - results.push(uItem); - } - - // Get Accounts - var accounts = results.filter((x: any) => x.entity === 'account'); - console.debug('ℹī¸ Accounts: ', JSON.stringify(accounts)); - - for (const account of accounts) { - account.currencies = []; - - // var positions = results.filter((x: any) => x.entity === 'position' && x.aggregateId === account.aggregateId); - var positions = await getPositions(userId, account.aggregateId); - console.debug('ℹī¸ Positions: ', JSON.stringify(positions)); - - if (positions.length > 0) { - var positionsGrouped = groupByCurrency(positions); - console.log('🔔 Positions Grouped by Currency: ', JSON.stringify(positionsGrouped)); - - // Sum book/marketValue for grouped positions - var currencies: any = []; - var cur: any, pos: any; - for ([cur, pos] of Object.entries(positionsGrouped)) { - console.log('🔔 Currency: ', cur); - console.log('🔔 Positions: ', JSON.stringify(pos)); - - let bookValue = 0; - let marketValue = 0; - pos.forEach((p: any) => { - bookValue += p.bookValue; - marketValue += p.marketValue; - }); - - var currency: any = { currency: cur, bookValue, marketValue }; - console.log('ℹī¸ Currency: ', JSON.stringify(currency)); - currencies.push(currency); - } - - account.currencies = currencies; - } - } - - let res = { items: accounts, lastEvaluatedKey: lastEvalKey }; - console.log(`✅ Found Accounts: ${JSON.stringify(res)}`); - return res; - } - - console.log(`🛑 Could not find any Account`); - return []; -} - -async function getPositions(userId: string, aggregateId: string) { - const queryCommandInput: QueryCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - IndexName: 'aggregateId-lsi', - KeyConditionExpression: 'userId = :v1 AND aggregateId = :v2', - FilterExpression: 'begins_with(sk, :v3)', - ExpressionAttributeValues: { - ':v1': { S: userId }, - ':v2': { S: aggregateId }, - ':v3': { S: 'ACCPOS#' }, - }, - }; - - var result = await dynamoDbCommand(new QueryCommand(queryCommandInput)); - - var results: any = []; - if (result && result.$metadata.httpStatusCode === 200) { - // Unmarshall results - for (const item of result.Items) { - console.debug('ℹī¸ Item: ', JSON.stringify(item)); - - var uItem = unmarshall(item); - - results.push(uItem); - } - } - - return results; -} - -function groupByCurrency(items: any[]) { - var result = items.reduce(function (r: any[], a: any) { - r[a.currency] = r[a.currency] || []; - r[a.currency].push(a); - return r; - }, Object.create(null)); - - return result; -} - -export default getAccounts; diff --git a/backend/src/lambda/accountsResolver/helpers/dynamoDbCommand.ts b/backend/src/lambda/accountsResolver/helpers/dynamoDbCommand.ts deleted file mode 100644 index 60762750..00000000 --- a/backend/src/lambda/accountsResolver/helpers/dynamoDbCommand.ts +++ /dev/null @@ -1,21 +0,0 @@ -const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); - -async function dynamoDbCommand(command: any) { - var result; - - try { - console.debug(`ℹī¸ Initializing DynamoDB client in ${process.env.REGION}`); - var client = new DynamoDBClient({ region: process.env.REGION }); - - console.debug(`ℹī¸ Executing DynamoDB command:\n${JSON.stringify(command)}`); - result = await client.send(command); - - console.log(`🔔 DynamoDB result:\n${JSON.stringify(result)}`); - } catch (error) { - console.error(`🛑 Error with DynamoDB command:\n`, error); - } - - return result; -} - -export default dynamoDbCommand; diff --git a/backend/src/lambda/accountsResolver/helpers/eventBridge.ts b/backend/src/lambda/accountsResolver/helpers/eventBridge.ts deleted file mode 100644 index 6ed0f703..00000000 --- a/backend/src/lambda/accountsResolver/helpers/eventBridge.ts +++ /dev/null @@ -1,33 +0,0 @@ -const { EventBridgeClient, PutEventsCommand } = require('@aws-sdk/client-eventbridge'); - -async function publishEventAsync(detailType: string, input: any) { - var params = { - Entries: [ - { - Source: 'custom.pecuniary', - EventBusName: process.env.EVENTBUS_PECUNIARY_NAME, - DetailType: detailType, - Detail: JSON.stringify(input), - }, - ], - }; - - var result; - try { - console.debug(`🕧 Initializing EventBridge client in ${process.env.REGION}`); - const client = new EventBridgeClient({ region: process.env.REGION }); - - console.debug(`🕧 Sending ${JSON.stringify(params)} event to EventBridge`); - var command = new PutEventsCommand(params); - - result = await client.send(command); - console.log(`🔔 EventBridge result:\n${JSON.stringify(result)}`); - } catch (error) { - console.error(`🛑 Error sending EventBridge event`, error); - return; - } - - console.log(`✅ Sent ${params.Entries.length} event(s) to EventBridge`); -} - -export default publishEventAsync; diff --git a/backend/src/lambda/accountsResolver/main.ts b/backend/src/lambda/accountsResolver/main.ts deleted file mode 100644 index 977855e7..00000000 --- a/backend/src/lambda/accountsResolver/main.ts +++ /dev/null @@ -1,34 +0,0 @@ -import getAccounts from './getAccounts'; -import createAccount from './createAccount'; -import updateAccount from './updateAccount'; -import deleteAccount from './deleteAccount'; - -import { AccountAppSyncEvent } from '../types/Account'; - -exports.handler = async (event: AccountAppSyncEvent) => { - console.debug(`🕧 AppSync event: ${JSON.stringify(event)}`); - console.debug(`🕧 AppSync info: ${JSON.stringify(event.info)}`); - console.debug(`🕧 AppSync arguments: ${JSON.stringify(event.arguments)}`); - - switch (event.info.fieldName) { - // Queries - case 'getAccounts': - console.debug(`🔔 GetAccounts: ${JSON.stringify(event.arguments.userId)}`); - return await getAccounts(event.arguments.userId, event.arguments.aggregateId, event.arguments.lastEvaluatedKey); - - // Mutations - case 'createAccount': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.createAccountInput)}`); - return await createAccount(event.arguments.createAccountInput); - case 'updateAccount': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.updateAccountInput)}`); - return await updateAccount(event.arguments.updateAccountInput); - case 'deleteAccount': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.deleteAccountInput)}`); - return await deleteAccount(event.arguments.deleteAccountInput); - - default: - console.error(`🛑 No AppSync resolver defined for ${event.info.fieldName}`); - return null; - } -}; diff --git a/backend/src/lambda/accountsResolver/package-lock.json b/backend/src/lambda/accountsResolver/package-lock.json deleted file mode 100644 index 5069e732..00000000 --- a/backend/src/lambda/accountsResolver/package-lock.json +++ /dev/null @@ -1,1253 +0,0 @@ -{ - "name": "accounts-resolver", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "accounts-resolver", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.577.0", - "@aws-sdk/util-dynamodb": "^3.577.0", - "uuid": "^9.0.1" - }, - "devDependencies": { - "@types/node": "^20.12.12" - } - }, - "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.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.577.0.tgz", - "integrity": "sha512-jR+rhYz25aPcMQgQy9tyQS9bsZ2bUKf7gaJ89jvhrrt61dcvw2iXzoO++2SCJWTx8WE1nsT6Vcw70RYpc5y71g==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.577.0", - "@aws-sdk/client-sts": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-endpoint-discovery": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.577.0.tgz", - "integrity": "sha512-BwujdXrydlk6UEyPmewm5GqG4nkQ6OVyRhS/SyZP/6UKSFv2/sf391Cmz0hN0itUTH1rR4XeLln8XCOtarkrzg==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.577.0.tgz", - "integrity": "sha512-njmKSPDWueWWYVFpFcZ2P3fI6/pdQVDa0FgCyYZhOnJLgEHZIcBBg1AsnkVWacBuLopp9XVt2m+7hO6ugY1/1g==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.577.0.tgz", - "integrity": "sha512-509Kklimva1XVlhGbpTpeX3kOP6ORpm44twJxDHpa9TURbmoaxj7veWlnLCbDorxDTrbsDghvYZshvcLsojVpg==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.576.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.576.0.tgz", - "integrity": "sha512-KDvDlbeipSTIf+ffKtTg1m419TK7s9mZSWC8bvuZ9qx6/sjQFOXIKOVqyuli6DnfxGbvRcwoRuY99OcCH1N/0w==", - "dependencies": { - "@smithy/core": "^2.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/signature-v4": "^3.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "fast-xml-parser": "4.2.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.577.0.tgz", - "integrity": "sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.577.0.tgz", - "integrity": "sha512-n++yhCp67b9+ZRGEdY1jhamB5E/O+QsIDOPSuRmdaSGMCOd82oUEKPgIVEU1bkqxDsBxgiEWuvtfhK6sNiDS0A==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.577.0.tgz", - "integrity": "sha512-q7lHPtv6BjRvChUE3m0tIaEZKxPTaZ1B3lKxGYsFl3VLAu5N8yGCUKwuA1izf4ucT+LyKscVGqK6VDZx1ev3nw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.577.0", - "@aws-sdk/credential-provider-process": "3.577.0", - "@aws-sdk/credential-provider-sso": "3.577.0", - "@aws-sdk/credential-provider-web-identity": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.577.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.577.0.tgz", - "integrity": "sha512-epZ1HOMsrXBNczc0HQpv0VMjqAEpc09DUA7Rg3gUJfn8umhML7A7bXnUyqPA+S54q397UYg1leQKdSn23OiwQQ==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.577.0", - "@aws-sdk/credential-provider-http": "3.577.0", - "@aws-sdk/credential-provider-ini": "3.577.0", - "@aws-sdk/credential-provider-process": "3.577.0", - "@aws-sdk/credential-provider-sso": "3.577.0", - "@aws-sdk/credential-provider-web-identity": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.577.0.tgz", - "integrity": "sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.577.0.tgz", - "integrity": "sha512-iVm5SQvS7EgZTJsRaqUOmDQpBQPPPat42SCbWFvFQOLrl8qewq8OP94hFS5w2mP62zngeYzqhJnDel79HXbxew==", - "dependencies": { - "@aws-sdk/client-sso": "3.577.0", - "@aws-sdk/token-providers": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.577.0.tgz", - "integrity": "sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.577.0" - } - }, - "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.572.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.572.0.tgz", - "integrity": "sha512-CzuRWMj/xtN9p9eP915nlPmlyniTzke732Ow/M60++gGgB3W+RtZyFftw3TEx+NzNhd1tH54dEcGiWdiNaBz3Q==", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.577.0.tgz", - "integrity": "sha512-duLI1awiBV7xyi+SQQnFy0J2s9Fhk5miHR5LsyEpk4p4M1Zi9hbBMg3wOdoxGCnNGn56PcP70isD79BfrbWwlA==", - "dependencies": { - "@aws-sdk/endpoint-cache": "3.572.0", - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.577.0.tgz", - "integrity": "sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.577.0.tgz", - "integrity": "sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.577.0.tgz", - "integrity": "sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.577.0.tgz", - "integrity": "sha512-P55HAXgwmiHHpFx5JEPvOnAbfhN7v6sWv9PBQs+z2tC7QiBcPS0cdJR6PfV7J1n4VPK52/OnrK3l9VxdQ7Ms0g==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.577.0.tgz", - "integrity": "sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.577.0.tgz", - "integrity": "sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.577.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.577.0.tgz", - "integrity": "sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.577.0.tgz", - "integrity": "sha512-GGzUZ1saDcP052jFpZ6HfukMwBM2Jtxq1H0fzfWV1YPLikjNJaXt8j/Eng2cNNH0RUdTkPGVAF+mlHjNirosKA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.577.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.577.0.tgz", - "integrity": "sha512-FjuUz1Kdy4Zly2q/c58tpdqHd6z7iOdU/caYzoc8jwgAHBDBbIJNQLCU9hXJnPV2M8pWxQDyIZsoVwtmvErPzw==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", - "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.577.0.tgz", - "integrity": "sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.577.0.tgz", - "integrity": "sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.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": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.0.tgz", - "integrity": "sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.0.1.tgz", - "integrity": "sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.1", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.0.0.tgz", - "integrity": "sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.1.tgz", - "integrity": "sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==", - "dependencies": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/hash-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.0.tgz", - "integrity": "sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==", - "dependencies": { - "@smithy/types": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.0.tgz", - "integrity": "sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.0.tgz", - "integrity": "sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==", - "dependencies": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.0.tgz", - "integrity": "sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==", - "dependencies": { - "@smithy/middleware-serde": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.1.tgz", - "integrity": "sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/service-error-classification": "^3.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.0.tgz", - "integrity": "sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.0.tgz", - "integrity": "sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.0.0.tgz", - "integrity": "sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==", - "dependencies": { - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.0.tgz", - "integrity": "sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==", - "dependencies": { - "@smithy/abort-controller": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.0.0.tgz", - "integrity": "sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.0.tgz", - "integrity": "sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.0.tgz", - "integrity": "sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==", - "dependencies": { - "@smithy/types": "^3.0.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.0.tgz", - "integrity": "sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.0.tgz", - "integrity": "sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==", - "dependencies": { - "@smithy/types": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.0.0.tgz", - "integrity": "sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.0.0.tgz", - "integrity": "sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.0.1.tgz", - "integrity": "sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz", - "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.0.tgz", - "integrity": "sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==", - "dependencies": { - "@smithy/querystring-parser": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.1.tgz", - "integrity": "sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==", - "dependencies": { - "@smithy/property-provider": "^3.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.1.tgz", - "integrity": "sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==", - "dependencies": { - "@smithy/config-resolver": "^3.0.0", - "@smithy/credential-provider-imds": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.0.tgz", - "integrity": "sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.0.tgz", - "integrity": "sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.0.tgz", - "integrity": "sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==", - "dependencies": { - "@smithy/service-error-classification": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.1.tgz", - "integrity": "sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==", - "dependencies": { - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.0.0.tgz", - "integrity": "sha512-+fEXJxGDLCoqRKVSmo0auGxaqbiCo+8oph+4auefYjaNxjOLKSY2MxVQfRzo65PaZv4fr+5lWg+au7vSuJJ/zw==", - "dependencies": { - "@smithy/abort-controller": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "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/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/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - } - } -} diff --git a/backend/src/lambda/accountsResolver/package.json b/backend/src/lambda/accountsResolver/package.json deleted file mode 100644 index 3f7a4688..00000000 --- a/backend/src/lambda/accountsResolver/package.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "accounts-resolver", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "tsc", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.577.0", - "@aws-sdk/util-dynamodb": "^3.577.0", - "uuid": "^9.0.1" - }, - "devDependencies": { - "@types/node": "^20.12.12" - } -} diff --git a/backend/src/lambda/accountsResolver/tsconfig.json b/backend/src/lambda/accountsResolver/tsconfig.json deleted file mode 100644 index ef0d2bd3..00000000 --- a/backend/src/lambda/accountsResolver/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "strict": true, - "preserveConstEnums": true, - "noEmit": true, - "sourceMap": false, - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "isolatedModules": true - }, - "ts-node": { - "swc": true - }, - "exclude": ["node_modules", "**/*.test.ts"] -} diff --git a/backend/src/lambda/accountsResolver/updateAccount.ts b/backend/src/lambda/accountsResolver/updateAccount.ts deleted file mode 100644 index bc7b4826..00000000 --- a/backend/src/lambda/accountsResolver/updateAccount.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { UpdateItemCommand, UpdateItemCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall, unmarshall } from '@aws-sdk/util-dynamodb'; - -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import { UpdateAccountInput } from '../types/Account'; - -async function updateAccount(input: UpdateAccountInput) { - console.debug(`🕧 Update Account initialized`); - - const updateItemCommandInput: UpdateItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Key: marshall({ - userId: input.userId, - sk: input.sk, - }), - UpdateExpression: 'SET #type=:type, #name=:name, description=:description, updatedAt=:updatedAt', - ExpressionAttributeValues: marshall({ - ':type': input.type, - ':name': input.name, - ':description': input.description, - ':updatedAt': new Date().toISOString(), - }), - ExpressionAttributeNames: { - '#type': 'type', - '#name': 'name', - }, - ReturnValues: 'ALL_NEW', - }; - - var updateResult = await dynamoDbCommand(new UpdateItemCommand(updateItemCommandInput)); - - if (updateResult.$metadata.httpStatusCode === 200) { - console.log( - `✅ Updated Account: {result: ${JSON.stringify(updateResult)}, items: ${JSON.stringify(unmarshall(updateResult.Attributes))}}` - ); - return unmarshall(updateResult.Attributes); - } - - console.log(`🛑 Could not update Account`); - return {}; -} - -export default updateAccount; diff --git a/backend/src/lambda/transactionsResolver/createBankTransaction.ts b/backend/src/lambda/transactionsResolver/createBankTransaction.ts deleted file mode 100644 index dad9779d..00000000 --- a/backend/src/lambda/transactionsResolver/createBankTransaction.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { PutItemCommand, PutItemCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall } from '@aws-sdk/util-dynamodb'; -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import publishEventAsync from './helpers/eventBridge'; -import { BankTransaction, CreateBankTransactionInput } from '../../appsync/api/codegen/appsync'; -import { v4 as uuidv4 } from 'uuid'; - -async function createBankTransaction(userId: string, input: CreateBankTransactionInput) { - console.debug(`🕧 Create Bank Transaction initialized`); - - const transactionId = uuidv4(); - const datetime = new Date().toISOString(); - - const item: BankTransaction = { - pk: `trans#${transactionId}`, - entity: 'bank-transaction', - accountId: input.accountId, - transactionId: transactionId, - transactionDate: input.transactionDate, - payee: input.payee, - category: input.category, - amount: input.amount, - userId: userId, - createdAt: datetime, - updatedAt: datetime, - }; - - const putItemCommandInput: PutItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Item: marshall(item), - }; - const result = await dynamoDbCommand(new PutItemCommand(putItemCommandInput)); - - if (result.$metadata.httpStatusCode === 200) { - // Publish event to update positions - await publishEventAsync('TransactionSavedEvent', { ...input, userId: userId }); - - console.log(`✅ Saved Transaction: ${JSON.stringify({ result: result, item: item })}`); - return item; - } - - console.error(`🛑 Error saving bank transaction:\n`, result); - return {}; -} - -export default createBankTransaction; diff --git a/backend/src/lambda/transactionsResolver/createInvestmentTransaction.ts b/backend/src/lambda/transactionsResolver/createInvestmentTransaction.ts deleted file mode 100644 index 35d6a189..00000000 --- a/backend/src/lambda/transactionsResolver/createInvestmentTransaction.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { PutItemCommand, PutItemCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall } from '@aws-sdk/util-dynamodb'; -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import publishEventAsync from './helpers/eventBridge'; -import { CreateInvestmentTransactionInput, InvestmentTransaction } from '../../appsync/api/codegen/appsync'; -import { v4 as uuidv4 } from 'uuid'; - -async function createTransaction(userId: string, input: CreateInvestmentTransactionInput) { - console.debug(`🕧 Create Investment Transaction initialized`); - - const transactionId = uuidv4(); - const datetime = new Date().toISOString(); - - const item: InvestmentTransaction = { - pk: `trans#${transactionId}`, - entity: 'investment-transaction', - accountId: input.accountId, - transactionId: transactionId, - type: input.type, - transactionDate: input.transactionDate, - symbol: input.symbol, - shares: input.shares, - price: input.price, - commission: input.commission, - userId: userId, - createdAt: datetime, - updatedAt: datetime, - }; - - const putItemCommandInput: PutItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Item: marshall(item), - }; - const result = await dynamoDbCommand(new PutItemCommand(putItemCommandInput)); - - if (result.$metadata.httpStatusCode === 200) { - // Publish event to update positions - await publishEventAsync('TransactionSavedEvent', { ...input, userId: userId }); - - console.log(`✅ Saved Transaction: ${JSON.stringify({ result: result, item: item })}`); - return item; - } - - console.error(`🛑 Error saving investment transaction:\n`, result); - return {}; -} - -export default createTransaction; diff --git a/backend/src/lambda/transactionsResolver/deleteTransaction.ts b/backend/src/lambda/transactionsResolver/deleteTransaction.ts deleted file mode 100644 index b73f5336..00000000 --- a/backend/src/lambda/transactionsResolver/deleteTransaction.ts +++ /dev/null @@ -1,37 +0,0 @@ -const { DeleteItemCommand } = require('@aws-sdk/client-dynamodb'); -const { marshall } = require('@aws-sdk/util-dynamodb'); - -import { DeleteTransactionInput } from '../../appsync/api/codegen/appsync'; -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import publishEventAsync from './helpers/eventBridge'; -import { DeleteItemCommandInput } from '@aws-sdk/client-dynamodb'; - -async function deleteTransaction(input: DeleteTransactionInput) { - console.debug(`🕧 Delete Transaction initialized`); - - // Delete Transaction - const deleteItemCommandInput: DeleteItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Key: marshall({ - pk: input.pk, - }), - // ConditionExpression: 'symbol = :v1', - // ExpressionAttributeValues: { - // ':v1': { S: input.symbol }, - // }, - }; - let result = await dynamoDbCommand(new DeleteItemCommand(deleteItemCommandInput)); - - if (result.$metadata.httpStatusCode === 200) { - // Publish event to update positions - await publishEventAsync('TransactionSavedEvent', input.pk); - - console.log(`✅ Deleted Transaction: { result: ${result}, item: ${input} }`); - return input; - } - - console.log('🛑 Could not delete Transaction', result); - return {}; -} - -export default deleteTransaction; diff --git a/backend/src/lambda/transactionsResolver/helpers/dynamoDbCommand.ts b/backend/src/lambda/transactionsResolver/helpers/dynamoDbCommand.ts deleted file mode 100644 index b6ba8e9d..00000000 --- a/backend/src/lambda/transactionsResolver/helpers/dynamoDbCommand.ts +++ /dev/null @@ -1,21 +0,0 @@ -const { DynamoDBClient } = require('@aws-sdk/client-dynamodb'); - -async function dynamoDbCommand(command: any) { - var result; - - try { - console.debug('ℹī¸ Initializing DynamoDB client'); - var client = new DynamoDBClient(); - - console.debug(`ℹī¸ Executing DynamoDB command:\n${JSON.stringify(command)}`); - result = await client.send(command); - - console.log(`🔔 DynamoDB result:\n${JSON.stringify(result)}`); - } catch (error) { - console.error(`🛑 Error with DynamoDB command:\n`, error); - } - - return result; -} - -export default dynamoDbCommand; diff --git a/backend/src/lambda/transactionsResolver/helpers/eventBridge.ts b/backend/src/lambda/transactionsResolver/helpers/eventBridge.ts deleted file mode 100644 index ce7b8038..00000000 --- a/backend/src/lambda/transactionsResolver/helpers/eventBridge.ts +++ /dev/null @@ -1,33 +0,0 @@ -const { EventBridgeClient, PutEventsCommand } = require('@aws-sdk/client-eventbridge'); - -async function publishEventAsync(detailType: string, input: any) { - var params = { - Entries: [ - { - Source: 'custom.pecuniary', - EventBusName: process.env.EVENTBUS_NAME, - DetailType: detailType, - Detail: JSON.stringify(input), - }, - ], - }; - - var result; - try { - console.debug(`🕧 Initializing EventBridge client in ${process.env.REGION}`); - const client = new EventBridgeClient({ region: process.env.REGION }); - - console.debug(`🕧 Sending ${JSON.stringify(params)} event to EventBridge`); - var command = new PutEventsCommand(params); - - result = await client.send(command); - console.log(`🔔 EventBridge result:\n${JSON.stringify(result)}`); - } catch (error) { - console.error(`🛑 Error sending EventBridge event`, error); - return; - } - - console.log(`✅ Sent ${params.Entries.length} event(s) to EventBridge`); -} - -export default publishEventAsync; diff --git a/backend/src/lambda/transactionsResolver/main.ts b/backend/src/lambda/transactionsResolver/main.ts deleted file mode 100644 index fe44ac48..00000000 --- a/backend/src/lambda/transactionsResolver/main.ts +++ /dev/null @@ -1,46 +0,0 @@ -import createBankTransaction from './createBankTransaction'; -import createInvestmentTransaction from './createInvestmentTransaction'; -import updateBankTransaction from './updateBankTransaction'; -import updateInvestmentTransaction from './updateInvestmentTransaction'; -import deleteTransaction from './deleteTransaction'; - -import { TransactionAppSyncEvent } from '../types/Transaction'; -import { - CreateBankTransactionInput, - CreateInvestmentTransactionInput, - DeleteTransactionInput, - UpdateBankTransactionInput, - UpdateInvestmentTransactionInput, -} from '../../appsync/api/codegen/appsync'; - -exports.handler = async (event: TransactionAppSyncEvent) => { - console.debug(`🕧 AppSync event: ${JSON.stringify(event)}`); - console.debug(`🕧 AppSync info: ${JSON.stringify(event.info)}`); - console.debug(`🕧 AppSync arguments: ${JSON.stringify(event.arguments)}`); - - switch (event.info.fieldName) { - case 'createBankTransaction': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.input)}`); - return await createBankTransaction(event.identity.username, event.arguments.input as CreateBankTransactionInput); - - case 'updateBankTransaction': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.input)}`); - return await updateBankTransaction(event.identity.username, event.arguments.input as UpdateBankTransactionInput); - - case 'createInvestmentTransaction': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.input)}`); - return await createInvestmentTransaction(event.identity.username, event.arguments.input as CreateInvestmentTransactionInput); - - case 'updateInvestmentTransaction': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.input)}`); - return await updateInvestmentTransaction(event.identity.username, event.arguments.input as UpdateInvestmentTransactionInput); - - case 'deleteTransaction': - console.debug(`🔔 ${event.info.fieldName} GraphQL data: ${JSON.stringify(event.arguments.input)}`); - return await deleteTransaction(event.arguments.input as DeleteTransactionInput); - - default: - console.error(`🛑 No AppSync resolver defined for ${event.info.fieldName}`); - return null; - } -}; diff --git a/backend/src/lambda/transactionsResolver/package-lock.json b/backend/src/lambda/transactionsResolver/package-lock.json deleted file mode 100644 index cfead7e3..00000000 --- a/backend/src/lambda/transactionsResolver/package-lock.json +++ /dev/null @@ -1,1399 +0,0 @@ -{ - "name": "transactions-resolver", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "transactions-resolver", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.577.0", - "@aws-sdk/client-eventbridge": "^3.577.0", - "@aws-sdk/util-dynamodb": "^3.577.0", - "uuid": "^10.0.0" - }, - "devDependencies": { - "@types/node": "^20.12.12", - "@types/uuid": "^10.0.0" - } - }, - "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.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.577.0.tgz", - "integrity": "sha512-jR+rhYz25aPcMQgQy9tyQS9bsZ2bUKf7gaJ89jvhrrt61dcvw2iXzoO++2SCJWTx8WE1nsT6Vcw70RYpc5y71g==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.577.0", - "@aws-sdk/client-sts": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-endpoint-discovery": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "@smithy/util-waiter": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-dynamodb/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@aws-sdk/client-eventbridge": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-eventbridge/-/client-eventbridge-3.577.0.tgz", - "integrity": "sha512-oIE41KzxHX5TE6m3nBq3/wo1nzYPF7FZCYgDLgoShfNbxPr3jS7UU0ciWLyt0Nl3HXtN8J/+yyqHTTc0NffJ8Q==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.577.0", - "@aws-sdk/client-sts": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-signing": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/signature-v4-multi-region": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.577.0.tgz", - "integrity": "sha512-BwujdXrydlk6UEyPmewm5GqG4nkQ6OVyRhS/SyZP/6UKSFv2/sf391Cmz0hN0itUTH1rR4XeLln8XCOtarkrzg==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sso-oidc": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.577.0.tgz", - "integrity": "sha512-njmKSPDWueWWYVFpFcZ2P3fI6/pdQVDa0FgCyYZhOnJLgEHZIcBBg1AsnkVWacBuLopp9XVt2m+7hO6ugY1/1g==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sts": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/client-sts": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.577.0.tgz", - "integrity": "sha512-509Kklimva1XVlhGbpTpeX3kOP6ORpm44twJxDHpa9TURbmoaxj7veWlnLCbDorxDTrbsDghvYZshvcLsojVpg==", - "dependencies": { - "@aws-crypto/sha256-browser": "3.0.0", - "@aws-crypto/sha256-js": "3.0.0", - "@aws-sdk/client-sso-oidc": "3.577.0", - "@aws-sdk/core": "3.576.0", - "@aws-sdk/credential-provider-node": "3.577.0", - "@aws-sdk/middleware-host-header": "3.577.0", - "@aws-sdk/middleware-logger": "3.577.0", - "@aws-sdk/middleware-recursion-detection": "3.577.0", - "@aws-sdk/middleware-user-agent": "3.577.0", - "@aws-sdk/region-config-resolver": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@aws-sdk/util-user-agent-browser": "3.577.0", - "@aws-sdk/util-user-agent-node": "3.577.0", - "@smithy/config-resolver": "^3.0.0", - "@smithy/core": "^2.0.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/hash-node": "^3.0.0", - "@smithy/invalid-dependency": "^3.0.0", - "@smithy/middleware-content-length": "^3.0.0", - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.0", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-body-length-browser": "^3.0.0", - "@smithy/util-body-length-node": "^3.0.0", - "@smithy/util-defaults-mode-browser": "^3.0.0", - "@smithy/util-defaults-mode-node": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.576.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.576.0.tgz", - "integrity": "sha512-KDvDlbeipSTIf+ffKtTg1m419TK7s9mZSWC8bvuZ9qx6/sjQFOXIKOVqyuli6DnfxGbvRcwoRuY99OcCH1N/0w==", - "dependencies": { - "@smithy/core": "^2.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/signature-v4": "^3.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "fast-xml-parser": "4.2.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.577.0.tgz", - "integrity": "sha512-Jxu255j0gToMGEiqufP8ZtKI8HW90lOLjwJ3LrdlD/NLsAY0tOQf1fWc53u28hWmmNGMxmCrL2p66IOgMDhDUw==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.577.0.tgz", - "integrity": "sha512-n++yhCp67b9+ZRGEdY1jhamB5E/O+QsIDOPSuRmdaSGMCOd82oUEKPgIVEU1bkqxDsBxgiEWuvtfhK6sNiDS0A==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/fetch-http-handler": "^3.0.0", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.577.0.tgz", - "integrity": "sha512-q7lHPtv6BjRvChUE3m0tIaEZKxPTaZ1B3lKxGYsFl3VLAu5N8yGCUKwuA1izf4ucT+LyKscVGqK6VDZx1ev3nw==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.577.0", - "@aws-sdk/credential-provider-process": "3.577.0", - "@aws-sdk/credential-provider-sso": "3.577.0", - "@aws-sdk/credential-provider-web-identity": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.577.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.577.0.tgz", - "integrity": "sha512-epZ1HOMsrXBNczc0HQpv0VMjqAEpc09DUA7Rg3gUJfn8umhML7A7bXnUyqPA+S54q397UYg1leQKdSn23OiwQQ==", - "dependencies": { - "@aws-sdk/credential-provider-env": "3.577.0", - "@aws-sdk/credential-provider-http": "3.577.0", - "@aws-sdk/credential-provider-ini": "3.577.0", - "@aws-sdk/credential-provider-process": "3.577.0", - "@aws-sdk/credential-provider-sso": "3.577.0", - "@aws-sdk/credential-provider-web-identity": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/credential-provider-imds": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.577.0.tgz", - "integrity": "sha512-Gin6BWtOiXxIgITrJ3Nwc+Y2P1uVT6huYR4EcbA/DJUPWyO0n9y5UFLewPvVbLkRn15JeEqErBLUrHclkiOKtw==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.577.0.tgz", - "integrity": "sha512-iVm5SQvS7EgZTJsRaqUOmDQpBQPPPat42SCbWFvFQOLrl8qewq8OP94hFS5w2mP62zngeYzqhJnDel79HXbxew==", - "dependencies": { - "@aws-sdk/client-sso": "3.577.0", - "@aws-sdk/token-providers": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.577.0.tgz", - "integrity": "sha512-ZGHGNRaCtJJmszb9UTnC7izNCtRUttdPlLdMkh41KPS32vfdrBDHs1JrpbZijItRj1xKuOXsiYSXLAaHGcLh8Q==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sts": "^3.577.0" - } - }, - "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.572.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.572.0.tgz", - "integrity": "sha512-CzuRWMj/xtN9p9eP915nlPmlyniTzke732Ow/M60++gGgB3W+RtZyFftw3TEx+NzNhd1tH54dEcGiWdiNaBz3Q==", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.577.0.tgz", - "integrity": "sha512-duLI1awiBV7xyi+SQQnFy0J2s9Fhk5miHR5LsyEpk4p4M1Zi9hbBMg3wOdoxGCnNGn56PcP70isD79BfrbWwlA==", - "dependencies": { - "@aws-sdk/endpoint-cache": "3.572.0", - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-host-header": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.577.0.tgz", - "integrity": "sha512-9ca5MJz455CODIVXs0/sWmJm7t3QO4EUa1zf8pE8grLpzf0J94bz/skDWm37Pli13T3WaAQBHCTiH2gUVfCsWg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-logger": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.577.0.tgz", - "integrity": "sha512-aPFGpGjTZcJYk+24bg7jT4XdIp42mFXSuPt49lw5KygefLyJM/sB0bKKqPYYivW0rcuZ9brQ58eZUNthrzYAvg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.577.0.tgz", - "integrity": "sha512-pn3ZVEd2iobKJlR3H+bDilHjgRnNrQ6HMmK9ZzZw89Ckn3Dcbv48xOv4RJvu0aU8SDLl/SNCxppKjeLDTPGBNA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-sdk-s3": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.577.0.tgz", - "integrity": "sha512-/t8Shvy6lGIRdTEKG6hA8xy+oon/CDF5H8Ksms/cd/uvIy/MYbNjOJ/Arwk8H5W6LB4DP/1O+tOzOpGx1MCufA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-arn-parser": "3.568.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/signature-v4": "^3.0.0", - "@smithy/smithy-client": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-config-provider": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-signing": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.577.0.tgz", - "integrity": "sha512-QS/dh3+NqZbXtY0j/DZ867ogP413pG5cFGqBy9OeOhDMsolcwLrQbi0S0c621dc1QNq+er9ffaMhZ/aPkyXXIg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/signature-v4": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.577.0.tgz", - "integrity": "sha512-P55HAXgwmiHHpFx5JEPvOnAbfhN7v6sWv9PBQs+z2tC7QiBcPS0cdJR6PfV7J1n4VPK52/OnrK3l9VxdQ7Ms0g==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@aws-sdk/util-endpoints": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/region-config-resolver": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.577.0.tgz", - "integrity": "sha512-4ChCFACNwzqx/xjg3zgFcW8Ali6R9C95cFECKWT/7CUM1D0MGvkclSH2cLarmHCmJgU6onKkJroFtWp0kHhgyg==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.577.0.tgz", - "integrity": "sha512-mMykGRFBYmlDcMhdbhNM0z1JFUaYYZ8r9WV7Dd0T2PWELv2brSAjDAOBHdJLHObDMYRnM6H0/Y974qTl3icEcQ==", - "dependencies": { - "@aws-sdk/middleware-sdk-s3": "3.577.0", - "@aws-sdk/types": "3.577.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/signature-v4": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.577.0.tgz", - "integrity": "sha512-0CkIZpcC3DNQJQ1hDjm2bdSy/Xjs7Ny5YvSsacasGOkNfk+FdkiQy6N67bZX3Zbc9KIx+Nz4bu3iDeNSNplnnQ==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-sso-oidc": "^3.577.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.577.0.tgz", - "integrity": "sha512-FT2JZES3wBKN/alfmhlo+3ZOq/XJ0C7QOZcDNrpKjB0kqYoKjhVKZ/Hx6ArR0czkKfHzBBEs6y40ebIHx2nSmA==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-arn-parser": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.568.0.tgz", - "integrity": "sha512-XUKJWWo+KOB7fbnPP0+g/o5Ulku/X53t7i/h+sPHr5xxYTJJ9CYnbToo95mzxe7xWvkLrsNtJ8L+MnNn9INs2w==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-dynamodb": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.577.0.tgz", - "integrity": "sha512-GGzUZ1saDcP052jFpZ6HfukMwBM2Jtxq1H0fzfWV1YPLikjNJaXt8j/Eng2cNNH0RUdTkPGVAF+mlHjNirosKA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.577.0" - } - }, - "node_modules/@aws-sdk/util-endpoints": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.577.0.tgz", - "integrity": "sha512-FjuUz1Kdy4Zly2q/c58tpdqHd6z7iOdU/caYzoc8jwgAHBDBbIJNQLCU9hXJnPV2M8pWxQDyIZsoVwtmvErPzw==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "@smithy/util-endpoints": "^2.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.568.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", - "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.577.0.tgz", - "integrity": "sha512-zEAzHgR6HWpZOH7xFgeJLc6/CzMcx4nxeQolZxVZoB5pPaJd3CjyRhZN0xXeZB0XIRCWmb4yJBgyiugXLNMkLA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/types": "^3.0.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.577.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.577.0.tgz", - "integrity": "sha512-XqvtFjbSMtycZTWVwDe8DRWovuoMbA54nhUoZwVU6rW9OSD6NZWGR512BUGHFaWzW0Wg8++Dj10FrKTG2XtqfA==", - "dependencies": { - "@aws-sdk/types": "3.577.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.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": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-p6GlFGBt9K4MYLu72YuJ523NVR4A8oHlC5M2JO6OmQqN8kAc/uh1JqLE+FizTokrSJGg0CSvC+BrsmGzKtsZKA==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/config-resolver": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.0.tgz", - "integrity": "sha512-2GzOfADwYLQugYkKQhIyZyQlM05K+tMKvRnc6eFfZcpJGRfKoMUMYdPlBKmqHwQFXQKBrGV6cxL9oymWgDzvFw==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-config-provider": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/core": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.0.1.tgz", - "integrity": "sha512-rcMkjvwxH/bER+oZUPR0yTA0ELD6m3A+d92+CFkdF6HJFCBB1bXo7P5pm21L66XwTN01B6bUhSCQ7cymWRD8zg==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-retry": "^3.0.1", - "@smithy/middleware-serde": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.0.0.tgz", - "integrity": "sha512-lfmBiFQcA3FsDAPxNfY0L7CawcWtbyWsBOHo34nF095728JLkBX4Y9q/VPPE2r7fqMVK+drmDigqE2/SSQeVRA==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.0.1.tgz", - "integrity": "sha512-uaH74i5BDj+rBwoQaXioKpI0SHBJFtOVwzrCpxZxphOW0ki5jhj7dXvDMYM2IJem8TpdFvS2iC08sjOblfFGFg==", - "dependencies": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/hash-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.0.tgz", - "integrity": "sha512-84qXstNemP3XS5jcof0el6+bDfjzuvhJPQTEfro3lgtbCtKgzPm3MgiS6ehXVPjeQ5+JS0HqmTz8f/RYfzHVxw==", - "dependencies": { - "@smithy/types": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/invalid-dependency": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.0.tgz", - "integrity": "sha512-F6wBBaEFgJzj0s4KUlliIGPmqXemwP6EavgvDqYwCH40O5Xr2iMHvS8todmGVZtuJCorBkXsYLyTu4PuizVq5g==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", - "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-content-length": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.0.tgz", - "integrity": "sha512-3C4s4d/iGobgCtk2tnWW6+zSTOBg1PRAm2vtWZLdriwTroFbbWNSr3lcyzHdrQHnEXYCC5K52EbpfodaIUY8sg==", - "dependencies": { - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-endpoint": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.0.0.tgz", - "integrity": "sha512-aXOAWztw/5qAfp0NcA2OWpv6ZI/E+Dh9mByif7i91D/0iyYNUcKvskmXiowKESFkuZ7PIMd3VOR4fTibZDs2OQ==", - "dependencies": { - "@smithy/middleware-serde": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/url-parser": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.1.tgz", - "integrity": "sha512-hBhSEuL841FhJBK/19WpaGk5YWSzFk/P2UaVjANGKRv3eYNO8Y1lANWgqnuPWjOyCEWMPr58vELFDWpxvRKANw==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/service-error-classification": "^3.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-retry": "^3.0.0", - "tslib": "^2.6.2", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-retry/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/@smithy/middleware-serde": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.0.tgz", - "integrity": "sha512-I1vKG1foI+oPgG9r7IMY1S+xBnmAn1ISqployvqkwHoSb8VPsngHDTOgYGYBonuOKndaWRUGJZrKYYLB+Ane6w==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/middleware-stack": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.0.tgz", - "integrity": "sha512-+H0jmyfAyHRFXm6wunskuNAqtj7yfmwFB6Fp37enytp2q047/Od9xetEaUbluyImOlGnGpaVGaVfjwawSr+i6Q==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.0.0.tgz", - "integrity": "sha512-buqfaSdDh0zo62EPLf8rGDvcpKwGpO5ho4bXS2cdFhlOta7tBkWJt+O5uiaAeICfIOfPclNOndshDNSanX2X9g==", - "dependencies": { - "@smithy/property-provider": "^3.0.0", - "@smithy/shared-ini-file-loader": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.0.0.tgz", - "integrity": "sha512-3trD4r7NOMygwLbUJo4eodyQuypAWr7uvPnebNJ9a70dQhVn+US8j/lCnvoJS6BXfZeF7PkkkI0DemVJw+n+eQ==", - "dependencies": { - "@smithy/abort-controller": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/querystring-builder": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/property-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.0.0.tgz", - "integrity": "sha512-LmbPgHBswdXCrkWWuUwBm9w72S2iLWyC/5jet9/Y9cGHtzqxi+GVjfCfahkvNV4KXEwgnH8EMpcrD9RUYe0eLQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/protocol-http": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.0.0.tgz", - "integrity": "sha512-qOQZOEI2XLWRWBO9AgIYuHuqjZ2csyr8/IlgFDHDNuIgLAMRx2Bl8ck5U5D6Vh9DPdoaVpuzwWMa0xcdL4O/AQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-builder": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.0.tgz", - "integrity": "sha512-bW8Fi0NzyfkE0TmQphDXr1AmBDbK01cA4C1Z7ggwMAU5RDz5AAv/KmoRwzQAS0kxXNf/D2ALTEgwK0U2c4LtRg==", - "dependencies": { - "@smithy/types": "^3.0.0", - "@smithy/util-uri-escape": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/querystring-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.0.tgz", - "integrity": "sha512-UzHwthk0UEccV4dHzPySnBy34AWw3V9lIqUTxmozQ+wPDAO9csCWMfOLe7V9A2agNYy7xE+Pb0S6K/J23JSzfQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/service-error-classification": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.0.tgz", - "integrity": "sha512-3BsBtOUt2Gsnc3X23ew+r2M71WwtpHfEDGhHYHSDg6q1t8FrWh15jT25DLajFV1H+PpxAJ6gqe9yYeRUsmSdFA==", - "dependencies": { - "@smithy/types": "^3.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/shared-ini-file-loader": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.0.0.tgz", - "integrity": "sha512-REVw6XauXk8xE4zo5aGL7Rz4ywA8qNMUn8RtWeTRQsgAlmlvbJ7CEPBcaXU2NDC3AYBgYAXrGyWD8XrN8UGDog==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-3.0.0.tgz", - "integrity": "sha512-kXFOkNX+BQHe2qnLxpMEaCRGap9J6tUGLzc3A9jdn+nD4JdMwCKTJ+zFwQ20GkY+mAXGatyTw3HcoUlR39HwmA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-middleware": "^3.0.0", - "@smithy/util-uri-escape": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/smithy-client": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.0.1.tgz", - "integrity": "sha512-KAiFY4Y4jdHxR+4zerH/VBhaFKM8pbaVmJZ/CWJRwtM/CmwzTfXfvYwf6GoUwiHepdv+lwiOXCuOl6UBDUEINw==", - "dependencies": { - "@smithy/middleware-endpoint": "^3.0.0", - "@smithy/middleware-stack": "^3.0.0", - "@smithy/protocol-http": "^4.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-stream": "^3.0.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.0.0.tgz", - "integrity": "sha512-VvWuQk2RKFuOr98gFhjca7fkBS+xLLURT8bUjk5XQoV0ZLm7WPwWPPY3/AwzTLuUBDeoKDCthfe1AsTUWaSEhw==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/url-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.0.tgz", - "integrity": "sha512-2XLazFgUu+YOGHtWihB3FSLAfCUajVfNBXGGYjOaVKjLAuAxx3pSBY3hBgLzIgB17haf59gOG3imKqTy8mcrjw==", - "dependencies": { - "@smithy/querystring-parser": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-base64": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", - "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-body-length-browser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", - "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@smithy/util-body-length-node": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", - "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", - "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", - "dependencies": { - "@smithy/is-array-buffer": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-config-provider": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", - "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.1.tgz", - "integrity": "sha512-nW5kEzdJn1Bn5TF+gOPHh2rcPli8JU9vSSXLbfg7uPnfR1TMRQqs9zlYRhIb87NeSxIbpdXOI94tvXSy+fvDYg==", - "dependencies": { - "@smithy/property-provider": "^3.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.1.tgz", - "integrity": "sha512-TFk+Qb+elLc/MOhtSp+50fstyfZ6avQbgH2d96xUBpeScu+Al9elxv+UFAjaTHe0HQe5n+wem8ZLpXvU8lwV6Q==", - "dependencies": { - "@smithy/config-resolver": "^3.0.0", - "@smithy/credential-provider-imds": "^3.0.0", - "@smithy/node-config-provider": "^3.0.0", - "@smithy/property-provider": "^3.0.0", - "@smithy/smithy-client": "^3.0.1", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/@smithy/util-endpoints": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.0.tgz", - "integrity": "sha512-+exaXzEY3DNt2qtA2OtRNSDlVrE4p32j1JSsQkzA5AdP0YtJNjkYbYhJxkFmPYcjI1abuwopOZCwUmv682QkiQ==", - "dependencies": { - "@smithy/node-config-provider": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-hex-encoding": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", - "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-middleware": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.0.tgz", - "integrity": "sha512-q5ITdOnV2pXHSVDnKWrwgSNTDBAMHLptFE07ua/5Ty5WJ11bvr0vk2a7agu7qRhrCFRQlno5u3CneU5EELK+DQ==", - "dependencies": { - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-retry": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.0.tgz", - "integrity": "sha512-nK99bvJiziGv/UOKJlDvFF45F00WgPLKVIGUfAK+mDhzVN2hb/S33uW2Tlhg5PVBoqY7tDVqL0zmu4OxAHgo9g==", - "dependencies": { - "@smithy/service-error-classification": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-stream": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.0.1.tgz", - "integrity": "sha512-7F7VNNhAsfMRA8I986YdOY5fE0/T1/ZjFF6OLsqkvQVNP3vZ/szYDfGCyphb7ioA09r32K/0qbSFfNFU68aSzA==", - "dependencies": { - "@smithy/fetch-http-handler": "^3.0.1", - "@smithy/node-http-handler": "^3.0.0", - "@smithy/types": "^3.0.0", - "@smithy/util-base64": "^3.0.0", - "@smithy/util-buffer-from": "^3.0.0", - "@smithy/util-hex-encoding": "^3.0.0", - "@smithy/util-utf8": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-uri-escape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", - "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", - "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", - "dependencies": { - "@smithy/util-buffer-from": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@smithy/util-waiter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-3.0.0.tgz", - "integrity": "sha512-+fEXJxGDLCoqRKVSmo0auGxaqbiCo+8oph+4auefYjaNxjOLKSY2MxVQfRzo65PaZv4fr+5lWg+au7vSuJJ/zw==", - "dependencies": { - "@smithy/abort-controller": "^3.0.0", - "@smithy/types": "^3.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true - }, - "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/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/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - } - } -} diff --git a/backend/src/lambda/transactionsResolver/package.json b/backend/src/lambda/transactionsResolver/package.json deleted file mode 100644 index c3a8882f..00000000 --- a/backend/src/lambda/transactionsResolver/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "transactions-resolver", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "build": "tsc", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "", - "license": "ISC", - "dependencies": { - "@aws-sdk/client-dynamodb": "^3.577.0", - "@aws-sdk/client-eventbridge": "^3.577.0", - "@aws-sdk/util-dynamodb": "^3.577.0", - "uuid": "^10.0.0" - }, - "devDependencies": { - "@types/node": "^20.12.12", - "@types/uuid": "^10.0.0" - } -} diff --git a/backend/src/lambda/transactionsResolver/tsconfig.json b/backend/src/lambda/transactionsResolver/tsconfig.json deleted file mode 100644 index c9ebcd4a..00000000 --- a/backend/src/lambda/transactionsResolver/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "strict": true, - "preserveConstEnums": true, - "noEmit": true, - "sourceMap": false, - "module": "commonjs", - "moduleResolution": "node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "isolatedModules": true - }, - "exclude": ["node_modules", "**/*.test.ts"] -} diff --git a/backend/src/lambda/transactionsResolver/updateBankTransaction.ts b/backend/src/lambda/transactionsResolver/updateBankTransaction.ts deleted file mode 100644 index 7dc10fc0..00000000 --- a/backend/src/lambda/transactionsResolver/updateBankTransaction.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { UpdateItemCommand, UpdateItemCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall } from '@aws-sdk/util-dynamodb'; - -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import publishEventAsync from './helpers/eventBridge'; -import { UpdateBankTransactionInput } from '../../appsync/api/codegen/appsync'; - -async function updateBankTransaction(userId: string, input: UpdateBankTransactionInput) { - console.debug(`🕧 Update Bank Transaction initialized`); - - const updatedAt = new Date().toISOString(); - - const updateItemCommandInput: UpdateItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Key: marshall({ - pk: `trans#${input.transactionId}`, - }), - UpdateExpression: 'SET transactionDate=:transactionDate, payee=:payee, category=:category, amount=:amount, updatedAt=:updatedAt', - ExpressionAttributeValues: marshall({ - ':transactionDate': input.transactionDate, - ':payee': input.payee, - ':category': input.category, - ':amount': input.amount, - ':userId': userId, - ':updatedAt': updatedAt, - }), - ConditionExpression: 'userId = :userId', - }; - const updateResult = await dynamoDbCommand(new UpdateItemCommand(updateItemCommandInput)); - - if (updateResult.$metadata.httpStatusCode === 200) { - // Publish event to update positions - await publishEventAsync('TransactionSavedEvent', input); - - // console.log(`✅ Updated Transaction: {result: ${JSON.stringify(updateResult)}, item: ${unmarshall(updateResult.Attributes)}}`); - // return unmarshall(updateResult.Attributes); - console.log(`✅ Updated Transaction: {result: ${JSON.stringify(updateResult)}`); - return { - ...input, - accountId: input.accountId, - updatedAt, - }; - } - - console.log(`🛑 Could not update bank transaction\n`, updateResult); - return {}; -} - -export default updateBankTransaction; diff --git a/backend/src/lambda/transactionsResolver/updateInvestmentTransaction.ts b/backend/src/lambda/transactionsResolver/updateInvestmentTransaction.ts deleted file mode 100644 index adb7f587..00000000 --- a/backend/src/lambda/transactionsResolver/updateInvestmentTransaction.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { UpdateItemCommand, UpdateItemCommandInput } from '@aws-sdk/client-dynamodb'; -import { marshall } from '@aws-sdk/util-dynamodb'; - -import dynamoDbCommand from './helpers/dynamoDbCommand'; -import publishEventAsync from './helpers/eventBridge'; -import { UpdateInvestmentTransactionInput } from '../../appsync/api/codegen/appsync'; - -async function updateInvestmentTransaction(userId: string, input: UpdateInvestmentTransactionInput) { - console.debug(`🕧 Update Investment Transaction initialized`); - - const updatedAt = new Date().toISOString(); - - const updateItemCommandInput: UpdateItemCommandInput = { - TableName: process.env.DATA_TABLE_NAME, - Key: marshall({ - pk: `trans#${input.transactionId}`, - }), - UpdateExpression: - 'SET #type=:type, transactionDate=:transactionDate, symbol=:symbol, shares=:shares, price=:price, commission=:commission, updatedAt=:updatedAt', - ExpressionAttributeValues: marshall({ - ':type': input.type, - ':transactionDate': input.transactionDate, - ':symbol': input.symbol, - ':shares': input.shares, - ':price': input.price, - ':commission': input.commission, - ':userId': userId, - ':updatedAt': updatedAt, - }), - ExpressionAttributeNames: { - '#type': 'type', - }, - ConditionExpression: 'userId = :userId', - }; - const updateResult = await dynamoDbCommand(new UpdateItemCommand(updateItemCommandInput)); - - if (updateResult.$metadata.httpStatusCode === 200) { - // Publish event to update positions - await publishEventAsync('TransactionSavedEvent', input); - - // console.log(`✅ Updated Transaction: {result: ${JSON.stringify(updateResult)}, item: ${unmarshall(updateResult.Attributes)}}`); - // return unmarshall(updateResult.Attributes); - console.log(`✅ Updated Transaction: {result: ${JSON.stringify(updateResult)}`); - return { - ...input, - accountId: input.accountId, - updatedAt, - }; - } - - console.log(`🛑 Could not update investment transaction\n`, updateResult); - return {}; -} - -export default updateInvestmentTransaction; diff --git a/backend/src/lambda/types/Account.ts b/backend/src/lambda/types/Account.ts deleted file mode 100644 index 03eb0c18..00000000 --- a/backend/src/lambda/types/Account.ts +++ /dev/null @@ -1,57 +0,0 @@ -export type AccountReadModel = { - userId: string; - sk: string; - aggregateId: string; - entity: string; - type: string; - name: string; - description: string; - createdAt: string; - updatedAt: string; -}; - -export type CreateAccountInput = { - userId: string; - type: string; - name: string; - description: string; -}; - -export type UpdateAccountInput = { - userId: string; - sk: string; - type: string; - name: string; - description: string; -}; - -export type DeleteAccountInput = { - userId: string; - aggregateId: string; -}; - -export type LastEvaluatedKey = { - userId: string; - sk: string; -}; - -export type AccountAppSyncEvent = { - info: { - fieldName: string; - }; - arguments: { - userId: string; //getAccounts - aggregateId: string; //getAccount - lastEvaluatedKey: LastEvaluatedKey; //getAccounts - - createAccountInput: CreateAccountInput; - updateAccountInput: UpdateAccountInput; - deleteAccountInput: DeleteAccountInput; - }; - identity: { - username: string; - claims: { - [key: string]: string[]; - }; - }; -}; diff --git a/backend/src/lambda/types/Transaction.ts b/backend/src/lambda/types/Transaction.ts deleted file mode 100644 index fbd7d0d1..00000000 --- a/backend/src/lambda/types/Transaction.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { - CreateBankTransactionInput, - CreateInvestmentTransactionInput, - DeleteTransactionInput, - UpdateBankTransactionInput, - UpdateInvestmentTransactionInput, -} from '../../appsync/api/codegen/appsync'; - -export type TransactionAppSyncEvent = { - info: { - fieldName: string; - }; - arguments: { - input: - | CreateBankTransactionInput - | CreateInvestmentTransactionInput - | UpdateBankTransactionInput - | UpdateInvestmentTransactionInput - | DeleteTransactionInput; - }; - identity: { - username: string; - claims: { - [key: string]: string[]; - }; - }; -}; diff --git a/backend/src/lambda/updatePositions/package.json b/backend/src/lambda/updatePositions/package.json index c9abcf6c..229f382c 100644 --- a/backend/src/lambda/updatePositions/package.json +++ b/backend/src/lambda/updatePositions/package.json @@ -15,7 +15,7 @@ "@aws-sdk/util-dynamodb": "^3.577.0", "@types/aws-lambda": "^8.10.138", "aws-lambda": "^1.0.7", - "yahoo-finance2": "^2.13.3" + "yahoo-finance2": "2.13.3" }, "devDependencies": { "@types/node": "^20.12.12" diff --git a/backend/src/lambda/updatePositions/yahooFinance.ts b/backend/src/lambda/updatePositions/yahooFinance.ts index 97a03f7b..50b8aec2 100644 --- a/backend/src/lambda/updatePositions/yahooFinance.ts +++ b/backend/src/lambda/updatePositions/yahooFinance.ts @@ -5,11 +5,18 @@ import { HistoricalHistoryResult, HistoricalRowHistory } from 'yahoo-finance2/di export async function getQuoteSummary(symbol: string) { console.debug(`Getting quote for ${symbol}`); + console.log('đŸ•ĩī¸ Calling YahooFinance quoteSummary()'); + // Get quotes from Yahoo Finance + // TODO: this is returning ""Unsupported redirect to https://finance.yahoo.com/quote/AAPL/, please report."," and halting the lambda + // https://github.com/gadicc/node-yahoo-finance2/issues/777 + // Need to fix const data = await yahooFinance.quoteSummary(symbol, { modules: ['price'], }); + console.log('đŸ•ĩī¸ Returned from YahooFinance quoteSummary()', data); + if (!data || !data.price || !data.price.regularMarketTime) { return; } diff --git a/backend/test/appsync/Mutation.createBankTransaction.test..ts b/backend/test/appsync/Mutation.createBankTransaction.test..ts new file mode 100644 index 00000000..b81f987d --- /dev/null +++ b/backend/test/appsync/Mutation.createBankTransaction.test..ts @@ -0,0 +1,64 @@ +import { AppSyncClient, EvaluateCodeCommand, EvaluateCodeCommandInput } from '@aws-sdk/client-appsync'; +import { readFile } from 'fs/promises'; +import { unmarshall } from '@aws-sdk/util-dynamodb'; + +const file = './src/appsync/build/Mutation.createBankTransaction.js'; + +const appsync = new AppSyncClient({ region: 'us-east-1' }); + +describe('Mutation.createBankTransaction', () => { + it('creates a new bank transaction', async () => { + // Arrange + const context = { + arguments: { + input: { + accountId: '123', + amount: 100.0, + category: 'Housing', + payee: 'Amazon', + transactionDate: new Date().setHours(0, 0, 0, 0), + }, + }, + identity: { + username: 'testuser', + sub: 'uuid', + sourceIp: ['0.0.0.0'], + defaultAuthStrategy: 'ALLOW', + groups: null, + issuer: 'test-issuer', + claims: {}, + }, + }; + const input: EvaluateCodeCommandInput = { + runtime: { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' }, + code: await readFile(file, { encoding: 'utf8' }), + context: JSON.stringify(context), + function: 'request', + }; + const evaluateCodeCommand = new EvaluateCodeCommand(input); + + // Act + const response = await appsync.send(evaluateCodeCommand); + + // Assert + expect(response).toBeDefined(); + expect(response.error).toBeUndefined(); + expect(response.evaluationResult).toBeDefined(); + + const result = JSON.parse(response.evaluationResult ?? '{}'); + expect(result.operation).toEqual('PutItem'); + + const key = unmarshall(result.key); + const attributeValues = unmarshall(result.attributeValues); + expect(key.pk).toContain('trans#'); + expect(attributeValues['entity']).toBe('bank-transaction'); + expect(attributeValues['accountId']).toBe(context.arguments.input.accountId); + expect(attributeValues['transactionId']).toBeDefined(); + expect(attributeValues['payee']).toBe(context.arguments.input.payee); + expect(attributeValues['category']).toBe(context.arguments.input.category); + expect(attributeValues['amount']).toBe(context.arguments.input.amount); + expect(attributeValues['userId']).toBe(context.identity.username); + expect(attributeValues['createdAt']).toBeDefined(); + expect(attributeValues['updatedAt']).toBeDefined(); + }); +}); diff --git a/backend/test/appsync/Mutation.createInvestmentTransaction.test.ts b/backend/test/appsync/Mutation.createInvestmentTransaction.test.ts new file mode 100644 index 00000000..8345a5f2 --- /dev/null +++ b/backend/test/appsync/Mutation.createInvestmentTransaction.test.ts @@ -0,0 +1,68 @@ +import { AppSyncClient, EvaluateCodeCommand, EvaluateCodeCommandInput } from '@aws-sdk/client-appsync'; +import { readFile } from 'fs/promises'; +import { unmarshall } from '@aws-sdk/util-dynamodb'; + +const file = './src/appsync/build/Mutation.createInvestmentTransaction.js'; + +const appsync = new AppSyncClient({ region: 'us-east-1' }); + +describe('Mutation.createInvestmentTransaction', () => { + it('creates a new investment transaction', async () => { + // Arrange + const context = { + arguments: { + input: { + accountId: '123', + commission: 10.0, + price: 180.27, + shares: 100, + symbol: 'AMZN', + type: 'Buy', + transactionDate: new Date().setHours(0, 0, 0, 0), + }, + }, + identity: { + username: 'testuser', + sub: 'uuid', + sourceIp: ['0.0.0.0'], + defaultAuthStrategy: 'ALLOW', + groups: null, + issuer: 'test-issuer', + claims: {}, + }, + }; + const input: EvaluateCodeCommandInput = { + runtime: { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' }, + code: await readFile(file, { encoding: 'utf8' }), + context: JSON.stringify(context), + function: 'request', + }; + const evaluateCodeCommand = new EvaluateCodeCommand(input); + + // Act + const response = await appsync.send(evaluateCodeCommand); + + // Assert + expect(response).toBeDefined(); + expect(response.error).toBeUndefined(); + expect(response.evaluationResult).toBeDefined(); + + const result = JSON.parse(response.evaluationResult ?? '{}'); + expect(result.operation).toEqual('PutItem'); + + const key = unmarshall(result.key); + const attributeValues = unmarshall(result.attributeValues); + expect(key.pk).toContain('trans#'); + expect(attributeValues['accountId']).toBe(context.arguments.input.accountId); + expect(attributeValues['transactionId']).toBeDefined(); + expect(attributeValues['transactionDate']).toBe(context.arguments.input.transactionDate); + expect(attributeValues['type']).toBe(context.arguments.input.type); + expect(attributeValues['symbol']).toBe(context.arguments.input.symbol); + expect(attributeValues['shares']).toBe(context.arguments.input.shares); + expect(attributeValues['price']).toBe(context.arguments.input.price); + expect(attributeValues['commission']).toBe(context.arguments.input.commission); + expect(attributeValues['userId']).toBe(context.identity.username); + expect(attributeValues['createdAt']).toBeDefined(); + expect(attributeValues['updatedAt']).toBeDefined(); + }); +}); diff --git a/backend/test/appsync/Mutation.deleteBankTransaction.test.ts b/backend/test/appsync/Mutation.deleteBankTransaction.test.ts new file mode 100644 index 00000000..d9e24ae3 --- /dev/null +++ b/backend/test/appsync/Mutation.deleteBankTransaction.test.ts @@ -0,0 +1,49 @@ +import { AppSyncClient, EvaluateCodeCommand, EvaluateCodeCommandInput } from '@aws-sdk/client-appsync'; +import { unmarshall } from '@aws-sdk/util-dynamodb'; +import { readFile } from 'fs/promises'; + +const file = './src/appsync/build/Mutation.deleteBankTransaction.js'; + +const appsync = new AppSyncClient({ region: 'us-east-1' }); + +describe('Mutation.deleteBankTransaction', () => { + it('deletes a single bank transaction', async () => { + // Arrange + const context = { + arguments: { + input: { + pk: 'pk', + }, + }, + identity: { + sub: 'uuid', + issuer: ' https://cognito-idp.us-east-1.amazonaws.com/userPoolId', + username: 'testuser', + claims: {}, + sourceIp: ['x.x.x.x'], + defaultAuthStrategy: 'ALLOW', + }, + }; + const input: EvaluateCodeCommandInput = { + runtime: { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' }, + code: await readFile(file, { encoding: 'utf8' }), + context: JSON.stringify(context), + function: 'request', + }; + const evaluateCodeCommand = new EvaluateCodeCommand(input); + + // Act + const response = await appsync.send(evaluateCodeCommand); + + // Assert + expect(response).toBeDefined(); + expect(response.error).toBeUndefined(); + expect(response.evaluationResult).toBeDefined(); + + const result = JSON.parse(response.evaluationResult ?? '{}'); + expect(result.operation).toEqual('DeleteItem'); + + const pk = unmarshall(result.key); + expect(pk).toBe(pk); + }); +}); diff --git a/backend/test/appsync/Mutation.deleteInvestmentTransaction.test.ts b/backend/test/appsync/Mutation.deleteInvestmentTransaction.test.ts new file mode 100644 index 00000000..a017d336 --- /dev/null +++ b/backend/test/appsync/Mutation.deleteInvestmentTransaction.test.ts @@ -0,0 +1,49 @@ +import { AppSyncClient, EvaluateCodeCommand, EvaluateCodeCommandInput } from '@aws-sdk/client-appsync'; +import { unmarshall } from '@aws-sdk/util-dynamodb'; +import { readFile } from 'fs/promises'; + +const file = './src/appsync/build/Mutation.deleteInvestmentTransaction.js'; + +const appsync = new AppSyncClient({ region: 'us-east-1' }); + +describe('Mutation.deleteInvestmentTransaction', () => { + it('deletes a single investment transaction', async () => { + // Arrange + const context = { + arguments: { + input: { + pk: 'pk', + }, + }, + identity: { + sub: 'uuid', + issuer: ' https://cognito-idp.us-east-1.amazonaws.com/userPoolId', + username: 'testuser', + claims: {}, + sourceIp: ['x.x.x.x'], + defaultAuthStrategy: 'ALLOW', + }, + }; + const input: EvaluateCodeCommandInput = { + runtime: { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' }, + code: await readFile(file, { encoding: 'utf8' }), + context: JSON.stringify(context), + function: 'request', + }; + const evaluateCodeCommand = new EvaluateCodeCommand(input); + + // Act + const response = await appsync.send(evaluateCodeCommand); + + // Assert + expect(response).toBeDefined(); + expect(response.error).toBeUndefined(); + expect(response.evaluationResult).toBeDefined(); + + const result = JSON.parse(response.evaluationResult ?? '{}'); + expect(result.operation).toEqual('DeleteItem'); + + const pk = unmarshall(result.key); + expect(pk).toBe(pk); + }); +}); diff --git a/backend/test/appsync/Mutation.updateBankTransaction.test.ts b/backend/test/appsync/Mutation.updateBankTransaction.test.ts new file mode 100644 index 00000000..4f3bfca6 --- /dev/null +++ b/backend/test/appsync/Mutation.updateBankTransaction.test.ts @@ -0,0 +1,63 @@ +import { AppSyncClient, EvaluateCodeCommand, EvaluateCodeCommandInput } from '@aws-sdk/client-appsync'; +import { readFile } from 'fs/promises'; +import { unmarshall } from '@aws-sdk/util-dynamodb'; + +const file = './src/appsync/build/Mutation.updateBankTransaction.js'; + +const appsync = new AppSyncClient({ region: 'us-east-1' }); + +describe('Mutation.updateBankTransaction', () => { + it('updates an existing bank transaction', async () => { + // Arrange + const context = { + arguments: { + input: { + accountId: '123', + amount: 100.0, + category: 'Housing', + payee: 'Amazon', + transactionDate: new Date().setHours(0, 0, 0, 0), + transasctionId: '456', + }, + }, + identity: { + username: 'testuser', + sub: 'uuid', + sourceIp: ['0.0.0.0'], + defaultAuthStrategy: 'ALLOW', + groups: null, + issuer: 'test-issuer', + claims: {}, + }, + }; + const input: EvaluateCodeCommandInput = { + runtime: { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' }, + code: await readFile(file, { encoding: 'utf8' }), + context: JSON.stringify(context), + function: 'request', + }; + const evaluateCodeCommand = new EvaluateCodeCommand(input); + + // Act + const response = await appsync.send(evaluateCodeCommand); + + // Assert + expect(response).toBeDefined(); + expect(response.error).toBeUndefined(); + expect(response.evaluationResult).toBeDefined(); + + const result = JSON.parse(response.evaluationResult ?? '{}'); + expect(result.operation).toEqual('UpdateItem'); + + const key = unmarshall(result.key); + const expressionValues = unmarshall(result.update.expressionValues); + expect(key.pk).toContain('trans#'); + expect(expressionValues['accountId']).toBe(context.arguments.input.accountId); + expect(expressionValues['transactionDate']).toBe(context.arguments.input.transactionDate); + expect(expressionValues['payee']).toBe(context.arguments.input.payee); + expect(expressionValues['category']).toBe(context.arguments.input.category); + expect(expressionValues['amount']).toBe(context.arguments.input.amount); + expect(expressionValues['userId']).toBe(context.identity.username); + expect(expressionValues['updatedAt']).toBeDefined(); + }); +}); diff --git a/backend/test/appsync/Mutation.updateInvestmentTransaction.test.ts b/backend/test/appsync/Mutation.updateInvestmentTransaction.test.ts new file mode 100644 index 00000000..337b4950 --- /dev/null +++ b/backend/test/appsync/Mutation.updateInvestmentTransaction.test.ts @@ -0,0 +1,66 @@ +import { AppSyncClient, EvaluateCodeCommand, EvaluateCodeCommandInput } from '@aws-sdk/client-appsync'; +import { readFile } from 'fs/promises'; +import { unmarshall } from '@aws-sdk/util-dynamodb'; + +const file = './src/appsync/build/Mutation.updateInvestmentTransaction.js'; + +const appsync = new AppSyncClient({ region: 'us-east-1' }); + +describe('Mutation.updateInvestmentTransaction', () => { + it('updates an existing investment transaction', async () => { + // Arrange + const context = { + arguments: { + input: { + accountId: '123', + commission: 10.0, + price: 180.27, + shares: 100, + symbol: 'AMZN', + type: 'Buy', + transactionDate: new Date().setHours(0, 0, 0, 0), + transactionId: '456', + }, + }, + identity: { + username: 'testuser', + sub: 'uuid', + sourceIp: ['0.0.0.0'], + defaultAuthStrategy: 'ALLOW', + groups: null, + issuer: 'test-issuer', + claims: {}, + }, + }; + const input: EvaluateCodeCommandInput = { + runtime: { name: 'APPSYNC_JS', runtimeVersion: '1.0.0' }, + code: await readFile(file, { encoding: 'utf8' }), + context: JSON.stringify(context), + function: 'request', + }; + const evaluateCodeCommand = new EvaluateCodeCommand(input); + + // Act + const response = await appsync.send(evaluateCodeCommand); + + // Assert + expect(response).toBeDefined(); + expect(response.error).toBeUndefined(); + expect(response.evaluationResult).toBeDefined(); + + const result = JSON.parse(response.evaluationResult ?? '{}'); + expect(result.operation).toEqual('UpdateItem'); + + const key = unmarshall(result.key); + const expressionValues = unmarshall(result.update.expressionValues); + expect(key.pk).toContain('trans#'); + expect(expressionValues['accountId']).toBe(context.arguments.input.accountId); + expect(expressionValues['type']).toBe(context.arguments.input.type); + expect(expressionValues['symbol']).toBe(context.arguments.input.symbol); + expect(expressionValues['shares']).toBe(context.arguments.input.shares); + expect(expressionValues['price']).toBe(context.arguments.input.price); + expect(expressionValues['commission']).toBe(context.arguments.input.commission); + expect(expressionValues['userId']).toBe(context.identity.username); + expect(expressionValues['updatedAt']).toBeDefined(); + }); +}); diff --git a/frontend/src/actions/api/mutations.ts b/frontend/src/actions/api/mutations.ts index 9472372d..8c3a39c4 100644 --- a/frontend/src/actions/api/mutations.ts +++ b/frontend/src/actions/api/mutations.ts @@ -6,7 +6,8 @@ import { MutationCreatePayeeArgs, MutationCreateSymbolArgs, MutationDeleteAccountArgs, - MutationDeleteTransactionArgs, + MutationDeleteBankTransactionArgs, + MutationDeleteInvestmentTransactionArgs, MutationUpdateAccountArgs, MutationUpdateBankTransactionArgs, MutationUpdateCategoryArgs, @@ -89,6 +90,12 @@ export const updateBankTransaction = `mutation UpdateBankTransaction($input: Upd } }` as Query; +export const deleteBankTransaction = `mutation DeleteBankTransaction($input: DeleteBankTransactionInput!) { + deleteBankTransaction(input: $input) { + pk + } +}` as Query; + export const createInvestmentTransaction = `mutation CreateInvestmentTransaction($input: CreateInvestmentTransactionInput!) { createInvestmentTransaction(input: $input) { transactionId @@ -118,11 +125,11 @@ export const updateInvestmentTransaction = `mutation UpdateInvestmentTransaction } }` as Query; -export const deleteTransaction = `mutation DeleteTransaction($input: DeleteTransactionInput!) { - deleteTransaction(input: $input) { +export const deleteInvestmentTransaction = `mutation DeleteInvestmentTransaction($input: DeleteInvestmentTransactionInput!) { + deleteInvestmentTransaction(input: $input) { pk } -}` as Query; +}` as Query; export const createCategory = `mutation CreateCategory($name: String!) { createCategory(name: $name) { diff --git a/frontend/src/actions/delete-transaction.ts b/frontend/src/actions/delete-bank-transaction.ts similarity index 60% rename from frontend/src/actions/delete-transaction.ts rename to frontend/src/actions/delete-bank-transaction.ts index 499d6a23..98aa83e6 100644 --- a/frontend/src/actions/delete-transaction.ts +++ b/frontend/src/actions/delete-bank-transaction.ts @@ -1,24 +1,24 @@ 'use server'; import { serverClient } from '@/utils/amplifyServerUtils'; -import { deleteTransaction } from './api/mutations'; +import { deleteBankTransaction } from './api/mutations'; import { revalidatePath } from 'next/cache'; import { redirect } from 'next/navigation'; -import { BankTransaction, InvestmentTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; +import { BankTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; -interface DeleteTransactionFormState { +interface DeleteBankTransactionFormState { errors: { transactionId?: string[]; _form?: string[]; }; } -export async function deleteExistingTransaction(transaction: BankTransaction | InvestmentTransaction): Promise { - console.log('deleteExistingTransaction', transaction); +export async function deleteExistingBankTransaction(transaction: BankTransaction): Promise { + console.log('deleteExistingBankTransaction', transaction); try { await serverClient.graphql({ - query: deleteTransaction, + query: deleteBankTransaction, variables: { input: { pk: transaction.pk, diff --git a/frontend/src/actions/delete-investment-transaction.ts b/frontend/src/actions/delete-investment-transaction.ts new file mode 100644 index 00000000..92e822f8 --- /dev/null +++ b/frontend/src/actions/delete-investment-transaction.ts @@ -0,0 +1,40 @@ +'use server'; + +import { serverClient } from '@/utils/amplifyServerUtils'; +import { deleteInvestmentTransaction } from './api/mutations'; +import { revalidatePath } from 'next/cache'; +import { redirect } from 'next/navigation'; +import { InvestmentTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; + +interface DeleteInvestmentTransactionFormState { + errors: { + transactionId?: string[]; + _form?: string[]; + }; +} + +export async function deleteExistingInvestmentTransaction( + transaction: InvestmentTransaction +): Promise { + console.log('deleteExistingInvestmentTransaction', transaction); + + try { + await serverClient.graphql({ + query: deleteInvestmentTransaction, + variables: { + input: { + pk: transaction.pk, + }, + }, + }); + } catch (err: unknown) { + if (err instanceof Error) { + return { errors: { _form: [err.message] } }; + } else { + return { errors: { _form: ['An unknown error occurred'] } }; + } + } + + revalidatePath('/', 'layout'); + redirect(`/accounts/${transaction.accountId}`); +} diff --git a/frontend/src/actions/index.ts b/frontend/src/actions/index.ts index c8d986c3..554e3636 100644 --- a/frontend/src/actions/index.ts +++ b/frontend/src/actions/index.ts @@ -6,7 +6,8 @@ export { createNewBankTransaction } from './create-bank-transaction'; export { createNewInvestmentTransaction } from './create-investment-transaction'; export { editExistingBankTransaction } from './edit-bank-transaction'; export { editExistingInvestmentTransaction } from './edit-investment-transaction'; -export { deleteExistingTransaction } from './delete-transaction'; +export { deleteExistingBankTransaction } from './delete-bank-transaction'; +export { deleteExistingInvestmentTransaction } from './delete-investment-transaction'; export { createNewCategory } from './create-category'; export { editExistingCategory } from './edit-category'; diff --git a/frontend/src/app/(main)/(bank-transactions)/banking-actions.tsx b/frontend/src/app/(main)/(bank-transactions)/banking-actions.tsx new file mode 100644 index 00000000..9618b490 --- /dev/null +++ b/frontend/src/app/(main)/(bank-transactions)/banking-actions.tsx @@ -0,0 +1,97 @@ +'use client'; + +import { Edit, MoreHorizontal, Trash } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; +import { useOpenBankTransaction } from '@/hooks/use-open-bank-transaction'; +import { BankTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; +import { deleteExistingBankTransaction } from '@/actions'; +import { useState } from 'react'; +import { toast } from 'sonner'; +import DeleteItem from '@/components/delete-item'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; + +type TransactionsProps = { + transaction: BankTransaction; +}; + +export const Actions = ({ transaction }: TransactionsProps) => { + const [isOpen, setOpen] = useState(false); + const [isPending, setPending] = useState(false); + + const queryClient = useQueryClient(); + + const { onOpen: onBankingOpen } = useOpenBankTransaction(); + + const handleClose = () => { + setOpen(false); + }; + + const mutation = useMutation({ + mutationFn: deleteExistingBankTransaction, + onSuccess: async () => { + setPending(false); + handleClose(); + + toast.success('Transaction deleted successfully 🎉', { + id: 'delete-transaction', + }); + + await queryClient.invalidateQueries({ queryKey: ['bank-transactions'] }); + }, + onError: (error) => { + setPending(false); + + toast.error('Failed to delete transaction', { + id: 'delete-bank-transaction', + }); + }, + }); + + const handleConfirm = async () => { + setPending(true); + + toast.loading('Deleting transaction...', { id: 'delete-bank-transaction' }); + + mutation.mutate(transaction); + }; + + const handleDelete = () => { + setOpen(true); + }; + + const handleOpen = () => { + onBankingOpen(transaction); + }; + + return ( + <> + + + + + + + + + handleOpen()}> + + Edit + + + + Delete + + + + + ); +}; diff --git a/frontend/src/app/(main)/(transactions)/banking-columns.tsx b/frontend/src/app/(main)/(bank-transactions)/banking-columns.tsx similarity index 97% rename from frontend/src/app/(main)/(transactions)/banking-columns.tsx rename to frontend/src/app/(main)/(bank-transactions)/banking-columns.tsx index ebb8e7a7..29da0237 100644 --- a/frontend/src/app/(main)/(transactions)/banking-columns.tsx +++ b/frontend/src/app/(main)/(bank-transactions)/banking-columns.tsx @@ -2,7 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { BankTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; -import { Actions } from '@/app/(main)/(transactions)/actions'; +import { Actions } from '@/app/(main)/(bank-transactions)/banking-actions'; import { Checkbox } from '@/components/ui/checkbox'; import { Button } from '@/components/ui/button'; import { ArrowUpDown } from 'lucide-react'; diff --git a/frontend/src/app/(main)/(transactions)/actions.tsx b/frontend/src/app/(main)/(investment-transactions)/investment-actions.tsx similarity index 75% rename from frontend/src/app/(main)/(transactions)/actions.tsx rename to frontend/src/app/(main)/(investment-transactions)/investment-actions.tsx index 7b529808..a7b8338a 100644 --- a/frontend/src/app/(main)/(transactions)/actions.tsx +++ b/frontend/src/app/(main)/(investment-transactions)/investment-actions.tsx @@ -3,17 +3,16 @@ import { Edit, MoreHorizontal, Trash } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; -import { useOpenBankTransaction } from '@/hooks/use-open-bank-transaction'; import { useOpenInvestmentTransaction } from '@/hooks/use-open-investment-transaction'; -import { BankTransaction, InvestmentTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; -import { deleteExistingTransaction } from '@/actions'; +import { InvestmentTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; +import { deleteExistingInvestmentTransaction } from '@/actions'; import { useState } from 'react'; import { toast } from 'sonner'; import DeleteItem from '@/components/delete-item'; import { useMutation, useQueryClient } from '@tanstack/react-query'; type TransactionsProps = { - transaction: BankTransaction | InvestmentTransaction; + transaction: InvestmentTransaction; }; export const Actions = ({ transaction }: TransactionsProps) => { @@ -22,7 +21,6 @@ export const Actions = ({ transaction }: TransactionsProps) => { const queryClient = useQueryClient(); - const { onOpen: onBankingOpen } = useOpenBankTransaction(); const { onOpen: onInvestmentOpen } = useOpenInvestmentTransaction(); const handleClose = () => { @@ -30,7 +28,7 @@ export const Actions = ({ transaction }: TransactionsProps) => { }; const mutation = useMutation({ - mutationFn: deleteExistingTransaction, + mutationFn: deleteExistingInvestmentTransaction, onSuccess: async () => { setPending(false); handleClose(); @@ -39,7 +37,6 @@ export const Actions = ({ transaction }: TransactionsProps) => { id: 'delete-transaction', }); - await queryClient.invalidateQueries({ queryKey: ['bank-transactions'] }); await queryClient.invalidateQueries({ queryKey: ['investment-transactions'] }); }, onError: (error) => { @@ -54,7 +51,7 @@ export const Actions = ({ transaction }: TransactionsProps) => { const handleConfirm = async () => { setPending(true); - toast.loading('Deleting transaction...', { id: 'delete-transaction' }); + toast.loading('Deleting transaction...', { id: 'delete-investment-transaction' }); mutation.mutate(transaction); }; @@ -64,11 +61,7 @@ export const Actions = ({ transaction }: TransactionsProps) => { }; const handleOpen = () => { - if (transaction.entity === 'bank-transaction') { - onBankingOpen(transaction as BankTransaction); - } else if (transaction.entity === 'investment-transaction') { - onInvestmentOpen(transaction as InvestmentTransaction); - } + onInvestmentOpen(transaction); }; return ( diff --git a/frontend/src/app/(main)/(transactions)/investment-columns.tsx b/frontend/src/app/(main)/(investment-transactions)/investment-columns.tsx similarity index 95% rename from frontend/src/app/(main)/(transactions)/investment-columns.tsx rename to frontend/src/app/(main)/(investment-transactions)/investment-columns.tsx index eac34396..3fdb76b5 100644 --- a/frontend/src/app/(main)/(transactions)/investment-columns.tsx +++ b/frontend/src/app/(main)/(investment-transactions)/investment-columns.tsx @@ -2,7 +2,7 @@ import { ColumnDef } from '@tanstack/react-table'; import { InvestmentTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; -import { Actions } from '@/app/(main)/(transactions)/actions'; +import { Actions } from '@/app/(main)/(investment-transactions)/investment-actions'; import { Checkbox } from '@/components/ui/checkbox'; export const investmentColumns: ColumnDef[] = [ diff --git a/frontend/src/components/data-table.tsx b/frontend/src/components/data-table.tsx index ac7f5c7b..6523fe80 100644 --- a/frontend/src/components/data-table.tsx +++ b/frontend/src/components/data-table.tsx @@ -18,7 +18,7 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { toast } from 'sonner'; -import { deleteExistingAccount, deleteExistingTransaction } from '@/actions'; +import { deleteExistingAccount, deleteExistingBankTransaction, deleteExistingInvestmentTransaction } from '@/actions'; import { Account, BankTransaction, InvestmentTransaction } from '@/../../backend/src/appsync/api/codegen/appsync'; import DeleteItem from './delete-item'; import { Card, CardContent, CardHeader, CardTitle } from './ui/card'; @@ -60,13 +60,13 @@ export function DataTable({ title, columns, data, onClick, filter }; const handleConfirm = async () => { - table.getFilteredSelectedRowModel().rows.forEach(async (row: any) => { - if (row.original.entity === 'account') { + table.getFilteredSelectedRowModel().rows.forEach(async (row: { original: TData }) => { + if ((row.original as Account).entity === 'account') { await deleteExistingAccount((row.original as Account).accountId); - } else if (row.original.entity === 'bank-transaction') { - await deleteExistingTransaction(row.original as BankTransaction); - } else if (row.original.entity === 'investment-transaction') { - await deleteExistingTransaction(row.original as InvestmentTransaction); + } else if ((row.original as BankTransaction).entity === 'bank-transaction') { + await deleteExistingBankTransaction(row.original as BankTransaction); + } else if ((row.original as InvestmentTransaction).entity === 'investment-transaction') { + await deleteExistingInvestmentTransaction(row.original as InvestmentTransaction); } }); diff --git a/frontend/src/features/banking-transactions/index.tsx b/frontend/src/features/banking-transactions/index.tsx index ad22f7af..228e4b5d 100644 --- a/frontend/src/features/banking-transactions/index.tsx +++ b/frontend/src/features/banking-transactions/index.tsx @@ -1,7 +1,7 @@ 'use client'; import { DataTable } from '@/components/data-table'; -import { bankingColumns } from '@/app/(main)/(transactions)/banking-columns'; +import { bankingColumns } from '@/app/(main)/(bank-transactions)/banking-columns'; import { BankTransaction } from '../../../../backend/src/appsync/api/codegen/appsync'; import { useNewTransaction } from '@/hooks/use-new-transaction'; diff --git a/frontend/src/features/investment-transactions/index.tsx b/frontend/src/features/investment-transactions/index.tsx index cacbacec..90469cb6 100644 --- a/frontend/src/features/investment-transactions/index.tsx +++ b/frontend/src/features/investment-transactions/index.tsx @@ -1,7 +1,7 @@ 'use client'; import { DataTable } from '@/components/data-table'; -import { investmentColumns } from '@/app/(main)/(transactions)/investment-columns'; +import { investmentColumns } from '@/app/(main)/(investment-transactions)/investment-columns'; import { InvestmentTransaction } from '../../../../backend/src/appsync/api/codegen/appsync'; import { useNewTransaction } from '@/hooks/use-new-transaction';