diff --git a/eslint.config.mjs b/eslint.config.mjs index 09a55d787..029ba22cd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -115,7 +115,7 @@ export default defineConfig([ eslintImportResolverTypescript.createTypeScriptImportResolver({ project: [ 'lambdas/*/tsconfig.json', - 'tests/tsconfig.json', + 'lambdas/*/*/tsconfig.json', 'tests/tsconfig.json', 'internal/*/tsconfig.json', ], }), diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index b21ae6675..2d1508de4 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -60,9 +60,9 @@ No requirements. | Name | Source | Version | | ---- | ------ | ------- | -| [amendment\_event\_transformer](#module\_amendment\_event\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | +| [amendment\_event\_transformer](#module\_amendment\_event\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | | [amendments\_queue](#module\_amendments\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.5/terraform-sqs.zip | n/a | -| [authorizer\_lambda](#module\_authorizer\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | +| [authorizer\_lambda](#module\_authorizer\_lambda) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | | [ddb\_alarms\_idempotency](#module\_ddb\_alarms\_idempotency) | ../../modules/alarms-ddb | n/a | | [ddb\_alarms\_letter\_queue](#module\_ddb\_alarms\_letter\_queue) | ../../modules/alarms-ddb | n/a | | [ddb\_alarms\_letters](#module\_ddb\_alarms\_letters) | ../../modules/alarms-ddb | n/a | @@ -71,30 +71,33 @@ No requirements. | [domain\_truststore](#module\_domain\_truststore) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.0.6/terraform-s3bucket.zip | n/a | | [eventpub](#module\_eventpub) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/5.0.6/terraform-eventpub.zip | n/a | | [eventsub](#module\_eventsub) | ../../modules/eventsub | n/a | -| [get\_letter](#module\_get\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [get\_letter\_data](#module\_get\_letter\_data) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [get\_letters](#module\_get\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [get\_mi](#module\_get\_mi) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a | -| [get\_status](#module\_get\_status) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | +| [get\_letter](#module\_get\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [get\_letter\_data](#module\_get\_letter\_data) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [get\_letters](#module\_get\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [get\_mi](#module\_get\_mi) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [get\_status](#module\_get\_status) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | | [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-kms.zip | n/a | | [lambda\_alarms](#module\_lambda\_alarms) | ../../modules/alarms-lambda | n/a | | [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.5/terraform-sqs.zip | n/a | -| [letter\_updates\_transformer](#module\_letter\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [mi\_updates\_transformer](#module\_mi\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [post\_letters](#module\_post\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [post\_mi](#module\_post\_mi) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | +| [letter\_updates\_transformer](#module\_letter\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [mi\_updates\_transformer](#module\_mi\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [populate\_sameday\_breaches](#module\_populate\_sameday\_breaches) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [populate\_standard\_breaches](#module\_populate\_standard\_breaches) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [populate\_supplier\_config\_cache](#module\_populate\_supplier\_config\_cache) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [post\_letters](#module\_post\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [post\_mi](#module\_post\_mi) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | | [s3bucket\_test\_letters](#module\_s3bucket\_test\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-s3bucket.zip | n/a | | [sqs\_alarms](#module\_sqs\_alarms) | ../../modules/alarms-sqs | n/a | | [sqs\_letter\_updates](#module\_sqs\_letter\_updates) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.5/terraform-sqs.zip | n/a | | [sqs\_supplier\_allocator](#module\_sqs\_supplier\_allocator) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.5/terraform-sqs.zip | n/a | | [sqs\_supplier\_config](#module\_sqs\_supplier\_config) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/3.1.5/terraform-sqs.zip | n/a | -| [supplier\_allocator](#module\_supplier\_allocator) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [supplier\_config\_ingress](#module\_supplier\_config\_ingress) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.29/terraform-lambda.zip | n/a | -| [supplier\_mock](#module\_supplier\_mock) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.5/terraform-lambda.zip | n/a | +| [supplier\_allocator](#module\_supplier\_allocator) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [supplier\_config\_ingress](#module\_supplier\_config\_ingress) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [supplier\_mock](#module\_supplier\_mock) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | | [supplier\_ssl](#module\_supplier\_ssl) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-ssl.zip | n/a | -| [update\_letter\_queue](#module\_update\_letter\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | -| [upsert\_letter](#module\_upsert\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/4.0.2/terraform-lambda.zip | n/a | +| [update\_letter\_queue](#module\_update\_letter\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | +| [upsert\_letter](#module\_upsert\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip | n/a | ## Outputs | Name | Description | diff --git a/infrastructure/terraform/components/api/iam_role_letter_sla_breaches.tf b/infrastructure/terraform/components/api/iam_role_letter_sla_breaches.tf new file mode 100644 index 000000000..97a35bad2 --- /dev/null +++ b/infrastructure/terraform/components/api/iam_role_letter_sla_breaches.tf @@ -0,0 +1,17 @@ +resource "aws_iam_role" "letter_sla_breaches" { + name = "${local.csi}-letter-sla-breaches-sfn" + description = "Execution role for the letter SLA breaches state machine" + assume_role_policy = data.aws_iam_policy_document.letter_sla_breaches_trust_policy.json +} + +data "aws_iam_policy_document" "letter_sla_breaches_trust_policy" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["states.amazonaws.com"] + } + } +} diff --git a/infrastructure/terraform/components/api/iam_role_policy_letter_sla_breaches.tf b/infrastructure/terraform/components/api/iam_role_policy_letter_sla_breaches.tf new file mode 100644 index 000000000..d893cd8b0 --- /dev/null +++ b/infrastructure/terraform/components/api/iam_role_policy_letter_sla_breaches.tf @@ -0,0 +1,25 @@ +resource "aws_iam_role_policy" "letter_sla_breaches" { + name = "${local.csi}-letter-sla-breaches-sfn" + role = aws_iam_role.letter_sla_breaches.id + policy = data.aws_iam_policy_document.letter_sla_breaches_policy.json +} + +data "aws_iam_policy_document" "letter_sla_breaches_policy" { + statement { + sid = "AllowListOwnExecutions" + effect = "Allow" + actions = ["states:ListExecutions"] + resources = [local.letter_sla_breaches_state_machine_arn] + } + + statement { + sid = "AllowInvokeLambdas" + effect = "Allow" + actions = ["lambda:InvokeFunction"] + resources = [ + module.populate_supplier_config_cache.function_arn, + module.populate_sameday_breaches.function_arn, + module.populate_standard_breaches.function_arn, + ] + } +} diff --git a/infrastructure/terraform/components/api/locals.tf b/infrastructure/terraform/components/api/locals.tf index 6b4d90305..18c52e680 100644 --- a/infrastructure/terraform/components/api/locals.tf +++ b/infrastructure/terraform/components/api/locals.tf @@ -52,4 +52,7 @@ locals { var.region, var.csoc_destination_account ) + + letter_sla_breaches_state_machine_name = "${local.csi}-letter-sla-breaches" + letter_sla_breaches_state_machine_arn = "arn:aws:states:${var.region}:${var.aws_account_id}:stateMachine:${local.letter_sla_breaches_state_machine_name}" } diff --git a/infrastructure/terraform/components/api/module_lambda_populate_sameday_breaches.tf b/infrastructure/terraform/components/api/module_lambda_populate_sameday_breaches.tf new file mode 100644 index 000000000..020c4dd1c --- /dev/null +++ b/infrastructure/terraform/components/api/module_lambda_populate_sameday_breaches.tf @@ -0,0 +1,55 @@ +module "populate_sameday_breaches" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip" + + function_name = "populate_sameday_breaches" + description = "Populates same-day breaches for the letter SLA breaches state machine" + + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + group = var.group + + log_retention_in_days = var.log_retention_in_days + kms_key_arn = module.kms.key_arn + + iam_policy_document = { + body = data.aws_iam_policy_document.populate_sameday_breaches_lambda.json + } + + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_code_base_path = local.aws_lambda_functions_dir_path + function_code_dir = "letter-sla-breaches/populate-sameday-breaches/dist" + function_include_common = true + handler_function_name = "populateSamedayBreachesHandler" + runtime = "nodejs22.x" + memory = 128 + timeout = 29 + log_level = var.log_level + + force_lambda_code_deploy = var.force_lambda_code_deploy + enable_lambda_insights = false + + log_destination_arn = local.destination_arn + odin_log_destination_arn = local.odin_destination_arn + log_subscription_role_arn = local.acct.log_subscription_role_arn + + lambda_env_vars = {} +} + +data "aws_iam_policy_document" "populate_sameday_breaches_lambda" { + statement { + sid = "KMSPermissions" + effect = "Allow" + + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey", + ] + + resources = [ + module.kms.key_arn, + ] + } +} diff --git a/infrastructure/terraform/components/api/module_lambda_populate_standard_breaches.tf b/infrastructure/terraform/components/api/module_lambda_populate_standard_breaches.tf new file mode 100644 index 000000000..f5665bb82 --- /dev/null +++ b/infrastructure/terraform/components/api/module_lambda_populate_standard_breaches.tf @@ -0,0 +1,55 @@ +module "populate_standard_breaches" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip" + + function_name = "populate_standard_breaches" + description = "Populates standard breaches for the letter SLA breaches state machine" + + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + group = var.group + + log_retention_in_days = var.log_retention_in_days + kms_key_arn = module.kms.key_arn + + iam_policy_document = { + body = data.aws_iam_policy_document.populate_standard_breaches_lambda.json + } + + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_code_base_path = local.aws_lambda_functions_dir_path + function_code_dir = "letter-sla-breaches/populate-standard-breaches/dist" + function_include_common = true + handler_function_name = "populateStandardBreachesHandler" + runtime = "nodejs22.x" + memory = 128 + timeout = 29 + log_level = var.log_level + + force_lambda_code_deploy = var.force_lambda_code_deploy + enable_lambda_insights = false + + log_destination_arn = local.destination_arn + odin_log_destination_arn = local.odin_destination_arn + log_subscription_role_arn = local.acct.log_subscription_role_arn + + lambda_env_vars = {} +} + +data "aws_iam_policy_document" "populate_standard_breaches_lambda" { + statement { + sid = "KMSPermissions" + effect = "Allow" + + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey", + ] + + resources = [ + module.kms.key_arn, + ] + } +} diff --git a/infrastructure/terraform/components/api/module_lambda_populate_supplier_config_cache.tf b/infrastructure/terraform/components/api/module_lambda_populate_supplier_config_cache.tf new file mode 100644 index 000000000..57bf707fa --- /dev/null +++ b/infrastructure/terraform/components/api/module_lambda_populate_supplier_config_cache.tf @@ -0,0 +1,72 @@ +module "populate_supplier_config_cache" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/6.0.5/terraform-lambda.zip" + + function_name = "populate_supplier_config_cache" + description = "Populates the supplier config cache for the letter SLA breaches state machine" + + aws_account_id = var.aws_account_id + component = var.component + environment = var.environment + project = var.project + region = var.region + group = var.group + + log_retention_in_days = var.log_retention_in_days + kms_key_arn = module.kms.key_arn + + iam_policy_document = { + body = data.aws_iam_policy_document.populate_supplier_config_cache_lambda.json + } + + function_s3_bucket = local.acct.s3_buckets["lambda_function_artefacts"]["id"] + function_code_base_path = local.aws_lambda_functions_dir_path + function_code_dir = "letter-sla-breaches/populate-supplier-config-cache/dist" + function_include_common = true + handler_function_name = "populateSupplierConfigCacheHandler" + runtime = "nodejs22.x" + memory = 128 + timeout = 29 + log_level = var.log_level + + force_lambda_code_deploy = var.force_lambda_code_deploy + enable_lambda_insights = false + + log_destination_arn = local.destination_arn + odin_log_destination_arn = local.odin_destination_arn + log_subscription_role_arn = local.acct.log_subscription_role_arn + + lambda_env_vars = { + SUPPLIER_CONFIG_TABLE_NAME = aws_dynamodb_table.supplier-configuration.name + EVENT_CACHE_BUCKET_NAME = local.eventsub_event_cache_bucket_name + } +} + +data "aws_iam_policy_document" "populate_supplier_config_cache_lambda" { + statement { + sid = "KMSPermissions" + effect = "Allow" + + actions = [ + "kms:Decrypt", + "kms:GenerateDataKey", + ] + + resources = [ + module.kms.key_arn, + ] + } + + statement { + sid = "AllowQuerySupplierConfigTable" + effect = "Allow" + actions = ["dynamodb:Query"] + resources = [aws_dynamodb_table.supplier-configuration.arn] + } + + statement { + sid = "AllowWriteSupplierConfigCache" + effect = "Allow" + actions = ["s3:PutObject"] + resources = ["arn:aws:s3:::${local.eventsub_event_cache_bucket_name}/supplier_config_cache/*"] + } +} diff --git a/infrastructure/terraform/components/api/resources/letter_sla_breaches.json b/infrastructure/terraform/components/api/resources/letter_sla_breaches.json new file mode 100644 index 000000000..725b8eaf3 --- /dev/null +++ b/infrastructure/terraform/components/api/resources/letter_sla_breaches.json @@ -0,0 +1,77 @@ +{ + "Comment": "Identifies letters in breach of SLA for a given date (defaults to today)", + "QueryLanguage": "JSONata", + "StartAt": "CheckForRunningExecutions", + "States": { + "AlreadyRunning?": { + "Choices": [ + { + "Condition": "{% $count($states.input.Executions) > 1 %}", + "Next": "ExitAlreadyRunning" + } + ], + "Default": "PopulateSupplierConfigCache", + "Type": "Choice" + }, + "CheckForRunningExecutions": { + "Arguments": { + "StateMachineArn": "${STATE_MACHINE_ARN}", + "StatusFilter": "RUNNING" + }, + "Assign": { + "date": "{% $exists($states.context.Execution.Input.date) ? $states.context.Execution.Input.date : $substring($states.context.Execution.StartTime, 0, 10) %}" + }, + "Next": "AlreadyRunning?", + "Resource": "arn:aws:states:::aws-sdk:sfn:listExecutions", + "Type": "Task" + }, + "ExitAlreadyRunning": { + "Type": "Succeed" + }, + "PopulateSamedayBreaches": { + "Arguments": { + "FunctionName": "${POPULATE_SAMEDAY_BREACHES_FUNCTION_ARN}", + "Payload": { + "date": "{% $date %}" + } + }, + "Next": "PopulateStandardBreaches", + "Output": { + "populateSamedayBreaches": "{% $states.result.Payload %}", + "populateSupplierConfigCache": "{% $states.input.populateSupplierConfigCache %}" + }, + "Resource": "arn:aws:states:::lambda:invoke", + "Type": "Task" + }, + "PopulateStandardBreaches": { + "Arguments": { + "FunctionName": "${POPULATE_STANDARD_BREACHES_FUNCTION_ARN}", + "Payload": { + "date": "{% $date %}" + } + }, + "End": true, + "Output": { + "populateSamedayBreaches": "{% $states.input.populateSamedayBreaches %}", + "populateStandardBreaches": "{% $states.result.Payload %}", + "populateSupplierConfigCache": "{% $states.input.populateSupplierConfigCache %}" + }, + "Resource": "arn:aws:states:::lambda:invoke", + "Type": "Task" + }, + "PopulateSupplierConfigCache": { + "Arguments": { + "FunctionName": "${POPULATE_SUPPLIER_CONFIG_CACHE_FUNCTION_ARN}", + "Payload": { + "date": "{% $date %}" + } + }, + "Next": "PopulateSamedayBreaches", + "Output": { + "populateSupplierConfigCache": "{% $states.result.Payload %}" + }, + "Resource": "arn:aws:states:::lambda:invoke", + "Type": "Task" + } + } +} diff --git a/infrastructure/terraform/components/api/sfn_state_machine_letter_sla_breaches.tf b/infrastructure/terraform/components/api/sfn_state_machine_letter_sla_breaches.tf new file mode 100644 index 000000000..19d726103 --- /dev/null +++ b/infrastructure/terraform/components/api/sfn_state_machine_letter_sla_breaches.tf @@ -0,0 +1,11 @@ +resource "aws_sfn_state_machine" "letter_sla_breaches" { + name = local.letter_sla_breaches_state_machine_name + role_arn = aws_iam_role.letter_sla_breaches.arn + + definition = templatefile("${path.module}/resources/letter_sla_breaches.json", { + STATE_MACHINE_ARN = local.letter_sla_breaches_state_machine_arn + POPULATE_SUPPLIER_CONFIG_CACHE_FUNCTION_ARN = module.populate_supplier_config_cache.function_arn + POPULATE_SAMEDAY_BREACHES_FUNCTION_ARN = module.populate_sameday_breaches.function_arn + POPULATE_STANDARD_BREACHES_FUNCTION_ARN = module.populate_standard_breaches.function_arn + }) +} diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/.gitignore b/lambdas/letter-sla-breaches/populate-sameday-breaches/.gitignore new file mode 100644 index 000000000..fc5a7859a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/.gitignore @@ -0,0 +1,5 @@ +coverage +node_modules +dist +.reports +.aws-sam diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/jest.config.ts b/lambdas/letter-sla-breaches/populate-sameday-breaches/jest.config.ts new file mode 100644 index 000000000..ec5a312bb --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/jest.config.ts @@ -0,0 +1,46 @@ +export const baseJestConfig = { + preset: "ts-jest", + extensionsToTreatAsEsm: [".ts"], + transform: { + "^.+\\.ts$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, + + clearMocks: true, + collectCoverage: true, + coverageDirectory: "./.reports/unit/coverage", + coverageProvider: "babel", + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + coveragePathIgnorePatterns: ["/__tests__/"], + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], + + reporters: [ + "default", + [ + "jest-html-reporter", + { + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", + includeFailureMsg: true, + }, + ], + ], + + testEnvironment: "node", +}; + +export default baseJestConfig; diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/package.json b/lambdas/letter-sla-breaches/populate-sameday-breaches/package.json new file mode 100644 index 000000000..127c212c3 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/package.json @@ -0,0 +1,15 @@ +{ + "dependencies": { + "esbuild": "0.28.2" + }, + "name": "nhs-notify-supplier-api-populate-sameday-breaches", + "private": true, + "scripts": { + "lambda-build": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --loader:.node=file --entry-names=[name] --outdir=dist src/index.ts", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "test:unit": "jest", + "typecheck": "tsc --noEmit" + }, + "version": "0.0.1" +} diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/src/__tests__/populate-sameday-breaches.test.ts b/lambdas/letter-sla-breaches/populate-sameday-breaches/src/__tests__/populate-sameday-breaches.test.ts new file mode 100644 index 000000000..50492a04a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/src/__tests__/populate-sameday-breaches.test.ts @@ -0,0 +1,12 @@ +import populateSamedayBreaches from "../handler/populate-sameday-breaches"; + +describe("populateSamedayBreaches", () => { + it("returns a success result", async () => { + const result = await populateSamedayBreaches({ date: "2026-10-08" }); + + expect(result).toEqual({ + status: "SUCCESS", + message: "populate-sameday-breaches invoked successfully", + }); + }); +}); diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/src/handler/populate-sameday-breaches.ts b/lambdas/letter-sla-breaches/populate-sameday-breaches/src/handler/populate-sameday-breaches.ts new file mode 100644 index 000000000..f63d70492 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/src/handler/populate-sameday-breaches.ts @@ -0,0 +1,18 @@ +export type PopulateSamedayBreachesEvent = { + date: string; +}; + +export type PopulateSamedayBreachesResult = { + status: "SUCCESS"; + message: string; +}; + +// Placeholder: cache population is not yet implemented. +export default async function populateSamedayBreaches( + _event: PopulateSamedayBreachesEvent, +): Promise { + return { + status: "SUCCESS", + message: "populate-sameday-breaches invoked successfully", + }; +} diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/src/index.ts b/lambdas/letter-sla-breaches/populate-sameday-breaches/src/index.ts new file mode 100644 index 000000000..3143567ed --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/src/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import-x/prefer-default-export +export { default as populateSamedayBreachesHandler } from "./handler/populate-sameday-breaches"; diff --git a/lambdas/letter-sla-breaches/populate-sameday-breaches/tsconfig.json b/lambdas/letter-sla-breaches/populate-sameday-breaches/tsconfig.json new file mode 100644 index 000000000..4a11b255a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-sameday-breaches/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "ignoreDeprecations": "5.0" + }, + "extends": "../../../tsconfig.base.json", + "include": [ + "src/**/*", + "jest.config.ts" + ] +} diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/.gitignore b/lambdas/letter-sla-breaches/populate-standard-breaches/.gitignore new file mode 100644 index 000000000..fc5a7859a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/.gitignore @@ -0,0 +1,5 @@ +coverage +node_modules +dist +.reports +.aws-sam diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/jest.config.ts b/lambdas/letter-sla-breaches/populate-standard-breaches/jest.config.ts new file mode 100644 index 000000000..ec5a312bb --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/jest.config.ts @@ -0,0 +1,46 @@ +export const baseJestConfig = { + preset: "ts-jest", + extensionsToTreatAsEsm: [".ts"], + transform: { + "^.+\\.ts$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, + + clearMocks: true, + collectCoverage: true, + coverageDirectory: "./.reports/unit/coverage", + coverageProvider: "babel", + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + coveragePathIgnorePatterns: ["/__tests__/"], + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], + + reporters: [ + "default", + [ + "jest-html-reporter", + { + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", + includeFailureMsg: true, + }, + ], + ], + + testEnvironment: "node", +}; + +export default baseJestConfig; diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/package.json b/lambdas/letter-sla-breaches/populate-standard-breaches/package.json new file mode 100644 index 000000000..8875e4acc --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/package.json @@ -0,0 +1,15 @@ +{ + "dependencies": { + "esbuild": "0.28.2" + }, + "name": "nhs-notify-supplier-api-populate-standard-breaches", + "private": true, + "scripts": { + "lambda-build": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --loader:.node=file --entry-names=[name] --outdir=dist src/index.ts", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "test:unit": "jest", + "typecheck": "tsc --noEmit" + }, + "version": "0.0.1" +} diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/src/__tests__/populate-standard-breaches.test.ts b/lambdas/letter-sla-breaches/populate-standard-breaches/src/__tests__/populate-standard-breaches.test.ts new file mode 100644 index 000000000..f64093251 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/src/__tests__/populate-standard-breaches.test.ts @@ -0,0 +1,12 @@ +import populateStandardBreaches from "../handler/populate-standard-breaches"; + +describe("populateStandardBreaches", () => { + it("returns a success result", async () => { + const result = await populateStandardBreaches({ date: "2026-10-08" }); + + expect(result).toEqual({ + status: "SUCCESS", + message: "populate-standard-breaches invoked successfully", + }); + }); +}); diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/src/handler/populate-standard-breaches.ts b/lambdas/letter-sla-breaches/populate-standard-breaches/src/handler/populate-standard-breaches.ts new file mode 100644 index 000000000..1bcc2318c --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/src/handler/populate-standard-breaches.ts @@ -0,0 +1,18 @@ +export type PopulateStandardBreachesEvent = { + date: string; +}; + +export type PopulateStandardBreachesResult = { + status: "SUCCESS"; + message: string; +}; + +// Placeholder: cache population is not yet implemented. +export default async function populateStandardBreaches( + _event: PopulateStandardBreachesEvent, +): Promise { + return { + status: "SUCCESS", + message: "populate-standard-breaches invoked successfully", + }; +} diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/src/index.ts b/lambdas/letter-sla-breaches/populate-standard-breaches/src/index.ts new file mode 100644 index 000000000..5516fb886 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/src/index.ts @@ -0,0 +1,2 @@ +// eslint-disable-next-line import-x/prefer-default-export +export { default as populateStandardBreachesHandler } from "./handler/populate-standard-breaches"; diff --git a/lambdas/letter-sla-breaches/populate-standard-breaches/tsconfig.json b/lambdas/letter-sla-breaches/populate-standard-breaches/tsconfig.json new file mode 100644 index 000000000..4a11b255a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-standard-breaches/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "ignoreDeprecations": "5.0" + }, + "extends": "../../../tsconfig.base.json", + "include": [ + "src/**/*", + "jest.config.ts" + ] +} diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/.gitignore b/lambdas/letter-sla-breaches/populate-supplier-config-cache/.gitignore new file mode 100644 index 000000000..fc5a7859a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/.gitignore @@ -0,0 +1,5 @@ +coverage +node_modules +dist +.reports +.aws-sam diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/jest.config.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/jest.config.ts new file mode 100644 index 000000000..ec5a312bb --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/jest.config.ts @@ -0,0 +1,46 @@ +export const baseJestConfig = { + preset: "ts-jest", + extensionsToTreatAsEsm: [".ts"], + transform: { + "^.+\\.ts$": [ + "ts-jest", + { + useESM: true, + }, + ], + }, + + clearMocks: true, + collectCoverage: true, + coverageDirectory: "./.reports/unit/coverage", + coverageProvider: "babel", + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + coveragePathIgnorePatterns: ["/__tests__/"], + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], + + reporters: [ + "default", + [ + "jest-html-reporter", + { + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", + includeFailureMsg: true, + }, + ], + ], + + testEnvironment: "node", +}; + +export default baseJestConfig; diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/package.json b/lambdas/letter-sla-breaches/populate-supplier-config-cache/package.json new file mode 100644 index 000000000..034e0301b --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/package.json @@ -0,0 +1,18 @@ +{ + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.1138.0", + "@aws-sdk/client-s3": "^3.1138.0", + "@aws-sdk/lib-dynamodb": "^3.1138.0", + "esbuild": "0.28.2" + }, + "name": "nhs-notify-supplier-api-populate-supplier-config-cache", + "private": true, + "scripts": { + "lambda-build": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --loader:.node=file --entry-names=[name] --outdir=dist src/index.ts", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "test:unit": "jest", + "typecheck": "tsc --noEmit" + }, + "version": "0.0.1" +} diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/__tests__/entity-cache.test.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/__tests__/entity-cache.test.ts new file mode 100644 index 000000000..1dac234a9 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/__tests__/entity-cache.test.ts @@ -0,0 +1,72 @@ +import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { DynamoDBDocumentClient, QueryCommand } from "@aws-sdk/lib-dynamodb"; +import populateEntityCache, { EntityCacheDeps } from "../handler/entity-cache"; + +function makeDeps(ddbSend: jest.Mock, s3Send: jest.Mock): EntityCacheDeps { + return { + ddbClient: { send: ddbSend } as unknown as DynamoDBDocumentClient, + s3Client: { send: s3Send } as unknown as S3Client, + env: { + SUPPLIER_CONFIG_TABLE_NAME: "config-table", + EVENT_CACHE_BUCKET_NAME: "cache-bucket", + }, + }; +} + +describe("populateEntityCache", () => { + it("queries all pages for the entity and writes them to S3", async () => { + const ddbSend = jest + .fn() + .mockResolvedValueOnce({ + Items: [{ pk: "ENTITY#supplier", sk: "ID#1" }], + LastEvaluatedKey: { pk: "ENTITY#supplier", sk: "ID#1" }, + }) + .mockResolvedValueOnce({ + Items: [{ pk: "ENTITY#supplier", sk: "ID#2" }], + }); + const s3Send = jest.fn().mockResolvedValue({}); + + const count = await populateEntityCache( + makeDeps(ddbSend, s3Send), + "supplier", + ); + + expect(count).toBe(2); + expect(ddbSend).toHaveBeenCalledTimes(2); + const firstQuery = ddbSend.mock.calls[0][0] as QueryCommand; + expect(firstQuery.input).toEqual({ + TableName: "config-table", + KeyConditionExpression: "pk = :pk", + ExpressionAttributeValues: { ":pk": "ENTITY#supplier" }, + ExclusiveStartKey: undefined, + }); + const secondQuery = ddbSend.mock.calls[1][0] as QueryCommand; + expect(secondQuery.input.ExclusiveStartKey).toEqual({ + pk: "ENTITY#supplier", + sk: "ID#1", + }); + + const put = s3Send.mock.calls[0][0] as PutObjectCommand; + expect(put.input.Bucket).toBe("cache-bucket"); + expect(put.input.Key).toBe("supplier_config_cache/supplier.json"); + expect(JSON.parse(put.input.Body as string)).toEqual([ + { pk: "ENTITY#supplier", sk: "ID#1" }, + { pk: "ENTITY#supplier", sk: "ID#2" }, + ]); + }); + + it("writes an empty file when no rows are returned", async () => { + const ddbSend = jest.fn().mockResolvedValue({}); + const s3Send = jest.fn().mockResolvedValue({}); + + const count = await populateEntityCache( + makeDeps(ddbSend, s3Send), + "volume-group", + ); + + expect(count).toBe(0); + const put = s3Send.mock.calls[0][0] as PutObjectCommand; + expect(put.input.Key).toBe("supplier_config_cache/volume-group.json"); + expect(put.input.Body).toBe("[]"); + }); +}); diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/__tests__/populate-supplier-config-cache.test.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/__tests__/populate-supplier-config-cache.test.ts new file mode 100644 index 000000000..54374eb2f --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/__tests__/populate-supplier-config-cache.test.ts @@ -0,0 +1,32 @@ +import populateEntityCache, { EntityCacheDeps } from "../handler/entity-cache"; +import createHandler, { + ENTITY_TYPES, +} from "../handler/populate-supplier-config-cache"; + +jest.mock("../handler/entity-cache"); + +describe("populateSupplierConfigCache", () => { + it("populates the cache once for each entity type and returns success", async () => { + const deps = {} as EntityCacheDeps; + const handler = createHandler(deps); + + const result = await handler({ date: "2026-10-08" }); + + expect(ENTITY_TYPES).toEqual([ + "volume-group", + "supplier-pack", + "letter-variant", + "pack-specification", + "supplier-allocation", + "supplier", + ]); + expect(populateEntityCache).toHaveBeenCalledTimes(ENTITY_TYPES.length); + for (const entityType of ENTITY_TYPES) { + expect(populateEntityCache).toHaveBeenCalledWith(deps, entityType); + } + expect(result).toEqual({ + status: "SUCCESS", + message: "populate-supplier-config-cache invoked successfully", + }); + }); +}); diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/deps.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/deps.ts new file mode 100644 index 000000000..6fdf2f926 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/deps.ts @@ -0,0 +1,15 @@ +import { S3Client } from "@aws-sdk/client-s3"; +import { DynamoDBClient } from "@aws-sdk/client-dynamodb"; +import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb"; +import { EntityCacheDeps } from "./entity-cache"; + +export default function createDependenciesContainer(): EntityCacheDeps { + return { + ddbClient: DynamoDBDocumentClient.from(new DynamoDBClient()), + s3Client: new S3Client(), + env: { + SUPPLIER_CONFIG_TABLE_NAME: process.env.SUPPLIER_CONFIG_TABLE_NAME!, + EVENT_CACHE_BUCKET_NAME: process.env.EVENT_CACHE_BUCKET_NAME!, + }, + }; +} diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/entity-cache.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/entity-cache.ts new file mode 100644 index 000000000..eab1beef6 --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/entity-cache.ts @@ -0,0 +1,49 @@ +import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; +import { + DynamoDBDocumentClient, + QueryCommand, + QueryCommandOutput, +} from "@aws-sdk/lib-dynamodb"; + +export type EntityCacheDeps = { + ddbClient: DynamoDBDocumentClient; + s3Client: S3Client; + env: { + SUPPLIER_CONFIG_TABLE_NAME: string; + EVENT_CACHE_BUCKET_NAME: string; + }; +}; + +export const CACHE_FOLDER = "supplier_config_cache"; + +export default async function populateEntityCache( + deps: EntityCacheDeps, + entityType: string, +): Promise { + const items: Record[] = []; + let exclusiveStartKey: QueryCommandOutput["LastEvaluatedKey"]; + + do { + const page: QueryCommandOutput = await deps.ddbClient.send( + new QueryCommand({ + TableName: deps.env.SUPPLIER_CONFIG_TABLE_NAME, + KeyConditionExpression: "pk = :pk", + ExpressionAttributeValues: { ":pk": `ENTITY#${entityType}` }, + ExclusiveStartKey: exclusiveStartKey, + }), + ); + items.push(...(page.Items ?? [])); + exclusiveStartKey = page.LastEvaluatedKey; + } while (exclusiveStartKey); + + await deps.s3Client.send( + new PutObjectCommand({ + Bucket: deps.env.EVENT_CACHE_BUCKET_NAME, + Key: `${CACHE_FOLDER}/${entityType}.json`, + Body: JSON.stringify(items), + ContentType: "application/json", + }), + ); + + return items.length; +} diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/populate-supplier-config-cache.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/populate-supplier-config-cache.ts new file mode 100644 index 000000000..b3c3d57fb --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/handler/populate-supplier-config-cache.ts @@ -0,0 +1,34 @@ +import populateEntityCache, { EntityCacheDeps } from "./entity-cache"; + +export type PopulateSupplierConfigCacheEvent = { + date: string; +}; + +export type PopulateSupplierConfigCacheResult = { + status: "SUCCESS"; + message: string; +}; + +export const ENTITY_TYPES = [ + "volume-group", + "supplier-pack", + "letter-variant", + "pack-specification", + "supplier-allocation", + "supplier", +]; + +export default function createHandler(deps: EntityCacheDeps) { + return async ( + _event: PopulateSupplierConfigCacheEvent, + ): Promise => { + await Promise.all( + ENTITY_TYPES.map((entityType) => populateEntityCache(deps, entityType)), + ); + + return { + status: "SUCCESS", + message: "populate-supplier-config-cache invoked successfully", + }; + }; +} diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/index.ts b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/index.ts new file mode 100644 index 000000000..fd06c3b3f --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/src/index.ts @@ -0,0 +1,7 @@ +import createDependenciesContainer from "./handler/deps"; +import createHandler from "./handler/populate-supplier-config-cache"; + +// eslint-disable-next-line import-x/prefer-default-export +export const populateSupplierConfigCacheHandler = createHandler( + createDependenciesContainer(), +); diff --git a/lambdas/letter-sla-breaches/populate-supplier-config-cache/tsconfig.json b/lambdas/letter-sla-breaches/populate-supplier-config-cache/tsconfig.json new file mode 100644 index 000000000..4a11b255a --- /dev/null +++ b/lambdas/letter-sla-breaches/populate-supplier-config-cache/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "ignoreDeprecations": "5.0" + }, + "extends": "../../../tsconfig.base.json", + "include": [ + "src/**/*", + "jest.config.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index cae5e3cea..a80f25d9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "docs", "internal/*", "lambdas/*", + "lambdas/letter-sla-breaches/*", "pact-contracts", "scripts/utilities/*", "tests", @@ -155,30 +156,6 @@ "node": ">=20.0.0" } }, - "internal/datastore/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "internal/datastore/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "internal/datastore/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -196,33 +173,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "internal/datastore/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "internal/datastore/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "internal/datastore/node_modules/@nhsdigital/nhs-notify-event-schemas-supplier-config": { "version": "1.1.1", "dependencies": { @@ -241,7 +191,7 @@ }, "internal/events": { "name": "@nhsdigital/nhs-notify-event-schemas-supplier-api", - "version": "1.0.21", + "version": "1.0.22", "license": "MIT", "dependencies": { "@asyncapi/bundler": "^1.0.2", @@ -365,30 +315,6 @@ "node": ">=20.0.0" } }, - "lambdas/api-handler/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/api-handler/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/api-handler/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -406,20 +332,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "lambdas/api-handler/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/api-handler/node_modules/@aws-sdk/middleware-sdk-sqs": { "version": "3.972.43", "license": "Apache-2.0", @@ -433,19 +345,6 @@ "node": ">=20.0.0" } }, - "lambdas/api-handler/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "lambdas/authorizer": { "name": "nhs-notify-supplier-authorizer", "version": "0.0.1", @@ -480,30 +379,6 @@ "node": ">=20.0.0" } }, - "lambdas/authorizer/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/authorizer/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/authorizer/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -521,31 +396,28 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "lambdas/authorizer/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", + "lambdas/letter-sla-breaches/populate-sameday-breaches": { + "name": "nhs-notify-supplier-api-populate-sameday-breaches", + "version": "0.0.1", "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" + "esbuild": "0.28.2" } }, - "lambdas/authorizer/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", + "lambdas/letter-sla-breaches/populate-standard-breaches": { + "name": "nhs-notify-supplier-api-populate-standard-breaches", + "version": "0.0.1", "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" + "esbuild": "0.28.2" + } + }, + "lambdas/letter-sla-breaches/populate-supplier-config-cache": { + "name": "nhs-notify-supplier-api-populate-supplier-config-cache", + "version": "0.0.1", + "dependencies": { + "@aws-sdk/client-dynamodb": "^3.1138.0", + "@aws-sdk/client-s3": "^3.1138.0", + "@aws-sdk/lib-dynamodb": "^3.1138.0", + "esbuild": "0.28.2" } }, "lambdas/letter-updates-transformer": { @@ -565,90 +437,6 @@ "zod": "^4.6.5" } }, - "lambdas/letter-updates-transformer/node_modules/@aws-sdk/client-dynamodb": { - "version": "3.1146.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1146.0.tgz", - "integrity": "sha512-3Mc8YkSu2KlgNNSuspaW+Fo0pTwX+fLYlC5ovH3yX3OoDg2RPtp3Py8KuQJr0FDlQj1tHw0K3+AtaH4NXlI3aQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/credential-provider-node": "^3.972.84", - "@aws-sdk/dynamodb-codec": "^3.973.46", - "@aws-sdk/middleware-endpoint-discovery": "^3.972.31", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/fetch-http-handler": "^5.8.0", - "@smithy/node-http-handler": "^4.12.1", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/letter-updates-transformer/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.46.tgz", - "integrity": "sha512-ApnSubn+5C6HQGP7025q9w/YiNzKwimIMksP76xVij779BCCqcmJ9poB6hQ4syY9NUxqmEQLBqY0PktX53L8iQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/letter-updates-transformer/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.11.tgz", - "integrity": "sha512-8q1ICxcDjHId3bBryuu/j+1L9y5/3uQnwzLDt5j2ElcjZSoWmFtymdJy7OjLrluSMe0Z4mq5bcH4fxBXvlEHfw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/letter-updates-transformer/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.31.tgz", - "integrity": "sha512-JqOIXupzP6cpAmCCmuEaacbXo/bVCcg1NkglCJC6q4wDAvJO09qIs7POf50JNzmhOhWPtfXvzgWxb5nMQl8QiA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/letter-updates-transformer/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.996.9.tgz", - "integrity": "sha512-16x2tRvl7OYpZ0W/DdFJieFriD13+RvuRBDbe5sj/tCEfK86HSGd7I2s5j0ivz8p6KWGkS+5wKRO9OliJkjUOQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "lambdas/mi-updates-transformer": { "name": "nhs-notify-supplier-api-mi-updates-transformer", "version": "0.0.1", @@ -665,90 +453,6 @@ "zod": "^4.6.5" } }, - "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb": { - "version": "3.1146.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1146.0.tgz", - "integrity": "sha512-3Mc8YkSu2KlgNNSuspaW+Fo0pTwX+fLYlC5ovH3yX3OoDg2RPtp3Py8KuQJr0FDlQj1tHw0K3+AtaH4NXlI3aQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/credential-provider-node": "^3.972.84", - "@aws-sdk/dynamodb-codec": "^3.973.46", - "@aws-sdk/middleware-endpoint-discovery": "^3.972.31", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/fetch-http-handler": "^5.8.0", - "@smithy/node-http-handler": "^4.12.1", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/mi-updates-transformer/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.46.tgz", - "integrity": "sha512-ApnSubn+5C6HQGP7025q9w/YiNzKwimIMksP76xVij779BCCqcmJ9poB6hQ4syY9NUxqmEQLBqY0PktX53L8iQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/mi-updates-transformer/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.11.tgz", - "integrity": "sha512-8q1ICxcDjHId3bBryuu/j+1L9y5/3uQnwzLDt5j2ElcjZSoWmFtymdJy7OjLrluSMe0Z4mq5bcH4fxBXvlEHfw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.31.tgz", - "integrity": "sha512-JqOIXupzP6cpAmCCmuEaacbXo/bVCcg1NkglCJC6q4wDAvJO09qIs7POf50JNzmhOhWPtfXvzgWxb5nMQl8QiA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/mi-updates-transformer/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.996.9.tgz", - "integrity": "sha512-16x2tRvl7OYpZ0W/DdFJieFriD13+RvuRBDbe5sj/tCEfK86HSGd7I2s5j0ivz8p6KWGkS+5wKRO9OliJkjUOQ==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "lambdas/supplier-allocator": { "name": "nhs-notify-supplier-api-allocate-letter", "version": "0.0.1", @@ -856,30 +560,6 @@ "node": ">=20.0.0" } }, - "lambdas/supplier-allocator/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/supplier-allocator/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/supplier-allocator/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -897,20 +577,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "lambdas/supplier-allocator/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/supplier-allocator/node_modules/@aws-sdk/middleware-sdk-sqs": { "version": "3.972.43", "license": "Apache-2.0", @@ -924,19 +590,6 @@ "node": ">=20.0.0" } }, - "lambdas/supplier-allocator/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "lambdas/supplier-allocator/node_modules/@aws/lambda-invoke-store": { "version": "0.3.0", "license": "Apache-2.0", @@ -1014,30 +667,6 @@ "node": ">=20.0.0" } }, - "lambdas/supplier-config-ingress/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/supplier-config-ingress/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/supplier-config-ingress/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -1055,33 +684,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "lambdas/supplier-config-ingress/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/supplier-config-ingress/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "lambdas/supplier-config-ingress/node_modules/@nhsdigital/nhs-notify-event-schemas-supplier-config": { "version": "1.1.1", "dependencies": { @@ -1167,30 +769,6 @@ "node": ">=20.0.0" } }, - "lambdas/update-letter-queue/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/update-letter-queue/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "lambdas/update-letter-queue/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -1208,33 +786,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "lambdas/update-letter-queue/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/update-letter-queue/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "lambdas/upsert-letter": { "name": "nhs-notify-supplier-api-upsert-letter", "version": "0.0.1", @@ -1295,79 +846,24 @@ } }, "lambdas/upsert-letter/node_modules/@aws-lambda-powertools/jmespath": { - "version": "2.35.0", - "license": "MIT-0", - "dependencies": { - "@aws-lambda-powertools/commons": "2.35.0" - } - }, - "lambdas/upsert-letter/node_modules/@aws-sdk/client-dynamodb": { - "version": "3.1145.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/credential-provider-node": "^3.972.84", - "@aws-sdk/dynamodb-codec": "^3.973.46", - "@aws-sdk/middleware-endpoint-discovery": "^3.972.31", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/fetch-http-handler": "^5.8.0", - "@smithy/node-http-handler": "^4.12.1", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/upsert-letter/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/upsert-letter/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "lambdas/upsert-letter/node_modules/@aws-sdk/lib-dynamodb": { - "version": "3.1145.0", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@aws-sdk/util-dynamodb": "^3.996.9", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1145.0" + "version": "2.35.0", + "license": "MIT-0", + "dependencies": { + "@aws-lambda-powertools/commons": "2.35.0" } }, - "lambdas/upsert-letter/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", + "lambdas/upsert-letter/node_modules/@aws-sdk/client-dynamodb": { + "version": "3.1145.0", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/credential-provider-node": "^3.972.84", + "@aws-sdk/dynamodb-codec": "^3.973.46", + "@aws-sdk/middleware-endpoint-discovery": "^3.972.31", "@aws-sdk/types": "^3.974.6", "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, @@ -1375,17 +871,21 @@ "node": ">=20.0.0" } }, - "lambdas/upsert-letter/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", + "lambdas/upsert-letter/node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.1145.0", "license": "Apache-2.0", "dependencies": { + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/util-dynamodb": "^3.996.9", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", "tslib": "^2.6.2" }, "engines": { "node": ">=20.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" + "@aws-sdk/client-dynamodb": "^3.1145.0" } }, "lambdas/upsert-letter/node_modules/@aws/lambda-invoke-store": { @@ -1536,6 +1036,27 @@ "node": ">=20.0.0" } }, + "node_modules/@aws-sdk/client-dynamodb": { + "version": "3.1147.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.1147.0.tgz", + "integrity": "sha512-lONixsTyj2jt5bb14ir4VYuBEy8kMNMZt7DSVxZ4HHE89hEfND5lO4Qj+F3Z74sENdFCaSAgK8RYQaiQWm5pfw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/credential-provider-node": "^3.972.84", + "@aws-sdk/dynamodb-codec": "^3.973.46", + "@aws-sdk/middleware-endpoint-discovery": "^3.972.31", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/fetch-http-handler": "^5.8.0", + "@smithy/node-http-handler": "^4.12.1", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@aws-sdk/client-kinesis": { "version": "3.1145.0", "license": "Apache-2.0", @@ -1780,6 +1301,69 @@ "node": ">=20.0.0" } }, + "node_modules/@aws-sdk/dynamodb-codec": { + "version": "3.973.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.973.46.tgz", + "integrity": "sha512-ApnSubn+5C6HQGP7025q9w/YiNzKwimIMksP76xVij779BCCqcmJ9poB6hQ4syY9NUxqmEQLBqY0PktX53L8iQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.1", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/endpoint-cache": { + "version": "3.972.11", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.972.11.tgz", + "integrity": "sha512-8q1ICxcDjHId3bBryuu/j+1L9y5/3uQnwzLDt5j2ElcjZSoWmFtymdJy7OjLrluSMe0Z4mq5bcH4fxBXvlEHfw==", + "license": "Apache-2.0", + "dependencies": { + "mnemonist": "0.38.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.1147.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/lib-dynamodb/-/lib-dynamodb-3.1147.0.tgz", + "integrity": "sha512-232+7ND08nb0YZrCyCviYSpySiYDusCZo8mdovBo9eOHDqBvndiP7n5/CrtN5HjegGuwJYQ/0AedWu1ORVUGDA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.978.1", + "@aws-sdk/util-dynamodb": "^3.996.9", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.1147.0" + } + }, + "node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.972.31", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.972.31.tgz", + "integrity": "sha512-JqOIXupzP6cpAmCCmuEaacbXo/bVCcg1NkglCJC6q4wDAvJO09qIs7POf50JNzmhOhWPtfXvzgWxb5nMQl8QiA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/endpoint-cache": "^3.972.11", + "@aws-sdk/types": "^3.974.6", + "@smithy/core": "^3.35.0", + "@smithy/types": "^4.19.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/@aws-sdk/middleware-sdk-api-gateway": { "version": "3.972.30", "license": "Apache-2.0", @@ -1879,6 +1463,21 @@ "node": ">=20.0.0" } }, + "node_modules/@aws-sdk/util-dynamodb": { + "version": "3.996.9", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.996.9.tgz", + "integrity": "sha512-16x2tRvl7OYpZ0W/DdFJieFriD13+RvuRBDbe5sj/tCEfK86HSGd7I2s5j0ivz8p6KWGkS+5wKRO9OliJkjUOQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.1111.0" + } + }, "node_modules/@aws-sdk/xml-builder": { "version": "3.972.41", "license": "Apache-2.0", @@ -12379,6 +11978,8 @@ }, "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==", "license": "MIT", "dependencies": { "obliterator": "^1.6.1" @@ -12537,6 +12138,18 @@ "resolved": "lambdas/mi-updates-transformer", "link": true }, + "node_modules/nhs-notify-supplier-api-populate-sameday-breaches": { + "resolved": "lambdas/letter-sla-breaches/populate-sameday-breaches", + "link": true + }, + "node_modules/nhs-notify-supplier-api-populate-standard-breaches": { + "resolved": "lambdas/letter-sla-breaches/populate-standard-breaches", + "link": true + }, + "node_modules/nhs-notify-supplier-api-populate-supplier-config-cache": { + "resolved": "lambdas/letter-sla-breaches/populate-supplier-config-cache", + "link": true + }, "node_modules/nhs-notify-supplier-api-supplier-config-ingress": { "resolved": "lambdas/supplier-config-ingress", "link": true @@ -12818,6 +12431,8 @@ }, "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==", "license": "MIT" }, "node_modules/obug": { @@ -16760,30 +16375,6 @@ "node": ">=20.0.0" } }, - "scripts/utilities/letter-test-data/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "scripts/utilities/letter-test-data/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "scripts/utilities/letter-test-data/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -16801,33 +16392,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "scripts/utilities/letter-test-data/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "scripts/utilities/letter-test-data/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "scripts/utilities/letter-test-data/node_modules/ansi-regex": { "version": "6.4.0", "license": "MIT", @@ -16989,30 +16553,6 @@ "node": ">=20.0.0" } }, - "scripts/utilities/supplier-data/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "scripts/utilities/supplier-data/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "scripts/utilities/supplier-data/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -17030,33 +16570,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "scripts/utilities/supplier-data/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "scripts/utilities/supplier-data/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "scripts/utilities/supplier-data/node_modules/ansi-regex": { "version": "6.4.0", "license": "MIT", @@ -17274,30 +16787,6 @@ "node": ">=20.0.0" } }, - "tests/node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.973.46", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.978.1", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "tests/node_modules/@aws-sdk/endpoint-cache": { - "version": "3.972.11", - "license": "Apache-2.0", - "dependencies": { - "mnemonist": "0.38.3", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "tests/node_modules/@aws-sdk/lib-dynamodb": { "version": "3.1145.0", "license": "Apache-2.0", @@ -17315,20 +16804,6 @@ "@aws-sdk/client-dynamodb": "^3.1145.0" } }, - "tests/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.972.31", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/endpoint-cache": "^3.972.11", - "@aws-sdk/types": "^3.974.6", - "@smithy/core": "^3.35.0", - "@smithy/types": "^4.19.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, "tests/node_modules/@aws-sdk/middleware-sdk-sqs": { "version": "3.972.43", "license": "Apache-2.0", @@ -17342,19 +16817,6 @@ "node": ">=20.0.0" } }, - "tests/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.996.9", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.1111.0" - } - }, "tests/node_modules/@babel/code-frame": { "version": "8.0.6", "dev": true, diff --git a/package.json b/package.json index 4e7f0e70d..d6e0a3e9b 100644 --- a/package.json +++ b/package.json @@ -149,7 +149,7 @@ "docs", "internal/*", "lambdas/*", - "pact-contracts", + "lambdas/letter-sla-breaches/*", "pact-contracts", "scripts/utilities/*", "tests", "tests/contracts/*"