From 2c77ad4b03506c77ff287ed4580f90199af87be7 Mon Sep 17 00:00:00 2001 From: Steve Buxton Date: Tue, 25 Nov 2025 10:20:40 +0000 Subject: [PATCH 01/21] CCM-12937 Letter updates transformer lambda --- .../terraform/components/api/README.md | 1 + .../components/api/ddb_table_letters.tf | 2 + .../module_lambda_letter_stream_forwarder.tf | 74 +++++++ .../src/events/__tests__/mi-events.test.ts | 1 + lambdas/letter-stream-forwarder/.eslintignore | 1 + lambdas/letter-stream-forwarder/.gitignore | 4 + .../letter-stream-forwarder/jest.config.ts | 60 ++++++ lambdas/letter-stream-forwarder/package.json | 21 ++ .../__tests__/letter-stream-forwarder.test.ts | 202 ++++++++++++++++++ lambdas/letter-stream-forwarder/src/deps.ts | 17 ++ lambdas/letter-stream-forwarder/src/env.ts | 9 + lambdas/letter-stream-forwarder/src/index.ts | 6 + .../src/letter-stream-forwarder.ts | 58 +++++ lambdas/letter-stream-forwarder/tsconfig.json | 7 + package-lock.json | 4 + 15 files changed, 467 insertions(+) create mode 100644 infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf create mode 100644 lambdas/letter-stream-forwarder/.eslintignore create mode 100644 lambdas/letter-stream-forwarder/.gitignore create mode 100644 lambdas/letter-stream-forwarder/jest.config.ts create mode 100644 lambdas/letter-stream-forwarder/package.json create mode 100644 lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts create mode 100644 lambdas/letter-stream-forwarder/src/deps.ts create mode 100644 lambdas/letter-stream-forwarder/src/env.ts create mode 100644 lambdas/letter-stream-forwarder/src/index.ts create mode 100644 lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts create mode 100644 lambdas/letter-stream-forwarder/tsconfig.json diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 150af054..559a0839 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -45,6 +45,7 @@ No requirements. | [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-kms.zip | n/a | | [letter\_status\_update](#module\_letter\_status\_update) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a | | [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a | +| [letter\_stream\_forwarder](#module\_letter\_stream\_forwarder) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [letter\_updates\_transformer](#module\_letter\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [logging\_bucket](#module\_logging\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-s3bucket.zip | n/a | | [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | diff --git a/infrastructure/terraform/components/api/ddb_table_letters.tf b/infrastructure/terraform/components/api/ddb_table_letters.tf index 6a3c3e48..04d2606e 100644 --- a/infrastructure/terraform/components/api/ddb_table_letters.tf +++ b/infrastructure/terraform/components/api/ddb_table_letters.tf @@ -1,6 +1,8 @@ resource "aws_dynamodb_table" "letters" { name = "${local.csi}-letters" billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_AND_OLD_IMAGES" hash_key = "supplierId" range_key = "id" diff --git a/infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf b/infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf new file mode 100644 index 00000000..13c36c34 --- /dev/null +++ b/infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf @@ -0,0 +1,74 @@ +module "letter_stream_forwarder" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip" + + function_name = "letter-stream-forwarder" + description = "Kinesis stream forwarder for DDB letter status updates" + + 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.letter_stream_forwarder_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-stream-forwarder/dist" + function_include_common = true + handler_function_name = "handler" + runtime = "nodejs22.x" + memory = 128 + timeout = 5 + log_level = var.log_level + + force_lambda_code_deploy = var.force_lambda_code_deploy + enable_lambda_insights = false + + send_to_firehose = true + log_destination_arn = local.destination_arn + log_subscription_role_arn = local.acct.log_subscription_role_arn + + lambda_env_vars = merge(local.common_lambda_env_vars, { + LETTER_CHANGE_STREAM_ARN = "${aws_kinesis_stream.letter_change_stream.arn}" + }) +} + +data "aws_iam_policy_document" "letter_stream_forwarder_lambda" { + + statement { + sid = "AllowDynamoDBStream" + effect = "Allow" + + actions = [ + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:DescribeStream", + "dynamodb:ListStreams", + ] + + resources = [ + "${aws_dynamodb_table.letters.arn}/stream/*" + ] + } + + statement { + sid = "AllowKinesisPut" + effect = "Allow" + + actions = [ + "kinesis:DescribeStream", + "kinesis:PutRecord", + ] + + resources = [ + aws_kinesis_stream.letter_change_stream.arn + ] + } +} diff --git a/internal/events/src/events/__tests__/mi-events.test.ts b/internal/events/src/events/__tests__/mi-events.test.ts index f4a22c98..f68ca26e 100644 --- a/internal/events/src/events/__tests__/mi-events.test.ts +++ b/internal/events/src/events/__tests__/mi-events.test.ts @@ -26,6 +26,7 @@ describe("MI event validations", () => { datacontenttype: "application/json", dataschema: "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json", + dataschemaversion: "1.0.0", subject: "mi/mi-test-001", data: expect.objectContaining({ id: "mi-test-001", diff --git a/lambdas/letter-stream-forwarder/.eslintignore b/lambdas/letter-stream-forwarder/.eslintignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/lambdas/letter-stream-forwarder/.eslintignore @@ -0,0 +1 @@ +dist diff --git a/lambdas/letter-stream-forwarder/.gitignore b/lambdas/letter-stream-forwarder/.gitignore new file mode 100644 index 00000000..80323f7c --- /dev/null +++ b/lambdas/letter-stream-forwarder/.gitignore @@ -0,0 +1,4 @@ +coverage +node_modules +dist +.reports diff --git a/lambdas/letter-stream-forwarder/jest.config.ts b/lambdas/letter-stream-forwarder/jest.config.ts new file mode 100644 index 00000000..d30f4cd1 --- /dev/null +++ b/lambdas/letter-stream-forwarder/jest.config.ts @@ -0,0 +1,60 @@ +import type { Config } from 'jest'; + +export const baseJestConfig: Config = { + preset: 'ts-jest', + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // The directory where Jest should output its coverage files + coverageDirectory: './.reports/unit/coverage', + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'babel', + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + coveragePathIgnorePatterns: ['/__tests__/'], + transform: { '^.+\\.ts$': 'ts-jest' }, + testPathIgnorePatterns: ['.build'], + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + + // Use this configuration option to add custom reporters to Jest + reporters: [ + 'default', + [ + 'jest-html-reporter', + { + pageTitle: 'Test Report', + outputPath: './.reports/unit/test-report.html', + includeFailureMsg: true, + }, + ], + ], + + // The test environment that will be used for testing + testEnvironment: 'jsdom', +}; + +const utilsJestConfig = { + ...baseJestConfig, + + testEnvironment: 'node', + + coveragePathIgnorePatterns: [ + ...(baseJestConfig.coveragePathIgnorePatterns ?? []), + 'zod-validators.ts', + ], +}; + +export default utilsJestConfig; diff --git a/lambdas/letter-stream-forwarder/package.json b/lambdas/letter-stream-forwarder/package.json new file mode 100644 index 00000000..a9c1c5ef --- /dev/null +++ b/lambdas/letter-stream-forwarder/package.json @@ -0,0 +1,21 @@ +{ + "dependencies": { + "@aws-sdk/client-kinesis": "^3.0.0", + "aws-lambda": "^1.0.7" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "typescript": "^5.0.0" + }, + "main": "src/index.ts", + "name": "letter-stream-forwarder", + "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.1.0" +} diff --git a/lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts b/lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts new file mode 100644 index 00000000..d4e11a23 --- /dev/null +++ b/lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts @@ -0,0 +1,202 @@ +import { KinesisClient } from "@aws-sdk/client-kinesis"; +import * as pino from "pino"; +import { mockDeep } from "jest-mock-extended"; +import { DynamoDBStreamEvent, Context } from "aws-lambda"; +import { Deps } from "../deps"; +import { EnvVars } from "../env"; +import { createHandler } from "../letter-stream-forwarder"; + +describe("letter-stream-forwarder Lambda", () => { + + const mockedDeps: jest.Mocked = { + kinesisClient: { send: jest.fn()} as unknown as KinesisClient, + logger: { info: jest.fn(), warn: jest.fn(), error: jest.fn() } as unknown as pino.Logger, + env: { + LETTER_CHANGE_STREAM_ARN: "test-stream.arn", + } as unknown as EnvVars + } as Deps; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + + it("forwards status changes to Kinesis", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "MODIFY", + dynamodb: { + Keys: { id: { S: "123" } }, + OldImage: buildValidLetter(), + NewImage: {...buildValidLetter(), status: { S: "ACCEPTED" } }, + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + + expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + StreamARN: "test-stream.arn", + PartitionKey: "123", + }), + }) + ); + }); + + + it("does not forward invalid status changes", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "MODIFY", + dynamodb: { + Keys: { id: { S: "123" } }, + OldImage: {...buildValidLetter(), status: { S: "CANCELLED" } }, + NewImage: {...buildValidLetter(), status: { S: "PRINTED" } }, + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + + expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); + }); + + it("forwards to Kinesis if a reason code is added", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "MODIFY", + dynamodb: { + Keys: { id: { S: "123" } }, + OldImage: buildValidLetter(), + NewImage: {...buildValidLetter(), reasonCode: {S: "r1"} }, + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + + expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + StreamARN: "test-stream.arn", + PartitionKey: "123", + }), + }) + ); + }); + + + it("forwards to Kinesis if a reason code is changed", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "MODIFY", + dynamodb: { + Keys: { id: { S: "123" } }, + OldImage: {...buildValidLetter(), reasonCode: {S: "r1"} }, + NewImage: {...buildValidLetter(), reasonCode: {S: "r2"} }, + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + + expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + StreamARN: "test-stream.arn", + PartitionKey: "123", + }), + }) + ); + }); + + it("does not forward if neither status nor reason code changed", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "MODIFY", + dynamodb: { + Keys: { id: { S: "123" } }, + OldImage: buildValidLetter(), + NewImage: buildValidLetter(), + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + + expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); + }); + + it("does not forward non-MODIFY events", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "INSERT", + dynamodb: { + Keys: { id: { S: "123" } }, + NewImage: buildValidLetter(), + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + + expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); + }); + + + it("does not forward invalid letter data", async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: "MODIFY", + dynamodb: { + Keys: { id: { S: "123" } }, + OldImage: buildInvalidLetter(), + NewImage: {...buildInvalidLetter(), status: { S: "ACCEPTED" } }, + }, + } + ], + }; + + const handler = createHandler(mockedDeps); + await expect(handler(event, mockDeep(), jest.fn())).rejects.toThrow(); + + expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); + }); + + function buildValidLetter() { + return { + id: {S: "123"}, + status: {S: "PENDING"}, + specificationId: {S: "spec1"}, + groupId: {S: "group1"}, + }; + } + + function buildInvalidLetter() { + return { + id: {S: "123"}, + status: {S: "PENDING"}, + }; + } +}); diff --git a/lambdas/letter-stream-forwarder/src/deps.ts b/lambdas/letter-stream-forwarder/src/deps.ts new file mode 100644 index 00000000..8c5c9d0b --- /dev/null +++ b/lambdas/letter-stream-forwarder/src/deps.ts @@ -0,0 +1,17 @@ +import pino from 'pino'; +import { KinesisClient } from '@aws-sdk/client-kinesis'; +import { envVars, EnvVars } from './env'; + +export type Deps = { + kinesisClient: KinesisClient; + logger: pino.Logger; + env: EnvVars; +}; + +export function createDependenciesContainer(): Deps { + return { + kinesisClient: new KinesisClient({}), + logger: pino(), + env: envVars, + }; +} diff --git a/lambdas/letter-stream-forwarder/src/env.ts b/lambdas/letter-stream-forwarder/src/env.ts new file mode 100644 index 00000000..035d3684 --- /dev/null +++ b/lambdas/letter-stream-forwarder/src/env.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +const EnvVarsSchema = z.object({ + LETTER_CHANGE_STREAM_ARN: z.string(), +}); + +export type EnvVars = z.infer; + +export const envVars = EnvVarsSchema.parse(process.env); diff --git a/lambdas/letter-stream-forwarder/src/index.ts b/lambdas/letter-stream-forwarder/src/index.ts new file mode 100644 index 00000000..e41bc3f3 --- /dev/null +++ b/lambdas/letter-stream-forwarder/src/index.ts @@ -0,0 +1,6 @@ +import { createHandler } from "./letter-stream-forwarder"; +import { createDependenciesContainer } from "./deps"; + +const container = createDependenciesContainer(); + +export const handler = createHandler(container); diff --git a/lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts b/lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts new file mode 100644 index 00000000..e9ec10ad --- /dev/null +++ b/lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts @@ -0,0 +1,58 @@ +import { LetterSchemaBase } from "@internal/datastore"; +import { DynamoDBStreamEvent, DynamoDBRecord, DynamoDBStreamHandler } from "aws-lambda"; +import { PutRecordCommand } from "@aws-sdk/client-kinesis"; +import { Deps } from "./deps"; +import { unmarshall } from "@aws-sdk/util-dynamodb"; +import { LetterStatus } from "../../api-handler/src/contracts/letters"; +import { Logger } from "pino"; + +const VALID_STATE_TRANSITIONS: Record> = { + "PENDING": new Set(["ACCEPTED", "REJECTED"]), + "REJECTED": new Set(["FAILED"]), + "ACCEPTED": new Set(["FORWARDED", "PRINTED", "ENCLOSED", "DISPATCHED", "CANCELLED", "FAILED"]), + "PRINTED": new Set(["ENCLOSED", "DISPATCHED", "CANCELLED", "FAILED"]), + "ENCLOSED": new Set(["DISPATCHED", "CANCELLED", "FAILED"]), + "FORWARDED": new Set(["DELIVERED", "RETURNED"]), + "DISPATCHED": new Set(["DELIVERED", "RETURNED"]), + "CANCELLED": new Set([]), + "FAILED": new Set([]), + "DELIVERED": new Set(["RETURNED"]), + "RETURNED": new Set([]), +} + +export function createHandler(deps: Deps): DynamoDBStreamHandler { + return async (event: DynamoDBStreamEvent): Promise => { + deps.logger.info({description: "Received event", event}); + const statusChanges = event.Records + .filter(record => record.eventName === "MODIFY") + .filter(record => + (isChanged(record, "status") && isValidStateTransition(record, deps.logger)) || + isChanged(record, "reasonCode")); + + for (const record of statusChanges) { + const newImage = record.dynamodb?.NewImage!; + const letter = LetterSchemaBase.parse(unmarshall(newImage as any)); + await deps.kinesisClient.send(new PutRecordCommand({ + StreamARN: deps.env.LETTER_CHANGE_STREAM_ARN, + PartitionKey: letter.id, + Data: Buffer.from(JSON.stringify(letter)), + })); + } + }; + + function isValidStateTransition(record: DynamoDBRecord, logger: Logger): boolean { + const oldStatus = record.dynamodb?.OldImage?.status?.S! as LetterStatus; + const newStatus = record.dynamodb?.NewImage?.status?.S! as LetterStatus; + const valid = VALID_STATE_TRANSITIONS[oldStatus].has(newStatus); + if (!valid) { + logger.warn({description: "Ignoring invalid state transition", oldStatus, newStatus}); + } + return valid; + } + + function isChanged(record: DynamoDBRecord, property: string): boolean { + const oldValue = record.dynamodb?.OldImage![property]; + const newValue = record.dynamodb?.NewImage![property]; + return oldValue?.S !== newValue?.S; + } +} diff --git a/lambdas/letter-stream-forwarder/tsconfig.json b/lambdas/letter-stream-forwarder/tsconfig.json new file mode 100644 index 00000000..ea37d696 --- /dev/null +++ b/lambdas/letter-stream-forwarder/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "src/**/*", + "jest.config.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index 4d51a035..68f25fb5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22201,6 +22201,10 @@ "node": ">=10" } }, + "node_modules/letter-stream-forwarder": { + "resolved": "lambdas/letter-stream-forwarder", + "link": true + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", From 4e447551d8673693b3dfdce96639a7e0d655db6c Mon Sep 17 00:00:00 2001 From: Steve Buxton Date: Tue, 2 Dec 2025 15:43:36 +0000 Subject: [PATCH 02/21] Address review comments --- .../terraform/components/api/README.md | 1 - .../module_lambda_letter_stream_forwarder.tf | 74 ------- .../src/events/__tests__/mi-events.test.ts | 1 - internal/events/src/events/letter-events.ts | 6 +- lambdas/letter-stream-forwarder/.eslintignore | 1 - lambdas/letter-stream-forwarder/.gitignore | 4 - .../letter-stream-forwarder/jest.config.ts | 60 ------ lambdas/letter-stream-forwarder/package.json | 21 -- .../__tests__/letter-stream-forwarder.test.ts | 202 ------------------ lambdas/letter-stream-forwarder/src/deps.ts | 17 -- lambdas/letter-stream-forwarder/src/env.ts | 9 - lambdas/letter-stream-forwarder/src/index.ts | 6 - .../src/letter-stream-forwarder.ts | 58 ----- lambdas/letter-stream-forwarder/tsconfig.json | 7 - 14 files changed, 3 insertions(+), 464 deletions(-) delete mode 100644 infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf delete mode 100644 lambdas/letter-stream-forwarder/.eslintignore delete mode 100644 lambdas/letter-stream-forwarder/.gitignore delete mode 100644 lambdas/letter-stream-forwarder/jest.config.ts delete mode 100644 lambdas/letter-stream-forwarder/package.json delete mode 100644 lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts delete mode 100644 lambdas/letter-stream-forwarder/src/deps.ts delete mode 100644 lambdas/letter-stream-forwarder/src/env.ts delete mode 100644 lambdas/letter-stream-forwarder/src/index.ts delete mode 100644 lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts delete mode 100644 lambdas/letter-stream-forwarder/tsconfig.json diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 559a0839..150af054 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -45,7 +45,6 @@ No requirements. | [kms](#module\_kms) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-kms.zip | n/a | | [letter\_status\_update](#module\_letter\_status\_update) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a | | [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a | -| [letter\_stream\_forwarder](#module\_letter\_stream\_forwarder) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [letter\_updates\_transformer](#module\_letter\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [logging\_bucket](#module\_logging\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-s3bucket.zip | n/a | | [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | diff --git a/infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf b/infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf deleted file mode 100644 index 13c36c34..00000000 --- a/infrastructure/terraform/components/api/module_lambda_letter_stream_forwarder.tf +++ /dev/null @@ -1,74 +0,0 @@ -module "letter_stream_forwarder" { - source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip" - - function_name = "letter-stream-forwarder" - description = "Kinesis stream forwarder for DDB letter status updates" - - 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.letter_stream_forwarder_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-stream-forwarder/dist" - function_include_common = true - handler_function_name = "handler" - runtime = "nodejs22.x" - memory = 128 - timeout = 5 - log_level = var.log_level - - force_lambda_code_deploy = var.force_lambda_code_deploy - enable_lambda_insights = false - - send_to_firehose = true - log_destination_arn = local.destination_arn - log_subscription_role_arn = local.acct.log_subscription_role_arn - - lambda_env_vars = merge(local.common_lambda_env_vars, { - LETTER_CHANGE_STREAM_ARN = "${aws_kinesis_stream.letter_change_stream.arn}" - }) -} - -data "aws_iam_policy_document" "letter_stream_forwarder_lambda" { - - statement { - sid = "AllowDynamoDBStream" - effect = "Allow" - - actions = [ - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:DescribeStream", - "dynamodb:ListStreams", - ] - - resources = [ - "${aws_dynamodb_table.letters.arn}/stream/*" - ] - } - - statement { - sid = "AllowKinesisPut" - effect = "Allow" - - actions = [ - "kinesis:DescribeStream", - "kinesis:PutRecord", - ] - - resources = [ - aws_kinesis_stream.letter_change_stream.arn - ] - } -} diff --git a/internal/events/src/events/__tests__/mi-events.test.ts b/internal/events/src/events/__tests__/mi-events.test.ts index f68ca26e..f4a22c98 100644 --- a/internal/events/src/events/__tests__/mi-events.test.ts +++ b/internal/events/src/events/__tests__/mi-events.test.ts @@ -26,7 +26,6 @@ describe("MI event validations", () => { datacontenttype: "application/json", dataschema: "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json", - dataschemaversion: "1.0.0", subject: "mi/mi-test-001", data: expect.objectContaining({ id: "mi-test-001", diff --git a/internal/events/src/events/letter-events.ts b/internal/events/src/events/letter-events.ts index 49795068..ea4960d5 100644 --- a/internal/events/src/events/letter-events.ts +++ b/internal/events/src/events/letter-events.ts @@ -13,7 +13,7 @@ export const $LetterEvent = EventEnvelope( "letter", "letter", $Letter, - $LetterStatus.options, + $LetterStatus.options.map((status) => status.toLowerCase()), "letter-origin", ).meta({ title: `letter.* Event`, @@ -27,13 +27,13 @@ export type LetterEvent = z.infer; */ const eventSchema = (status: LetterStatus) => EventEnvelope( - `letter.${status}`, + `letter.${status.toLowerCase()}`, "letter", $Letter, [status], "letter-origin", ).meta({ - title: `letter.${status} Event`, + title: `letter.${status.toLowerCase()} Event`, description: `Event schema for letter status change to ${status}`, }); diff --git a/lambdas/letter-stream-forwarder/.eslintignore b/lambdas/letter-stream-forwarder/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/lambdas/letter-stream-forwarder/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/lambdas/letter-stream-forwarder/.gitignore b/lambdas/letter-stream-forwarder/.gitignore deleted file mode 100644 index 80323f7c..00000000 --- a/lambdas/letter-stream-forwarder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -coverage -node_modules -dist -.reports diff --git a/lambdas/letter-stream-forwarder/jest.config.ts b/lambdas/letter-stream-forwarder/jest.config.ts deleted file mode 100644 index d30f4cd1..00000000 --- a/lambdas/letter-stream-forwarder/jest.config.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { Config } from 'jest'; - -export const baseJestConfig: Config = { - preset: 'ts-jest', - - // Automatically clear mock calls, instances, contexts and results before every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // The directory where Jest should output its coverage files - coverageDirectory: './.reports/unit/coverage', - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'babel', - - coverageThreshold: { - global: { - branches: 100, - functions: 100, - lines: 100, - statements: -10, - }, - }, - - coveragePathIgnorePatterns: ['/__tests__/'], - transform: { '^.+\\.ts$': 'ts-jest' }, - testPathIgnorePatterns: ['.build'], - testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], - - // Use this configuration option to add custom reporters to Jest - reporters: [ - 'default', - [ - 'jest-html-reporter', - { - pageTitle: 'Test Report', - outputPath: './.reports/unit/test-report.html', - includeFailureMsg: true, - }, - ], - ], - - // The test environment that will be used for testing - testEnvironment: 'jsdom', -}; - -const utilsJestConfig = { - ...baseJestConfig, - - testEnvironment: 'node', - - coveragePathIgnorePatterns: [ - ...(baseJestConfig.coveragePathIgnorePatterns ?? []), - 'zod-validators.ts', - ], -}; - -export default utilsJestConfig; diff --git a/lambdas/letter-stream-forwarder/package.json b/lambdas/letter-stream-forwarder/package.json deleted file mode 100644 index a9c1c5ef..00000000 --- a/lambdas/letter-stream-forwarder/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "dependencies": { - "@aws-sdk/client-kinesis": "^3.0.0", - "aws-lambda": "^1.0.7" - }, - "devDependencies": { - "@types/aws-lambda": "^8.10.119", - "typescript": "^5.0.0" - }, - "main": "src/index.ts", - "name": "letter-stream-forwarder", - "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.1.0" -} diff --git a/lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts b/lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts deleted file mode 100644 index d4e11a23..00000000 --- a/lambdas/letter-stream-forwarder/src/__tests__/letter-stream-forwarder.test.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { KinesisClient } from "@aws-sdk/client-kinesis"; -import * as pino from "pino"; -import { mockDeep } from "jest-mock-extended"; -import { DynamoDBStreamEvent, Context } from "aws-lambda"; -import { Deps } from "../deps"; -import { EnvVars } from "../env"; -import { createHandler } from "../letter-stream-forwarder"; - -describe("letter-stream-forwarder Lambda", () => { - - const mockedDeps: jest.Mocked = { - kinesisClient: { send: jest.fn()} as unknown as KinesisClient, - logger: { info: jest.fn(), warn: jest.fn(), error: jest.fn() } as unknown as pino.Logger, - env: { - LETTER_CHANGE_STREAM_ARN: "test-stream.arn", - } as unknown as EnvVars - } as Deps; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - - it("forwards status changes to Kinesis", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - Keys: { id: { S: "123" } }, - OldImage: buildValidLetter(), - NewImage: {...buildValidLetter(), status: { S: "ACCEPTED" } }, - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - - expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( - expect.objectContaining({ - input: expect.objectContaining({ - StreamARN: "test-stream.arn", - PartitionKey: "123", - }), - }) - ); - }); - - - it("does not forward invalid status changes", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - Keys: { id: { S: "123" } }, - OldImage: {...buildValidLetter(), status: { S: "CANCELLED" } }, - NewImage: {...buildValidLetter(), status: { S: "PRINTED" } }, - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - - expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); - }); - - it("forwards to Kinesis if a reason code is added", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - Keys: { id: { S: "123" } }, - OldImage: buildValidLetter(), - NewImage: {...buildValidLetter(), reasonCode: {S: "r1"} }, - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - - expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( - expect.objectContaining({ - input: expect.objectContaining({ - StreamARN: "test-stream.arn", - PartitionKey: "123", - }), - }) - ); - }); - - - it("forwards to Kinesis if a reason code is changed", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - Keys: { id: { S: "123" } }, - OldImage: {...buildValidLetter(), reasonCode: {S: "r1"} }, - NewImage: {...buildValidLetter(), reasonCode: {S: "r2"} }, - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - - expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( - expect.objectContaining({ - input: expect.objectContaining({ - StreamARN: "test-stream.arn", - PartitionKey: "123", - }), - }) - ); - }); - - it("does not forward if neither status nor reason code changed", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - Keys: { id: { S: "123" } }, - OldImage: buildValidLetter(), - NewImage: buildValidLetter(), - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - - expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); - }); - - it("does not forward non-MODIFY events", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "INSERT", - dynamodb: { - Keys: { id: { S: "123" } }, - NewImage: buildValidLetter(), - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - - expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); - }); - - - it("does not forward invalid letter data", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - Keys: { id: { S: "123" } }, - OldImage: buildInvalidLetter(), - NewImage: {...buildInvalidLetter(), status: { S: "ACCEPTED" } }, - }, - } - ], - }; - - const handler = createHandler(mockedDeps); - await expect(handler(event, mockDeep(), jest.fn())).rejects.toThrow(); - - expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); - }); - - function buildValidLetter() { - return { - id: {S: "123"}, - status: {S: "PENDING"}, - specificationId: {S: "spec1"}, - groupId: {S: "group1"}, - }; - } - - function buildInvalidLetter() { - return { - id: {S: "123"}, - status: {S: "PENDING"}, - }; - } -}); diff --git a/lambdas/letter-stream-forwarder/src/deps.ts b/lambdas/letter-stream-forwarder/src/deps.ts deleted file mode 100644 index 8c5c9d0b..00000000 --- a/lambdas/letter-stream-forwarder/src/deps.ts +++ /dev/null @@ -1,17 +0,0 @@ -import pino from 'pino'; -import { KinesisClient } from '@aws-sdk/client-kinesis'; -import { envVars, EnvVars } from './env'; - -export type Deps = { - kinesisClient: KinesisClient; - logger: pino.Logger; - env: EnvVars; -}; - -export function createDependenciesContainer(): Deps { - return { - kinesisClient: new KinesisClient({}), - logger: pino(), - env: envVars, - }; -} diff --git a/lambdas/letter-stream-forwarder/src/env.ts b/lambdas/letter-stream-forwarder/src/env.ts deleted file mode 100644 index 035d3684..00000000 --- a/lambdas/letter-stream-forwarder/src/env.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from 'zod'; - -const EnvVarsSchema = z.object({ - LETTER_CHANGE_STREAM_ARN: z.string(), -}); - -export type EnvVars = z.infer; - -export const envVars = EnvVarsSchema.parse(process.env); diff --git a/lambdas/letter-stream-forwarder/src/index.ts b/lambdas/letter-stream-forwarder/src/index.ts deleted file mode 100644 index e41bc3f3..00000000 --- a/lambdas/letter-stream-forwarder/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createHandler } from "./letter-stream-forwarder"; -import { createDependenciesContainer } from "./deps"; - -const container = createDependenciesContainer(); - -export const handler = createHandler(container); diff --git a/lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts b/lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts deleted file mode 100644 index e9ec10ad..00000000 --- a/lambdas/letter-stream-forwarder/src/letter-stream-forwarder.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { LetterSchemaBase } from "@internal/datastore"; -import { DynamoDBStreamEvent, DynamoDBRecord, DynamoDBStreamHandler } from "aws-lambda"; -import { PutRecordCommand } from "@aws-sdk/client-kinesis"; -import { Deps } from "./deps"; -import { unmarshall } from "@aws-sdk/util-dynamodb"; -import { LetterStatus } from "../../api-handler/src/contracts/letters"; -import { Logger } from "pino"; - -const VALID_STATE_TRANSITIONS: Record> = { - "PENDING": new Set(["ACCEPTED", "REJECTED"]), - "REJECTED": new Set(["FAILED"]), - "ACCEPTED": new Set(["FORWARDED", "PRINTED", "ENCLOSED", "DISPATCHED", "CANCELLED", "FAILED"]), - "PRINTED": new Set(["ENCLOSED", "DISPATCHED", "CANCELLED", "FAILED"]), - "ENCLOSED": new Set(["DISPATCHED", "CANCELLED", "FAILED"]), - "FORWARDED": new Set(["DELIVERED", "RETURNED"]), - "DISPATCHED": new Set(["DELIVERED", "RETURNED"]), - "CANCELLED": new Set([]), - "FAILED": new Set([]), - "DELIVERED": new Set(["RETURNED"]), - "RETURNED": new Set([]), -} - -export function createHandler(deps: Deps): DynamoDBStreamHandler { - return async (event: DynamoDBStreamEvent): Promise => { - deps.logger.info({description: "Received event", event}); - const statusChanges = event.Records - .filter(record => record.eventName === "MODIFY") - .filter(record => - (isChanged(record, "status") && isValidStateTransition(record, deps.logger)) || - isChanged(record, "reasonCode")); - - for (const record of statusChanges) { - const newImage = record.dynamodb?.NewImage!; - const letter = LetterSchemaBase.parse(unmarshall(newImage as any)); - await deps.kinesisClient.send(new PutRecordCommand({ - StreamARN: deps.env.LETTER_CHANGE_STREAM_ARN, - PartitionKey: letter.id, - Data: Buffer.from(JSON.stringify(letter)), - })); - } - }; - - function isValidStateTransition(record: DynamoDBRecord, logger: Logger): boolean { - const oldStatus = record.dynamodb?.OldImage?.status?.S! as LetterStatus; - const newStatus = record.dynamodb?.NewImage?.status?.S! as LetterStatus; - const valid = VALID_STATE_TRANSITIONS[oldStatus].has(newStatus); - if (!valid) { - logger.warn({description: "Ignoring invalid state transition", oldStatus, newStatus}); - } - return valid; - } - - function isChanged(record: DynamoDBRecord, property: string): boolean { - const oldValue = record.dynamodb?.OldImage![property]; - const newValue = record.dynamodb?.NewImage![property]; - return oldValue?.S !== newValue?.S; - } -} diff --git a/lambdas/letter-stream-forwarder/tsconfig.json b/lambdas/letter-stream-forwarder/tsconfig.json deleted file mode 100644 index ea37d696..00000000 --- a/lambdas/letter-stream-forwarder/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "@tsconfig/node22/tsconfig.json", - "include": [ - "src/**/*", - "jest.config.ts" - ] -} From 59bce40a650ed183020a9ab9aac4e2a3186613c3 Mon Sep 17 00:00:00 2001 From: Steve Buxton Date: Wed, 3 Dec 2025 11:23:11 +0000 Subject: [PATCH 03/21] Apply linting rules --- package-lock.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 68f25fb5..4d51a035 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22201,10 +22201,6 @@ "node": ">=10" } }, - "node_modules/letter-stream-forwarder": { - "resolved": "lambdas/letter-stream-forwarder", - "link": true - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", From 7f418c7aae6935413b2be519d071bd5c75e55945 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 27 Nov 2025 08:55:47 +0000 Subject: [PATCH 04/21] CM-12952 - MI Updates Transformer --- lambdas/mi-updates-transformer/jest.config.ts | 60 +++ lambdas/mi-updates-transformer/package.json | 24 + .../__tests__/mi-updates-transformer.test.ts | 133 +++++ lambdas/mi-updates-transformer/src/deps.ts | 24 + lambdas/mi-updates-transformer/src/env.ts | 9 + lambdas/mi-updates-transformer/src/index.ts | 6 + .../src/mappers/__tests__/mi-mapper.test.ts | 46 ++ .../src/mappers/mi-mapper.ts | 34 ++ .../src/mi-updates-transformer.ts | 43 ++ lambdas/mi-updates-transformer/tsconfig.json | 7 + package-lock.json | 460 ++++++++++++++++++ 11 files changed, 846 insertions(+) create mode 100644 lambdas/mi-updates-transformer/jest.config.ts create mode 100644 lambdas/mi-updates-transformer/package.json create mode 100644 lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts create mode 100644 lambdas/mi-updates-transformer/src/deps.ts create mode 100644 lambdas/mi-updates-transformer/src/env.ts create mode 100644 lambdas/mi-updates-transformer/src/index.ts create mode 100644 lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts create mode 100644 lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts create mode 100644 lambdas/mi-updates-transformer/src/mi-updates-transformer.ts create mode 100644 lambdas/mi-updates-transformer/tsconfig.json diff --git a/lambdas/mi-updates-transformer/jest.config.ts b/lambdas/mi-updates-transformer/jest.config.ts new file mode 100644 index 00000000..d30f4cd1 --- /dev/null +++ b/lambdas/mi-updates-transformer/jest.config.ts @@ -0,0 +1,60 @@ +import type { Config } from 'jest'; + +export const baseJestConfig: Config = { + preset: 'ts-jest', + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // The directory where Jest should output its coverage files + coverageDirectory: './.reports/unit/coverage', + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'babel', + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + coveragePathIgnorePatterns: ['/__tests__/'], + transform: { '^.+\\.ts$': 'ts-jest' }, + testPathIgnorePatterns: ['.build'], + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + + // Use this configuration option to add custom reporters to Jest + reporters: [ + 'default', + [ + 'jest-html-reporter', + { + pageTitle: 'Test Report', + outputPath: './.reports/unit/test-report.html', + includeFailureMsg: true, + }, + ], + ], + + // The test environment that will be used for testing + testEnvironment: 'jsdom', +}; + +const utilsJestConfig = { + ...baseJestConfig, + + testEnvironment: 'node', + + coveragePathIgnorePatterns: [ + ...(baseJestConfig.coveragePathIgnorePatterns ?? []), + 'zod-validators.ts', + ], +}; + +export default utilsJestConfig; diff --git a/lambdas/mi-updates-transformer/package.json b/lambdas/mi-updates-transformer/package.json new file mode 100644 index 00000000..16d8bc8d --- /dev/null +++ b/lambdas/mi-updates-transformer/package.json @@ -0,0 +1,24 @@ +{ + "dependencies": { + "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", + "esbuild": "^0.24.0" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.2", + "@types/aws-lambda": "^8.10.148", + "@types/jest": "^30.0.0", + "jest": "^30.2.0", + "jest-mock-extended": "^4.0.0", + "typescript": "^5.8.3" + }, + "name": "nhs-notify-supplier-api-mi-updates-transformer", + "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/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts new file mode 100644 index 00000000..69f83cb4 --- /dev/null +++ b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts @@ -0,0 +1,133 @@ +import { SNSClient } from '@aws-sdk/client-sns'; +import * as pino from 'pino'; +import { createHandler } from '../mi-updates-transformer'; +import { KinesisStreamEvent, Context, KinesisStreamRecordPayload } from 'aws-lambda'; +import { mockDeep } from 'jest-mock-extended'; +import { Deps } from '../deps'; +import { EnvVars } from '../env'; +import { MI } from '@internal/datastore'; +import { mapMIToCloudEvent } from '../mappers/mi-mapper'; + +// Make crypto return consistent values, since we're calling it in both prod and test code and comparing the values +const realCrypto = jest.requireActual('crypto'); +const randomBytes: Record = {'8': realCrypto.randomBytes(8), '16': realCrypto.randomBytes(16)} +jest.mock('crypto', () => ({ + randomUUID: () => '4616b2d9-b7a5-45aa-8523-fa7419626b69', + randomBytes: (size: number) => randomBytes[String(size)] +})); + +describe('mi-updates-transformer Lambda', () => { + + const mockedDeps: jest.Mocked = { + snsClient: { send: jest.fn()} as unknown as SNSClient, + logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger, + env: { + EVENT_PUB_SNS_TOPIC_ARN: 'arn:aws:sns:region:account:topic', + } as unknown as EnvVars + } as Deps; + + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }) + + it('processes Kinesis events and publishes them to SNS', async () => { + + const handler = createHandler(mockedDeps); + const miEvents = generateMIEvents(1); + const expectedEntries = [expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvents[0]))})]; + + await handler(generateKinesisEvent(miEvents), mockDeep(), jest.fn()); + + expect(mockedDeps.snsClient.send).toHaveBeenCalledWith(expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: 'arn:aws:sns:region:account:topic', + PublishBatchRequestEntries: expectedEntries + }) + })); + }); + + it ('batches mutiple records into a single call to SNS', async () => { + + const handler = createHandler(mockedDeps); + const miEvents = generateMIEvents(10); + const expectedEntries = miEvents.map(miEvent => + expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})); + + await handler(generateKinesisEvent(miEvents), mockDeep(), jest.fn()); + + expect(mockedDeps.snsClient.send).toHaveBeenCalledWith(expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: 'arn:aws:sns:region:account:topic', + PublishBatchRequestEntries: expectedEntries + }) + })); + }); + + + it('splits more than 10 records into multiple SNS calls', async () => { + + const handler = createHandler(mockedDeps); + const miEvents = generateMIEvents(21); + const expectedEntries = [ + miEvents.slice(0, 10).map(miEvent => + expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})), + miEvents.slice(10, 20).map(miEvent => + expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})), + miEvents.slice(20).map(miEvent => + expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})), + ]; + + await handler(generateKinesisEvent(miEvents), mockDeep(), jest.fn()); + + expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith(1, + expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: 'arn:aws:sns:region:account:topic', + PublishBatchRequestEntries: expectedEntries[0] + })})); + expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith(2, + expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: 'arn:aws:sns:region:account:topic', + PublishBatchRequestEntries: expectedEntries[1] + }) + }) + ); + + expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith(3, + expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: 'arn:aws:sns:region:account:topic', + PublishBatchRequestEntries: expectedEntries[2] + }) + }) + ); + }); + + function generateKinesisEvent(miEvents: Object[]): KinesisStreamEvent { + const records = miEvents + .map(mi => Buffer.from(JSON.stringify(mi), 'utf-8').toString('base64')) + .map(data => ({ kinesis: { data }} as unknown as KinesisStreamRecordPayload)); + return { Records: records } as unknown as KinesisStreamEvent; + } + function generateMIEvents(numMIEvents: number): MI[] { + return Array.from(Array(numMIEvents).keys()) + .map(i => ({ + id: String(i + 1), + lineItem: 'lineItem' + (i + 1), + timestamp: new Date().toISOString(), + quantity: 100 + i, + supplierId: 'supplier' + (i + 1), + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + ttl: Math.floor(Date.now() / 1000) + 3600, + specificationId: 'spec1', + groupId: 'group1', + stockRemaining: 500 - i, + })); + } +}); diff --git a/lambdas/mi-updates-transformer/src/deps.ts b/lambdas/mi-updates-transformer/src/deps.ts new file mode 100644 index 00000000..7f76c4a8 --- /dev/null +++ b/lambdas/mi-updates-transformer/src/deps.ts @@ -0,0 +1,24 @@ +import pino from 'pino'; +import { envVars, EnvVars } from "./env"; +import { SNSClient } from "@aws-sdk/client-sns"; + +export type Deps = { + snsClient: SNSClient; + logger: pino.Logger; + env: EnvVars; +}; + +function createSNSClient(): SNSClient { + return new SNSClient({}); +} + + +export function createDependenciesContainer(): Deps { + const log = pino(); + + return { + snsClient: createSNSClient(), + logger: log, + env: envVars + }; +} diff --git a/lambdas/mi-updates-transformer/src/env.ts b/lambdas/mi-updates-transformer/src/env.ts new file mode 100644 index 00000000..6c91e1de --- /dev/null +++ b/lambdas/mi-updates-transformer/src/env.ts @@ -0,0 +1,9 @@ +import {z} from 'zod'; + +const EnvVarsSchema = z.object({ + EVENT_PUB_SNS_TOPIC_ARN: z.string(), +}); + +export type EnvVars = z.infer; + +export const envVars = EnvVarsSchema.parse(process.env); diff --git a/lambdas/mi-updates-transformer/src/index.ts b/lambdas/mi-updates-transformer/src/index.ts new file mode 100644 index 00000000..f7c8a4df --- /dev/null +++ b/lambdas/mi-updates-transformer/src/index.ts @@ -0,0 +1,6 @@ +import { createHandler } from "./mi-updates-transformer"; +import { createDependenciesContainer } from "./deps"; + +const container = createDependenciesContainer(); + +export const handler = createHandler(container); diff --git a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts new file mode 100644 index 00000000..b8f0f755 --- /dev/null +++ b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts @@ -0,0 +1,46 @@ +import { $MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; +import { mapMIToCloudEvent } from "../mi-mapper"; +import { MI } from "@internal/datastore"; + +describe('mi-mapper', () => { + it('maps an MI to an MI event', async() => { + const mi: MI = { + id: 'id1', + lineItem: 'lineItem1', + timestamp: '2025-11-24T15:55:18Z', + quantity: 100, + supplierId: 'supplier1', + createdAt: '2025-11-24T15:55:18Z', + updatedAt: '2025-11-24T15:55:18Z', + ttl: 1735687518, + specificationId: 'spec1', + groupId: 'group1', + stockRemaining: 500 + }; + jest.useFakeTimers().setSystemTime(new Date('2025-11-24T15:55:18Z')); + const event = mapMIToCloudEvent(mi); + console.log("Mapped Event: ", event); + + // Check it conforms to the MI event schema - parse will throw an error if not + $MISubmittedEvent.parse(event); + expect(event.type).toBe('uk.nhs.notify.supplier-api.mi.SUBMITTED.v1'); + expect(event.dataschema).toBe('https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json'); + expect(event.subject).toBe('mi/id1'); + expect(event.time).toBe('2025-11-24T15:55:18.000Z'); + expect(event.recordedtime).toBe('2025-11-24T15:55:18.000Z'); + expect(event.data).toEqual({ + id: 'id1', + lineItem: 'lineItem1', + timestamp: '2025-11-24T15:55:18Z', + quantity: 100, + specificationId: 'spec1', + groupId: 'group1', + stockRemaining: 500, + supplierId: 'supplier1', + createdAt: '2025-11-24T15:55:18Z', + updatedAt: '2025-11-24T15:55:18Z' + }); + + jest.useRealTimers(); + }) +}); diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts new file mode 100644 index 00000000..3b206261 --- /dev/null +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -0,0 +1,34 @@ +import { MI } from '@internal/datastore'; +import { MISubmittedEvent } from '@nhsdigital/nhs-notify-event-schemas-supplier-api/src'; +import { randomUUID, randomBytes } from 'crypto'; + +export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { + const now = new Date().toISOString(); + const eventId = randomUUID(); + return { + specversion: '1.0', + id: eventId, + type: `uk.nhs.notify.supplier-api.mi.SUBMITTED.v1`, + dataschema: `https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json`, + source: '/data-plane/supplier-api/mi', + subject: 'mi/' + mi.id, + + data: { + id: mi.id as MISubmittedEvent['data']['id'], + lineItem: mi.lineItem, + timestamp: mi.timestamp, + quantity: mi.quantity, + supplierId: mi.supplierId, + createdAt: mi.createdAt, + updatedAt: mi.updatedAt, + specificationId: mi.specificationId, + groupId: mi.groupId, + stockRemaining: mi.stockRemaining + }, + time: now, + traceparent: `00-${randomBytes(16).toString('hex')}-${randomBytes(8).toString('hex')}-01`, + recordedtime: now, + severitynumber: 2, + severitytext: 'INFO', + }; +} diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts new file mode 100644 index 00000000..57d18c57 --- /dev/null +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -0,0 +1,43 @@ + +import { Handler, KinesisStreamEvent } from 'aws-lambda'; +import { mapMIToCloudEvent } from './mappers/mi-mapper'; +import { PublishBatchCommand, PublishBatchRequestEntry } from '@aws-sdk/client-sns'; +import { MISubmittedEvent } from '@nhsdigital/nhs-notify-event-schemas-supplier-api/src'; +import { Deps } from './deps'; +// SNS PublishBatchCommand supports up to 10 messages per batch +const BATCH_SIZE = 10; + +export function createHandler(deps: Deps): Handler { + return async(streamEvent: KinesisStreamEvent) => { + deps.logger.info({description: 'Received event', streamEvent}); + + const cloudEvents: MISubmittedEvent[] = streamEvent.Records + .map((record) => { + // Kinesis data is base64 encoded + const payload = Buffer.from(record.kinesis.data, 'base64').toString('utf-8'); + return JSON.parse(payload); + }) + .map(mapMIToCloudEvent); + + + for (let batch of generateBatches(cloudEvents)) { + await deps.snsClient.send(new PublishBatchCommand({ + TopicArn: deps.env.EVENT_PUB_SNS_TOPIC_ARN, + PublishBatchRequestEntries: batch.map(buildMessage), + })); + } + } + + function* generateBatches(events: MISubmittedEvent[]) { + for (let i = 0; i < events.length; i += BATCH_SIZE) { + yield events.slice(i, i + BATCH_SIZE); + } + } + + function buildMessage(event: MISubmittedEvent): PublishBatchRequestEntry { + return { + Id: event.id, + Message: JSON.stringify(event), + } + } +} diff --git a/lambdas/mi-updates-transformer/tsconfig.json b/lambdas/mi-updates-transformer/tsconfig.json new file mode 100644 index 00000000..ea37d696 --- /dev/null +++ b/lambdas/mi-updates-transformer/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "src/**/*", + "jest.config.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index 4d51a035..13662245 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3014,6 +3014,462 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "lambdas/mi-updates-transformer": { + "name": "nhs-notify-supplier-api-mi-updates-transformer", + "version": "0.0.1", + "dependencies": { + "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", + "esbuild": "^0.24.0" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.2", + "@types/aws-lambda": "^8.10.148", + "@types/jest": "^30.0.0", + "jest": "^30.2.0", + "jest-mock-extended": "^4.0.0", + "typescript": "^5.8.3" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "lambdas/mi-updates-transformer/node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, "lambdas/upsert-letter": { "name": "nhs-notify-supplier-api-upsert-letter", "version": "0.0.1", @@ -22760,6 +23216,10 @@ "resolved": "lambdas/letter-updates-transformer", "link": true }, + "node_modules/nhs-notify-supplier-api-mi-updates-transformer": { + "resolved": "lambdas/mi-updates-transformer", + "link": true + }, "node_modules/nhs-notify-supplier-api-suppliers-data-utility": { "resolved": "scripts/utilities/supplier-data", "link": true From 0d8cb2fbf152b5558138eeeb3a2d86febef45023 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 27 Nov 2025 11:00:33 +0000 Subject: [PATCH 05/21] Added terraform and stream forwarder --- .../terraform/components/api/README.md | 2 + .../terraform/components/api/ddb_table_mi.tf | 2 + .../api/event_source_mapping_mi_updates.tf | 23 ++++++ .../api/kinesis_mi_change_stream.tf | 5 ++ .../api/module_lambda_mi_stream_forwarder.tf | 73 ++++++++++++++++++ .../module_lambda_mi_updates_transformer.tf | 74 +++++++++++++++++++ lambdas/mi-stream-forwarder/.eslintignore | 1 + lambdas/mi-stream-forwarder/.gitignore | 4 + lambdas/mi-stream-forwarder/jest.config.ts | 60 +++++++++++++++ lambdas/mi-stream-forwarder/package.json | 21 ++++++ .../src/__tests__/mi-stream-forwarder.test.ts | 62 ++++++++++++++++ lambdas/mi-stream-forwarder/src/deps.ts | 14 ++++ lambdas/mi-stream-forwarder/src/env.ts | 9 +++ lambdas/mi-stream-forwarder/src/index.ts | 6 ++ .../src/mi-stream-forwarder.ts | 22 ++++++ lambdas/mi-stream-forwarder/tsconfig.json | 7 ++ package-lock.json | 15 ++++ 17 files changed, 400 insertions(+) create mode 100644 infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf create mode 100644 infrastructure/terraform/components/api/kinesis_mi_change_stream.tf create mode 100644 infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf create mode 100644 infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf create mode 100644 lambdas/mi-stream-forwarder/.eslintignore create mode 100644 lambdas/mi-stream-forwarder/.gitignore create mode 100644 lambdas/mi-stream-forwarder/jest.config.ts create mode 100644 lambdas/mi-stream-forwarder/package.json create mode 100644 lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts create mode 100644 lambdas/mi-stream-forwarder/src/deps.ts create mode 100644 lambdas/mi-stream-forwarder/src/env.ts create mode 100644 lambdas/mi-stream-forwarder/src/index.ts create mode 100644 lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts create mode 100644 lambdas/mi-stream-forwarder/tsconfig.json diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 150af054..9d188ae5 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -47,6 +47,8 @@ No requirements. | [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a | | [letter\_updates\_transformer](#module\_letter\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [logging\_bucket](#module\_logging\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-s3bucket.zip | n/a | +| [mi\_stream\_forwarder](#module\_mi\_stream\_forwarder) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | +| [mi\_updates\_transformer](#module\_mi\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [post\_letters](#module\_post\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a | | [post\_mi](#module\_post\_mi) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | diff --git a/infrastructure/terraform/components/api/ddb_table_mi.tf b/infrastructure/terraform/components/api/ddb_table_mi.tf index 712cd85d..7fdffb64 100644 --- a/infrastructure/terraform/components/api/ddb_table_mi.tf +++ b/infrastructure/terraform/components/api/ddb_table_mi.tf @@ -1,6 +1,8 @@ resource "aws_dynamodb_table" "mi" { name = "${local.csi}-mi" billing_mode = "PAY_PER_REQUEST" + stream_enabled = true + stream_view_type = "NEW_IMAGE" hash_key = "supplierId" range_key = "id" diff --git a/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf b/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf new file mode 100644 index 00000000..8acdae3d --- /dev/null +++ b/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf @@ -0,0 +1,23 @@ +resource "aws_lambda_event_source_mapping" "mi_stream_forwarder_dynamodb" { + event_source_arn = aws_dynamodb_table.mi.stream_arn + function_name = module.mi_stream_forwarder.function_arn + starting_position = "LATEST" + batch_size = 10 + maximum_batching_window_in_seconds = 1 + + depends_on = [ + module.mi_stream_forwarder # ensures stream forwarder exists + ] +} + +resource "aws_lambda_event_source_mapping" "mi_updates_transformer_kinesis" { + event_source_arn = aws_kinesis_stream.mi_change_stream.arn + function_name = module.mi_updates_transformer.function_arn + starting_position = "LATEST" + batch_size = 10 + maximum_batching_window_in_seconds = 1 + + depends_on = [ + module.mi_updates_transformer # ensures updates transformer exists + ] +} diff --git a/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf b/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf new file mode 100644 index 00000000..53465beb --- /dev/null +++ b/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf @@ -0,0 +1,5 @@ +resource "aws_kinesis_stream" "mi_change_stream" { + name = "mi-change-stream" + shard_count = 1 + retention_period = 24 +} diff --git a/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf b/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf new file mode 100644 index 00000000..cf8f1a50 --- /dev/null +++ b/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf @@ -0,0 +1,73 @@ +module "mi_stream_forwarder" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip" + + function_name = "mi-stream-forwarder" + description = "Kinesis stream forwarder for DDB mi status updates" + + 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.mi_stream_forwarder_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 = "mi-stream-forwarder/dist" + function_include_common = true + handler_function_name = "handler" + runtime = "nodejs22.x" + memory = 128 + timeout = 5 + log_level = var.log_level + + force_lambda_code_deploy = var.force_lambda_code_deploy + enable_lambda_insights = false + + send_to_firehose = true + log_destination_arn = local.destination_arn + log_subscription_role_arn = local.acct.log_subscription_role_arn + + lambda_env_vars = merge(local.common_lambda_env_vars, { + MI_CHANGE_STREAM_NAME = "mi_change_stream" + }) +} + +data "aws_iam_policy_document" "mi_stream_forwarder_lambda" { + + statement { + sid = "AllowDynamoDBStream" + effect = "Allow" + + actions = [ + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:DescribeStream", + "dynamodb:ListStreams", + ] + + resources = [ + "${aws_dynamodb_table.mi.arn}/stream/*" + ] + } + + statement { + sid = "AllowKinesisPut" + effect = "Allow" + + actions = [ + "kinesis:*" + ] + + resources = [ + aws_kinesis_stream.mi_change_stream.arn + ] + } +} diff --git a/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf b/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf new file mode 100644 index 00000000..cb208043 --- /dev/null +++ b/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf @@ -0,0 +1,74 @@ +module "mi_updates_transformer" { + source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip" + + function_name = "mi-updates-transformer" + description = "MI Update Filter/Producer" + + 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.mi_updates_transformer_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 = "mi-updates-transformer/dist" + function_include_common = true + handler_function_name = "handler" + runtime = "nodejs22.x" + memory = 128 + timeout = 5 + log_level = var.log_level + + force_lambda_code_deploy = var.force_lambda_code_deploy + enable_lambda_insights = false + + send_to_firehose = true + log_destination_arn = local.destination_arn + log_subscription_role_arn = local.acct.log_subscription_role_arn + + lambda_env_vars = merge(local.common_lambda_env_vars, { + EVENTPUB_SNS_TOPIC_ARN = module.eventpub.sns_topic.arn + }) +} + +data "aws_iam_policy_document" "mi_updates_transformer_lambda" { + statement { + sid = "AllowSNSPublish" + effect = "Allow" + + actions = [ + "sns:Publish" + ] + + resources = [ + module.eventpub.sns_topic.arn + ] + } + + statement { + sid = "AllowKinesisGet" + effect = "Allow" + + actions = [ + "kinesis:GetRecords", + "kinesis:GetShardIterator", + "kinesis:DescribeStream", + "kinesis:DescribeStreamSummary", + "kinesis:ListShards", + "kinesis:ListStreams", + ] + + resources = [ + aws_kinesis_stream.mi_change_stream.arn + ] + } +} diff --git a/lambdas/mi-stream-forwarder/.eslintignore b/lambdas/mi-stream-forwarder/.eslintignore new file mode 100644 index 00000000..1521c8b7 --- /dev/null +++ b/lambdas/mi-stream-forwarder/.eslintignore @@ -0,0 +1 @@ +dist diff --git a/lambdas/mi-stream-forwarder/.gitignore b/lambdas/mi-stream-forwarder/.gitignore new file mode 100644 index 00000000..80323f7c --- /dev/null +++ b/lambdas/mi-stream-forwarder/.gitignore @@ -0,0 +1,4 @@ +coverage +node_modules +dist +.reports diff --git a/lambdas/mi-stream-forwarder/jest.config.ts b/lambdas/mi-stream-forwarder/jest.config.ts new file mode 100644 index 00000000..d30f4cd1 --- /dev/null +++ b/lambdas/mi-stream-forwarder/jest.config.ts @@ -0,0 +1,60 @@ +import type { Config } from 'jest'; + +export const baseJestConfig: Config = { + preset: 'ts-jest', + + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // The directory where Jest should output its coverage files + coverageDirectory: './.reports/unit/coverage', + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'babel', + + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: -10, + }, + }, + + coveragePathIgnorePatterns: ['/__tests__/'], + transform: { '^.+\\.ts$': 'ts-jest' }, + testPathIgnorePatterns: ['.build'], + testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + + // Use this configuration option to add custom reporters to Jest + reporters: [ + 'default', + [ + 'jest-html-reporter', + { + pageTitle: 'Test Report', + outputPath: './.reports/unit/test-report.html', + includeFailureMsg: true, + }, + ], + ], + + // The test environment that will be used for testing + testEnvironment: 'jsdom', +}; + +const utilsJestConfig = { + ...baseJestConfig, + + testEnvironment: 'node', + + coveragePathIgnorePatterns: [ + ...(baseJestConfig.coveragePathIgnorePatterns ?? []), + 'zod-validators.ts', + ], +}; + +export default utilsJestConfig; diff --git a/lambdas/mi-stream-forwarder/package.json b/lambdas/mi-stream-forwarder/package.json new file mode 100644 index 00000000..3d0a201e --- /dev/null +++ b/lambdas/mi-stream-forwarder/package.json @@ -0,0 +1,21 @@ +{ + "dependencies": { + "@aws-sdk/client-kinesis": "^3.0.0", + "aws-lambda": "^1.0.7" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "typescript": "^5.0.0" + }, + "main": "src/index.ts", + "name": "mi-stream-forwarder", + "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.1.0" +} diff --git a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts new file mode 100644 index 00000000..657aa422 --- /dev/null +++ b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts @@ -0,0 +1,62 @@ +import { KinesisClient } from '@aws-sdk/client-kinesis'; +import { mockDeep } from 'jest-mock-extended'; +import { DynamoDBStreamEvent, Context } from 'aws-lambda'; +import { Deps } from '../deps'; +import { EnvVars } from '../env'; +import { createHandler } from '../mi-stream-forwarder'; + + +describe('mi-stream-forwarder Lambda', () => { + + const mockedDeps: jest.Mocked = { + kinesisClient: { send: jest.fn()} as unknown as KinesisClient, + env: { + MI_CHANGE_STREAM_NAME: "test-stream", + } as unknown as EnvVars + } as Deps; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('forwards INSERT records to Kinesis', async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: 'INSERT', + dynamodb: { + NewImage: { id: { S: 'mi-123' }, foo: { S: 'bar' } }, + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + StreamName: 'test-stream', + PartitionKey: 'mi-123', + }), + }) + ); + }); + + it('does not forward non-INSERT records', async () => { + const event: DynamoDBStreamEvent = { + Records: [ + { + eventName: 'MODIFY', + dynamodb: { + NewImage: { id: { S: 'mi-123' }, foo: { S: 'baz' } }, + }, + }, + ], + }; + + const handler = createHandler(mockedDeps); + await handler(event, mockDeep(), jest.fn()); + expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); + }); +}); diff --git a/lambdas/mi-stream-forwarder/src/deps.ts b/lambdas/mi-stream-forwarder/src/deps.ts new file mode 100644 index 00000000..c1a1808b --- /dev/null +++ b/lambdas/mi-stream-forwarder/src/deps.ts @@ -0,0 +1,14 @@ +import { KinesisClient } from '@aws-sdk/client-kinesis'; +import { envVars, EnvVars } from './env'; + +export type Deps = { + kinesisClient: KinesisClient; + env: EnvVars; +}; + +export function createDependenciesContainer(): Deps { + return { + kinesisClient: new KinesisClient({}), + env: envVars, + }; +} diff --git a/lambdas/mi-stream-forwarder/src/env.ts b/lambdas/mi-stream-forwarder/src/env.ts new file mode 100644 index 00000000..93336d9d --- /dev/null +++ b/lambdas/mi-stream-forwarder/src/env.ts @@ -0,0 +1,9 @@ +import { z } from 'zod'; + +const EnvVarsSchema = z.object({ + MI_CHANGE_STREAM_NAME: z.string(), +}); + +export type EnvVars = z.infer; + +export const envVars = EnvVarsSchema.parse(process.env); diff --git a/lambdas/mi-stream-forwarder/src/index.ts b/lambdas/mi-stream-forwarder/src/index.ts new file mode 100644 index 00000000..999b9a99 --- /dev/null +++ b/lambdas/mi-stream-forwarder/src/index.ts @@ -0,0 +1,6 @@ +import { createHandler } from "./mi-stream-forwarder"; +import { createDependenciesContainer } from "./deps"; + +const container = createDependenciesContainer(); + +export const handler = createHandler(container); diff --git a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts new file mode 100644 index 00000000..816c69f6 --- /dev/null +++ b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts @@ -0,0 +1,22 @@ +import { MI } from "@internal/datastore"; +import { DynamoDBStreamEvent, Handler } from "aws-lambda"; +import { PutRecordCommand } from "@aws-sdk/client-kinesis"; +import { Deps } from "./deps"; +import { unmarshall } from "@aws-sdk/util-dynamodb"; + +export function createHandler(deps: Deps): Handler { + return async (event: DynamoDBStreamEvent): Promise => { + const insertedRecords = event.Records + .filter(record => record.eventName === "INSERT"); + + for (const record of insertedRecords) { + const newImage = record.dynamodb?.NewImage!; + const miRecord = unmarshall(newImage as any) as MI; + await deps.kinesisClient.send(new PutRecordCommand({ + StreamName: deps.env.MI_CHANGE_STREAM_NAME, + PartitionKey: miRecord.id, + Data: Buffer.from(JSON.stringify(miRecord)), + })); + } + }; +} diff --git a/lambdas/mi-stream-forwarder/tsconfig.json b/lambdas/mi-stream-forwarder/tsconfig.json new file mode 100644 index 00000000..ea37d696 --- /dev/null +++ b/lambdas/mi-stream-forwarder/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@tsconfig/node22/tsconfig.json", + "include": [ + "src/**/*", + "jest.config.ts" + ] +} diff --git a/package-lock.json b/package-lock.json index 13662245..79128371 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3014,6 +3014,17 @@ "url": "https://github.com/sponsors/colinhacks" } }, + "lambdas/mi-stream-forwarder": { + "version": "0.1.0", + "dependencies": { + "@aws-sdk/client-kinesis": "^3.0.0", + "aws-lambda": "^1.0.7" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "typescript": "^5.0.0" + } + }, "lambdas/mi-updates-transformer": { "name": "nhs-notify-supplier-api-mi-updates-transformer", "version": "0.0.1", @@ -22918,6 +22929,10 @@ "node": ">= 8" } }, + "node_modules/mi-stream-forwarder": { + "resolved": "lambdas/mi-stream-forwarder", + "link": true + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", From db2615669911987dd4c7c8560f1491b35a95e285 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 27 Nov 2025 14:14:02 +0000 Subject: [PATCH 06/21] Unique stream name --- .../terraform/components/api/kinesis_mi_change_stream.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf b/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf index 53465beb..8afff084 100644 --- a/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf +++ b/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf @@ -1,5 +1,5 @@ resource "aws_kinesis_stream" "mi_change_stream" { - name = "mi-change-stream" + name = "${local.csi}-mi-change-stream" shard_count = 1 retention_period = 24 } From 530bf6801c774cff6e3d08a0152a067b5f010669 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 27 Nov 2025 14:45:55 +0000 Subject: [PATCH 07/21] copy fixes from base commit --- .../components/api/module_lambda_mi_stream_forwarder.tf | 5 +++-- .../components/api/module_lambda_mi_updates_transformer.tf | 2 +- .../src/__tests__/mi-stream-forwarder.test.ts | 4 ++-- lambdas/mi-stream-forwarder/src/env.ts | 2 +- lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts | 2 +- .../src/__tests__/mi-updates-transformer.test.ts | 2 +- lambdas/mi-updates-transformer/src/env.ts | 2 +- lambdas/mi-updates-transformer/src/mi-updates-transformer.ts | 2 +- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf b/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf index cf8f1a50..e8c3dc88 100644 --- a/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf +++ b/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf @@ -36,7 +36,7 @@ module "mi_stream_forwarder" { log_subscription_role_arn = local.acct.log_subscription_role_arn lambda_env_vars = merge(local.common_lambda_env_vars, { - MI_CHANGE_STREAM_NAME = "mi_change_stream" + MI_CHANGE_STREAM_ARN = "${aws_kinesis_stream.mi_change_stream.arn}" }) } @@ -63,7 +63,8 @@ data "aws_iam_policy_document" "mi_stream_forwarder_lambda" { effect = "Allow" actions = [ - "kinesis:*" + "kinesis:DescribeStream", + "kinesis:PutRecord", ] resources = [ diff --git a/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf b/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf index cb208043..4a63ba51 100644 --- a/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf +++ b/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf @@ -36,7 +36,7 @@ module "mi_updates_transformer" { log_subscription_role_arn = local.acct.log_subscription_role_arn lambda_env_vars = merge(local.common_lambda_env_vars, { - EVENTPUB_SNS_TOPIC_ARN = module.eventpub.sns_topic.arn + EVENTPUB_SNS_TOPIC_ARN = "${module.eventpub.sns_topic.arn}" }) } diff --git a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts index 657aa422..83da797f 100644 --- a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts +++ b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts @@ -11,7 +11,7 @@ describe('mi-stream-forwarder Lambda', () => { const mockedDeps: jest.Mocked = { kinesisClient: { send: jest.fn()} as unknown as KinesisClient, env: { - MI_CHANGE_STREAM_NAME: "test-stream", + MI_CHANGE_STREAM_ARN: "test-stream", } as unknown as EnvVars } as Deps; @@ -36,7 +36,7 @@ describe('mi-stream-forwarder Lambda', () => { expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( expect.objectContaining({ input: expect.objectContaining({ - StreamName: 'test-stream', + StreamARN: 'test-stream', PartitionKey: 'mi-123', }), }) diff --git a/lambdas/mi-stream-forwarder/src/env.ts b/lambdas/mi-stream-forwarder/src/env.ts index 93336d9d..136da191 100644 --- a/lambdas/mi-stream-forwarder/src/env.ts +++ b/lambdas/mi-stream-forwarder/src/env.ts @@ -1,7 +1,7 @@ import { z } from 'zod'; const EnvVarsSchema = z.object({ - MI_CHANGE_STREAM_NAME: z.string(), + MI_CHANGE_STREAM_ARN: z.string(), }); export type EnvVars = z.infer; diff --git a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts index 816c69f6..8e4de2d4 100644 --- a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts +++ b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts @@ -13,7 +13,7 @@ export function createHandler(deps: Deps): Handler { const newImage = record.dynamodb?.NewImage!; const miRecord = unmarshall(newImage as any) as MI; await deps.kinesisClient.send(new PutRecordCommand({ - StreamName: deps.env.MI_CHANGE_STREAM_NAME, + StreamARN: deps.env.MI_CHANGE_STREAM_ARN, PartitionKey: miRecord.id, Data: Buffer.from(JSON.stringify(miRecord)), })); diff --git a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts index 69f83cb4..73abc82d 100644 --- a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts +++ b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts @@ -22,7 +22,7 @@ describe('mi-updates-transformer Lambda', () => { snsClient: { send: jest.fn()} as unknown as SNSClient, logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger, env: { - EVENT_PUB_SNS_TOPIC_ARN: 'arn:aws:sns:region:account:topic', + EVENTPUB_SNS_TOPIC_ARN: 'arn:aws:sns:region:account:topic', } as unknown as EnvVars } as Deps; diff --git a/lambdas/mi-updates-transformer/src/env.ts b/lambdas/mi-updates-transformer/src/env.ts index 6c91e1de..b719bcfe 100644 --- a/lambdas/mi-updates-transformer/src/env.ts +++ b/lambdas/mi-updates-transformer/src/env.ts @@ -1,7 +1,7 @@ import {z} from 'zod'; const EnvVarsSchema = z.object({ - EVENT_PUB_SNS_TOPIC_ARN: z.string(), + EVENTPUB_SNS_TOPIC_ARN: z.string(), }); export type EnvVars = z.infer; diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index 57d18c57..1565e895 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -22,7 +22,7 @@ export function createHandler(deps: Deps): Handler { for (let batch of generateBatches(cloudEvents)) { await deps.snsClient.send(new PublishBatchCommand({ - TopicArn: deps.env.EVENT_PUB_SNS_TOPIC_ARN, + TopicArn: deps.env.EVENTPUB_SNS_TOPIC_ARN, PublishBatchRequestEntries: batch.map(buildMessage), })); } From 438588af097c8699fb69bb5372cff6dde9b1c327 Mon Sep 17 00:00:00 2001 From: David Wass Date: Mon, 1 Dec 2025 13:42:27 +0000 Subject: [PATCH 08/21] new envelope fields --- lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts index 3b206261..3659f9a9 100644 --- a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -5,11 +5,15 @@ import { randomUUID, randomBytes } from 'crypto'; export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { const now = new Date().toISOString(); const eventId = randomUUID(); + const dataschemaversion = '1.0.0'; + return { specversion: '1.0', id: eventId, type: `uk.nhs.notify.supplier-api.mi.SUBMITTED.v1`, - dataschema: `https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json`, + plane: 'data-plane', + dataschema: `https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.${dataschemaversion}.schema.json`, + dataschemaversion, source: '/data-plane/supplier-api/mi', subject: 'mi/' + mi.id, @@ -26,6 +30,7 @@ export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { stockRemaining: mi.stockRemaining }, time: now, + datacontenttype: 'application/json', traceparent: `00-${randomBytes(16).toString('hex')}-${randomBytes(8).toString('hex')}-01`, recordedtime: now, severitynumber: 2, From 24aa051c229f647bf0c6e78c526fd81e691a4d24 Mon Sep 17 00:00:00 2001 From: David Wass Date: Mon, 1 Dec 2025 15:20:49 +0000 Subject: [PATCH 09/21] logging --- .../src/__tests__/mi-stream-forwarder.test.ts | 2 ++ lambdas/mi-stream-forwarder/src/deps.ts | 3 +++ lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts | 2 ++ 3 files changed, 7 insertions(+) diff --git a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts index 83da797f..abdce9ff 100644 --- a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts +++ b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts @@ -1,4 +1,5 @@ import { KinesisClient } from '@aws-sdk/client-kinesis'; +import * as pino from "pino"; import { mockDeep } from 'jest-mock-extended'; import { DynamoDBStreamEvent, Context } from 'aws-lambda'; import { Deps } from '../deps'; @@ -10,6 +11,7 @@ describe('mi-stream-forwarder Lambda', () => { const mockedDeps: jest.Mocked = { kinesisClient: { send: jest.fn()} as unknown as KinesisClient, + logger: { info: jest.fn(), warn: jest.fn(), error: jest.fn() } as unknown as pino.Logger, env: { MI_CHANGE_STREAM_ARN: "test-stream", } as unknown as EnvVars diff --git a/lambdas/mi-stream-forwarder/src/deps.ts b/lambdas/mi-stream-forwarder/src/deps.ts index c1a1808b..8c5c9d0b 100644 --- a/lambdas/mi-stream-forwarder/src/deps.ts +++ b/lambdas/mi-stream-forwarder/src/deps.ts @@ -1,14 +1,17 @@ +import pino from 'pino'; import { KinesisClient } from '@aws-sdk/client-kinesis'; import { envVars, EnvVars } from './env'; export type Deps = { kinesisClient: KinesisClient; + logger: pino.Logger; env: EnvVars; }; export function createDependenciesContainer(): Deps { return { kinesisClient: new KinesisClient({}), + logger: pino(), env: envVars, }; } diff --git a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts index 8e4de2d4..c08220f7 100644 --- a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts +++ b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts @@ -3,9 +3,11 @@ import { DynamoDBStreamEvent, Handler } from "aws-lambda"; import { PutRecordCommand } from "@aws-sdk/client-kinesis"; import { Deps } from "./deps"; import { unmarshall } from "@aws-sdk/util-dynamodb"; +import { Logger } from "pino"; export function createHandler(deps: Deps): Handler { return async (event: DynamoDBStreamEvent): Promise => { + deps.logger.info({description: "Received event", event}); const insertedRecords = event.Records .filter(record => record.eventName === "INSERT"); From 42f1d30f52bbe05ec4d96c1e2411ef1f16350913 Mon Sep 17 00:00:00 2001 From: David Wass Date: Tue, 2 Dec 2025 09:57:06 +0000 Subject: [PATCH 10/21] lint fixes --- lambdas/mi-stream-forwarder/jest.config.ts | 30 +-- lambdas/mi-stream-forwarder/package.json | 7 +- .../src/__tests__/mi-stream-forwarder.test.ts | 44 ++-- lambdas/mi-stream-forwarder/src/deps.ts | 6 +- lambdas/mi-stream-forwarder/src/env.ts | 2 +- lambdas/mi-stream-forwarder/src/index.ts | 3 +- .../src/mi-stream-forwarder.ts | 26 ++- lambdas/mi-updates-transformer/jest.config.ts | 30 +-- lambdas/mi-updates-transformer/package.json | 7 +- .../__tests__/mi-updates-transformer.test.ts | 219 +++++++++++------- lambdas/mi-updates-transformer/src/deps.ts | 7 +- lambdas/mi-updates-transformer/src/env.ts | 2 +- lambdas/mi-updates-transformer/src/index.ts | 4 +- .../src/mappers/__tests__/mi-mapper.test.ts | 59 ++--- .../src/mappers/mi-mapper.ts | 28 +-- .../src/mi-updates-transformer.ts | 75 +++--- 16 files changed, 308 insertions(+), 241 deletions(-) diff --git a/lambdas/mi-stream-forwarder/jest.config.ts b/lambdas/mi-stream-forwarder/jest.config.ts index d30f4cd1..f88e7277 100644 --- a/lambdas/mi-stream-forwarder/jest.config.ts +++ b/lambdas/mi-stream-forwarder/jest.config.ts @@ -1,7 +1,7 @@ -import type { Config } from 'jest'; +import type { Config } from "jest"; export const baseJestConfig: Config = { - preset: 'ts-jest', + preset: "ts-jest", // Automatically clear mock calls, instances, contexts and results before every test clearMocks: true, @@ -10,10 +10,10 @@ export const baseJestConfig: Config = { collectCoverage: true, // The directory where Jest should output its coverage files - coverageDirectory: './.reports/unit/coverage', + coverageDirectory: "./.reports/unit/coverage", // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'babel', + coverageProvider: "babel", coverageThreshold: { global: { @@ -24,36 +24,36 @@ export const baseJestConfig: Config = { }, }, - coveragePathIgnorePatterns: ['/__tests__/'], - transform: { '^.+\\.ts$': 'ts-jest' }, - testPathIgnorePatterns: ['.build'], - testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + coveragePathIgnorePatterns: ["/__tests__/"], + transform: { "^.+\\.ts$": "ts-jest" }, + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], // Use this configuration option to add custom reporters to Jest reporters: [ - 'default', + "default", [ - 'jest-html-reporter', + "jest-html-reporter", { - pageTitle: 'Test Report', - outputPath: './.reports/unit/test-report.html', + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", includeFailureMsg: true, }, ], ], // The test environment that will be used for testing - testEnvironment: 'jsdom', + testEnvironment: "jsdom", }; const utilsJestConfig = { ...baseJestConfig, - testEnvironment: 'node', + testEnvironment: "node", coveragePathIgnorePatterns: [ ...(baseJestConfig.coveragePathIgnorePatterns ?? []), - 'zod-validators.ts', + "zod-validators.ts", ], }; diff --git a/lambdas/mi-stream-forwarder/package.json b/lambdas/mi-stream-forwarder/package.json index 3d0a201e..bcab62db 100644 --- a/lambdas/mi-stream-forwarder/package.json +++ b/lambdas/mi-stream-forwarder/package.json @@ -1,7 +1,12 @@ { "dependencies": { "@aws-sdk/client-kinesis": "^3.0.0", - "aws-lambda": "^1.0.7" + "@aws-sdk/util-dynamodb": "^3.940.0", + "@internal/datastore": "^0.1.0", + "aws-lambda": "^1.0.7", + "jest-mock-extended": "^4.0.0", + "pino": "^10.1.0", + "zod": "^4.1.13" }, "devDependencies": { "@types/aws-lambda": "^8.10.119", diff --git a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts index abdce9ff..ce4dd439 100644 --- a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts +++ b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts @@ -1,33 +1,35 @@ -import { KinesisClient } from '@aws-sdk/client-kinesis'; +import { KinesisClient } from "@aws-sdk/client-kinesis"; import * as pino from "pino"; -import { mockDeep } from 'jest-mock-extended'; -import { DynamoDBStreamEvent, Context } from 'aws-lambda'; -import { Deps } from '../deps'; -import { EnvVars } from '../env'; -import { createHandler } from '../mi-stream-forwarder'; - - -describe('mi-stream-forwarder Lambda', () => { +import { mockDeep } from "jest-mock-extended"; +import { Context, DynamoDBStreamEvent } from "aws-lambda"; +import { Deps } from "../deps"; +import { EnvVars } from "../env"; +import createHandler from "../mi-stream-forwarder"; +describe("mi-stream-forwarder Lambda", () => { const mockedDeps: jest.Mocked = { - kinesisClient: { send: jest.fn()} as unknown as KinesisClient, - logger: { info: jest.fn(), warn: jest.fn(), error: jest.fn() } as unknown as pino.Logger, + kinesisClient: { send: jest.fn() } as unknown as KinesisClient, + logger: { + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + } as unknown as pino.Logger, env: { MI_CHANGE_STREAM_ARN: "test-stream", - } as unknown as EnvVars + } as unknown as EnvVars, } as Deps; beforeEach(() => { jest.clearAllMocks(); }); - it('forwards INSERT records to Kinesis', async () => { + it("forwards INSERT records to Kinesis", async () => { const event: DynamoDBStreamEvent = { Records: [ { - eventName: 'INSERT', + eventName: "INSERT", dynamodb: { - NewImage: { id: { S: 'mi-123' }, foo: { S: 'bar' } }, + NewImage: { id: { S: "mi-123" }, foo: { S: "bar" } }, }, }, ], @@ -38,20 +40,20 @@ describe('mi-stream-forwarder Lambda', () => { expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( expect.objectContaining({ input: expect.objectContaining({ - StreamARN: 'test-stream', - PartitionKey: 'mi-123', + StreamARN: "test-stream", + PartitionKey: "mi-123", }), - }) + }), ); }); - it('does not forward non-INSERT records', async () => { + it("does not forward non-INSERT records", async () => { const event: DynamoDBStreamEvent = { Records: [ { - eventName: 'MODIFY', + eventName: "MODIFY", dynamodb: { - NewImage: { id: { S: 'mi-123' }, foo: { S: 'baz' } }, + NewImage: { id: { S: "mi-123" }, foo: { S: "baz" } }, }, }, ], diff --git a/lambdas/mi-stream-forwarder/src/deps.ts b/lambdas/mi-stream-forwarder/src/deps.ts index 8c5c9d0b..b051e20b 100644 --- a/lambdas/mi-stream-forwarder/src/deps.ts +++ b/lambdas/mi-stream-forwarder/src/deps.ts @@ -1,6 +1,6 @@ -import pino from 'pino'; -import { KinesisClient } from '@aws-sdk/client-kinesis'; -import { envVars, EnvVars } from './env'; +import pino from "pino"; +import { KinesisClient } from "@aws-sdk/client-kinesis"; +import { EnvVars, envVars } from "./env"; export type Deps = { kinesisClient: KinesisClient; diff --git a/lambdas/mi-stream-forwarder/src/env.ts b/lambdas/mi-stream-forwarder/src/env.ts index 136da191..df8d9d04 100644 --- a/lambdas/mi-stream-forwarder/src/env.ts +++ b/lambdas/mi-stream-forwarder/src/env.ts @@ -1,4 +1,4 @@ -import { z } from 'zod'; +import { z } from "zod"; const EnvVarsSchema = z.object({ MI_CHANGE_STREAM_ARN: z.string(), diff --git a/lambdas/mi-stream-forwarder/src/index.ts b/lambdas/mi-stream-forwarder/src/index.ts index 999b9a99..f7e9ed4a 100644 --- a/lambdas/mi-stream-forwarder/src/index.ts +++ b/lambdas/mi-stream-forwarder/src/index.ts @@ -3,4 +3,5 @@ import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); -export const handler = createHandler(container); +const handler = createHandler(container); +export default handler; diff --git a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts index c08220f7..c4a27d9c 100644 --- a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts +++ b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts @@ -1,24 +1,28 @@ import { MI } from "@internal/datastore"; import { DynamoDBStreamEvent, Handler } from "aws-lambda"; import { PutRecordCommand } from "@aws-sdk/client-kinesis"; -import { Deps } from "./deps"; import { unmarshall } from "@aws-sdk/util-dynamodb"; -import { Logger } from "pino"; +import { Deps } from "./deps"; -export function createHandler(deps: Deps): Handler { +export default function createHandler( + deps: Deps, +): Handler { return async (event: DynamoDBStreamEvent): Promise => { - deps.logger.info({description: "Received event", event}); - const insertedRecords = event.Records - .filter(record => record.eventName === "INSERT"); + deps.logger.info({ description: "Received event", event }); + const insertedRecords = event.Records.filter( + (record) => record.eventName === "INSERT", + ); for (const record of insertedRecords) { const newImage = record.dynamodb?.NewImage!; const miRecord = unmarshall(newImage as any) as MI; - await deps.kinesisClient.send(new PutRecordCommand({ - StreamARN: deps.env.MI_CHANGE_STREAM_ARN, - PartitionKey: miRecord.id, - Data: Buffer.from(JSON.stringify(miRecord)), - })); + await deps.kinesisClient.send( + new PutRecordCommand({ + StreamARN: deps.env.MI_CHANGE_STREAM_ARN, + PartitionKey: miRecord.id, + Data: Buffer.from(JSON.stringify(miRecord)), + }), + ); } }; } diff --git a/lambdas/mi-updates-transformer/jest.config.ts b/lambdas/mi-updates-transformer/jest.config.ts index d30f4cd1..f88e7277 100644 --- a/lambdas/mi-updates-transformer/jest.config.ts +++ b/lambdas/mi-updates-transformer/jest.config.ts @@ -1,7 +1,7 @@ -import type { Config } from 'jest'; +import type { Config } from "jest"; export const baseJestConfig: Config = { - preset: 'ts-jest', + preset: "ts-jest", // Automatically clear mock calls, instances, contexts and results before every test clearMocks: true, @@ -10,10 +10,10 @@ export const baseJestConfig: Config = { collectCoverage: true, // The directory where Jest should output its coverage files - coverageDirectory: './.reports/unit/coverage', + coverageDirectory: "./.reports/unit/coverage", // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'babel', + coverageProvider: "babel", coverageThreshold: { global: { @@ -24,36 +24,36 @@ export const baseJestConfig: Config = { }, }, - coveragePathIgnorePatterns: ['/__tests__/'], - transform: { '^.+\\.ts$': 'ts-jest' }, - testPathIgnorePatterns: ['.build'], - testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'], + coveragePathIgnorePatterns: ["/__tests__/"], + transform: { "^.+\\.ts$": "ts-jest" }, + testPathIgnorePatterns: [".build"], + testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], // Use this configuration option to add custom reporters to Jest reporters: [ - 'default', + "default", [ - 'jest-html-reporter', + "jest-html-reporter", { - pageTitle: 'Test Report', - outputPath: './.reports/unit/test-report.html', + pageTitle: "Test Report", + outputPath: "./.reports/unit/test-report.html", includeFailureMsg: true, }, ], ], // The test environment that will be used for testing - testEnvironment: 'jsdom', + testEnvironment: "jsdom", }; const utilsJestConfig = { ...baseJestConfig, - testEnvironment: 'node', + testEnvironment: "node", coveragePathIgnorePatterns: [ ...(baseJestConfig.coveragePathIgnorePatterns ?? []), - 'zod-validators.ts', + "zod-validators.ts", ], }; diff --git a/lambdas/mi-updates-transformer/package.json b/lambdas/mi-updates-transformer/package.json index 16d8bc8d..8f0f0c36 100644 --- a/lambdas/mi-updates-transformer/package.json +++ b/lambdas/mi-updates-transformer/package.json @@ -1,7 +1,12 @@ { "dependencies": { + "@aws-sdk/client-sns": "^3.940.0", + "@internal/datastore": "^0.1.0", "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", - "esbuild": "^0.24.0" + "aws-lambda": "^1.0.7", + "esbuild": "^0.24.0", + "pino": "^10.1.0", + "zod": "^4.1.13" }, "devDependencies": { "@tsconfig/node22": "^22.0.2", diff --git a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts index 73abc82d..945d4441 100644 --- a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts +++ b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts @@ -1,29 +1,60 @@ -import { SNSClient } from '@aws-sdk/client-sns'; -import * as pino from 'pino'; -import { createHandler } from '../mi-updates-transformer'; -import { KinesisStreamEvent, Context, KinesisStreamRecordPayload } from 'aws-lambda'; -import { mockDeep } from 'jest-mock-extended'; -import { Deps } from '../deps'; -import { EnvVars } from '../env'; -import { MI } from '@internal/datastore'; -import { mapMIToCloudEvent } from '../mappers/mi-mapper'; +import { SNSClient } from "@aws-sdk/client-sns"; +import * as pino from "pino"; +import { + Context, + KinesisStreamEvent, + KinesisStreamRecordPayload, +} from "aws-lambda"; +import { mockDeep } from "jest-mock-extended"; +import { MI } from "@internal/datastore"; +import createHandler from "../mi-updates-transformer"; +import { Deps } from "../deps"; +import { EnvVars } from "../env"; +import mapMIToCloudEvent from "../mappers/mi-mapper"; // Make crypto return consistent values, since we're calling it in both prod and test code and comparing the values -const realCrypto = jest.requireActual('crypto'); -const randomBytes: Record = {'8': realCrypto.randomBytes(8), '16': realCrypto.randomBytes(16)} -jest.mock('crypto', () => ({ - randomUUID: () => '4616b2d9-b7a5-45aa-8523-fa7419626b69', - randomBytes: (size: number) => randomBytes[String(size)] +const realCrypto = jest.requireActual("crypto"); +const randomBytes: Record = { + "8": realCrypto.randomBytes(8), + "16": realCrypto.randomBytes(16), +}; +jest.mock("crypto", () => ({ + randomUUID: () => "4616b2d9-b7a5-45aa-8523-fa7419626b69", + randomBytes: (size: number) => randomBytes[String(size)], })); -describe('mi-updates-transformer Lambda', () => { - +function generateKinesisEvent(miEvents: object[]): KinesisStreamEvent { + const records = miEvents + .map((mi) => Buffer.from(JSON.stringify(mi), "utf8").toString("base64")) + .map( + (data) => + ({ kinesis: { data } }) as unknown as KinesisStreamRecordPayload, + ); + return { Records: records } as unknown as KinesisStreamEvent; +} +function generateMIEvents(numMIEvents: number): MI[] { + return [...Array.from({ length: numMIEvents }).keys()].map((i) => ({ + id: String(i + 1), + lineItem: `lineItem${i + 1}`, + timestamp: new Date().toISOString(), + quantity: 100 + i, + supplierId: `supplier${i + 1}`, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + ttl: Math.floor(Date.now() / 1000) + 3600, + specificationId: "spec1", + groupId: "group1", + stockRemaining: 500 - i, + })); +} + +describe("mi-updates-transformer Lambda", () => { const mockedDeps: jest.Mocked = { - snsClient: { send: jest.fn()} as unknown as SNSClient, - logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger, + snsClient: { send: jest.fn() } as unknown as SNSClient, + logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger, env: { - EVENTPUB_SNS_TOPIC_ARN: 'arn:aws:sns:region:account:topic', - } as unknown as EnvVars + EVENTPUB_SNS_TOPIC_ARN: "arn:aws:sns:region:account:topic", + } as unknown as EnvVars, } as Deps; beforeEach(() => { @@ -32,102 +63,112 @@ describe('mi-updates-transformer Lambda', () => { afterEach(() => { jest.useRealTimers(); - }) - - it('processes Kinesis events and publishes them to SNS', async () => { + }); + it("processes Kinesis events and publishes them to SNS", async () => { const handler = createHandler(mockedDeps); const miEvents = generateMIEvents(1); - const expectedEntries = [expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvents[0]))})]; + const expectedEntries = [ + expect.objectContaining({ + Message: JSON.stringify(mapMIToCloudEvent(miEvents[0])), + }), + ]; - await handler(generateKinesisEvent(miEvents), mockDeep(), jest.fn()); + await handler( + generateKinesisEvent(miEvents), + mockDeep(), + jest.fn(), + ); - expect(mockedDeps.snsClient.send).toHaveBeenCalledWith(expect.objectContaining({ - input: expect.objectContaining({ - TopicArn: 'arn:aws:sns:region:account:topic', - PublishBatchRequestEntries: expectedEntries - }) - })); + expect(mockedDeps.snsClient.send).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: "arn:aws:sns:region:account:topic", + PublishBatchRequestEntries: expectedEntries, + }), + }), + ); }); - it ('batches mutiple records into a single call to SNS', async () => { - + it("batches mutiple records into a single call to SNS", async () => { const handler = createHandler(mockedDeps); const miEvents = generateMIEvents(10); - const expectedEntries = miEvents.map(miEvent => - expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})); + const expectedEntries = miEvents.map((miEvent) => + expect.objectContaining({ + Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + }), + ); - await handler(generateKinesisEvent(miEvents), mockDeep(), jest.fn()); + await handler( + generateKinesisEvent(miEvents), + mockDeep(), + jest.fn(), + ); - expect(mockedDeps.snsClient.send).toHaveBeenCalledWith(expect.objectContaining({ - input: expect.objectContaining({ - TopicArn: 'arn:aws:sns:region:account:topic', - PublishBatchRequestEntries: expectedEntries - }) - })); + expect(mockedDeps.snsClient.send).toHaveBeenCalledWith( + expect.objectContaining({ + input: expect.objectContaining({ + TopicArn: "arn:aws:sns:region:account:topic", + PublishBatchRequestEntries: expectedEntries, + }), + }), + ); }); - - it('splits more than 10 records into multiple SNS calls', async () => { - + it("splits more than 10 records into multiple SNS calls", async () => { const handler = createHandler(mockedDeps); const miEvents = generateMIEvents(21); const expectedEntries = [ - miEvents.slice(0, 10).map(miEvent => - expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})), - miEvents.slice(10, 20).map(miEvent => - expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})), - miEvents.slice(20).map(miEvent => - expect.objectContaining({Message: JSON.stringify(mapMIToCloudEvent(miEvent))})), + miEvents.slice(0, 10).map((miEvent) => + expect.objectContaining({ + Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + }), + ), + miEvents.slice(10, 20).map((miEvent) => + expect.objectContaining({ + Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + }), + ), + miEvents.slice(20).map((miEvent) => + expect.objectContaining({ + Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + }), + ), ]; - await handler(generateKinesisEvent(miEvents), mockDeep(), jest.fn()); + await handler( + generateKinesisEvent(miEvents), + mockDeep(), + jest.fn(), + ); - expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith(1, + expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith( + 1, expect.objectContaining({ input: expect.objectContaining({ - TopicArn: 'arn:aws:sns:region:account:topic', - PublishBatchRequestEntries: expectedEntries[0] - })})); - expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith(2, + TopicArn: "arn:aws:sns:region:account:topic", + PublishBatchRequestEntries: expectedEntries[0], + }), + }), + ); + expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith( + 2, expect.objectContaining({ input: expect.objectContaining({ - TopicArn: 'arn:aws:sns:region:account:topic', - PublishBatchRequestEntries: expectedEntries[1] - }) - }) + TopicArn: "arn:aws:sns:region:account:topic", + PublishBatchRequestEntries: expectedEntries[1], + }), + }), ); - expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith(3, + expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith( + 3, expect.objectContaining({ input: expect.objectContaining({ - TopicArn: 'arn:aws:sns:region:account:topic', - PublishBatchRequestEntries: expectedEntries[2] - }) - }) + TopicArn: "arn:aws:sns:region:account:topic", + PublishBatchRequestEntries: expectedEntries[2], + }), + }), ); }); - - function generateKinesisEvent(miEvents: Object[]): KinesisStreamEvent { - const records = miEvents - .map(mi => Buffer.from(JSON.stringify(mi), 'utf-8').toString('base64')) - .map(data => ({ kinesis: { data }} as unknown as KinesisStreamRecordPayload)); - return { Records: records } as unknown as KinesisStreamEvent; - } - function generateMIEvents(numMIEvents: number): MI[] { - return Array.from(Array(numMIEvents).keys()) - .map(i => ({ - id: String(i + 1), - lineItem: 'lineItem' + (i + 1), - timestamp: new Date().toISOString(), - quantity: 100 + i, - supplierId: 'supplier' + (i + 1), - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - ttl: Math.floor(Date.now() / 1000) + 3600, - specificationId: 'spec1', - groupId: 'group1', - stockRemaining: 500 - i, - })); - } }); diff --git a/lambdas/mi-updates-transformer/src/deps.ts b/lambdas/mi-updates-transformer/src/deps.ts index 7f76c4a8..9332410e 100644 --- a/lambdas/mi-updates-transformer/src/deps.ts +++ b/lambdas/mi-updates-transformer/src/deps.ts @@ -1,6 +1,6 @@ -import pino from 'pino'; -import { envVars, EnvVars } from "./env"; +import pino from "pino"; import { SNSClient } from "@aws-sdk/client-sns"; +import { EnvVars, envVars } from "./env"; export type Deps = { snsClient: SNSClient; @@ -12,13 +12,12 @@ function createSNSClient(): SNSClient { return new SNSClient({}); } - export function createDependenciesContainer(): Deps { const log = pino(); return { snsClient: createSNSClient(), logger: log, - env: envVars + env: envVars, }; } diff --git a/lambdas/mi-updates-transformer/src/env.ts b/lambdas/mi-updates-transformer/src/env.ts index b719bcfe..f93bbf39 100644 --- a/lambdas/mi-updates-transformer/src/env.ts +++ b/lambdas/mi-updates-transformer/src/env.ts @@ -1,4 +1,4 @@ -import {z} from 'zod'; +import { z } from "zod"; const EnvVarsSchema = z.object({ EVENTPUB_SNS_TOPIC_ARN: z.string(), diff --git a/lambdas/mi-updates-transformer/src/index.ts b/lambdas/mi-updates-transformer/src/index.ts index f7c8a4df..91e8433c 100644 --- a/lambdas/mi-updates-transformer/src/index.ts +++ b/lambdas/mi-updates-transformer/src/index.ts @@ -3,4 +3,6 @@ import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); -export const handler = createHandler(container); +const handler = createHandler(container); + +export default handler; diff --git a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts index b8f0f755..b46ceddc 100644 --- a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts +++ b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts @@ -1,46 +1,47 @@ import { $MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; -import { mapMIToCloudEvent } from "../mi-mapper"; import { MI } from "@internal/datastore"; +import mapMIToCloudEvent from "../mi-mapper"; -describe('mi-mapper', () => { - it('maps an MI to an MI event', async() => { +describe("mi-mapper", () => { + it("maps an MI to an MI event", async () => { const mi: MI = { - id: 'id1', - lineItem: 'lineItem1', - timestamp: '2025-11-24T15:55:18Z', + id: "id1", + lineItem: "lineItem1", + timestamp: "2025-11-24T15:55:18Z", quantity: 100, - supplierId: 'supplier1', - createdAt: '2025-11-24T15:55:18Z', - updatedAt: '2025-11-24T15:55:18Z', - ttl: 1735687518, - specificationId: 'spec1', - groupId: 'group1', - stockRemaining: 500 + supplierId: "supplier1", + createdAt: "2025-11-24T15:55:18Z", + updatedAt: "2025-11-24T15:55:18Z", + ttl: 1_735_687_518, + specificationId: "spec1", + groupId: "group1", + stockRemaining: 500, }; - jest.useFakeTimers().setSystemTime(new Date('2025-11-24T15:55:18Z')); + jest.useFakeTimers().setSystemTime(new Date("2025-11-24T15:55:18Z")); const event = mapMIToCloudEvent(mi); - console.log("Mapped Event: ", event); // Check it conforms to the MI event schema - parse will throw an error if not $MISubmittedEvent.parse(event); - expect(event.type).toBe('uk.nhs.notify.supplier-api.mi.SUBMITTED.v1'); - expect(event.dataschema).toBe('https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json'); - expect(event.subject).toBe('mi/id1'); - expect(event.time).toBe('2025-11-24T15:55:18.000Z'); - expect(event.recordedtime).toBe('2025-11-24T15:55:18.000Z'); + expect(event.type).toBe("uk.nhs.notify.supplier-api.mi.SUBMITTED.v1"); + expect(event.dataschema).toBe( + "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json", + ); + expect(event.subject).toBe("mi/id1"); + expect(event.time).toBe("2025-11-24T15:55:18.000Z"); + expect(event.recordedtime).toBe("2025-11-24T15:55:18.000Z"); expect(event.data).toEqual({ - id: 'id1', - lineItem: 'lineItem1', - timestamp: '2025-11-24T15:55:18Z', + id: "id1", + lineItem: "lineItem1", + timestamp: "2025-11-24T15:55:18Z", quantity: 100, - specificationId: 'spec1', - groupId: 'group1', + specificationId: "spec1", + groupId: "group1", stockRemaining: 500, - supplierId: 'supplier1', - createdAt: '2025-11-24T15:55:18Z', - updatedAt: '2025-11-24T15:55:18Z' + supplierId: "supplier1", + createdAt: "2025-11-24T15:55:18Z", + updatedAt: "2025-11-24T15:55:18Z", }); jest.useRealTimers(); - }) + }); }); diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts index 3659f9a9..f9999653 100644 --- a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -1,24 +1,24 @@ -import { MI } from '@internal/datastore'; -import { MISubmittedEvent } from '@nhsdigital/nhs-notify-event-schemas-supplier-api/src'; -import { randomUUID, randomBytes } from 'crypto'; +import { MI } from "@internal/datastore"; +import { MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; +import { randomBytes, randomUUID } from "node:crypto"; -export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { +export default function mapMIToCloudEvent(mi: MI): MISubmittedEvent { const now = new Date().toISOString(); const eventId = randomUUID(); - const dataschemaversion = '1.0.0'; + const dataschemaversion = "1.0.0"; return { - specversion: '1.0', + specversion: "1.0", id: eventId, type: `uk.nhs.notify.supplier-api.mi.SUBMITTED.v1`, - plane: 'data-plane', + plane: "data-plane", dataschema: `https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.${dataschemaversion}.schema.json`, dataschemaversion, - source: '/data-plane/supplier-api/mi', - subject: 'mi/' + mi.id, + source: "/data-plane/supplier-api/mi", + subject: `mi/${mi.id}`, data: { - id: mi.id as MISubmittedEvent['data']['id'], + id: mi.id, lineItem: mi.lineItem, timestamp: mi.timestamp, quantity: mi.quantity, @@ -27,13 +27,13 @@ export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { updatedAt: mi.updatedAt, specificationId: mi.specificationId, groupId: mi.groupId, - stockRemaining: mi.stockRemaining + stockRemaining: mi.stockRemaining, }, time: now, - datacontenttype: 'application/json', - traceparent: `00-${randomBytes(16).toString('hex')}-${randomBytes(8).toString('hex')}-01`, + datacontenttype: "application/json", + traceparent: `00-${randomBytes(16).toString("hex")}-${randomBytes(8).toString("hex")}-01`, recordedtime: now, severitynumber: 2, - severitytext: 'INFO', + severitytext: "INFO", }; } diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index 1565e895..7029465d 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -1,43 +1,50 @@ - -import { Handler, KinesisStreamEvent } from 'aws-lambda'; -import { mapMIToCloudEvent } from './mappers/mi-mapper'; -import { PublishBatchCommand, PublishBatchRequestEntry } from '@aws-sdk/client-sns'; -import { MISubmittedEvent } from '@nhsdigital/nhs-notify-event-schemas-supplier-api/src'; -import { Deps } from './deps'; +import { Handler, KinesisStreamEvent } from "aws-lambda"; +import { + PublishBatchCommand, + PublishBatchRequestEntry, +} from "@aws-sdk/client-sns"; +import { MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; +import mapMIToCloudEvent from "./mappers/mi-mapper"; +import { Deps } from "./deps"; // SNS PublishBatchCommand supports up to 10 messages per batch const BATCH_SIZE = 10; -export function createHandler(deps: Deps): Handler { - return async(streamEvent: KinesisStreamEvent) => { - deps.logger.info({description: 'Received event', streamEvent}); - - const cloudEvents: MISubmittedEvent[] = streamEvent.Records - .map((record) => { - // Kinesis data is base64 encoded - const payload = Buffer.from(record.kinesis.data, 'base64').toString('utf-8'); - return JSON.parse(payload); - }) - .map(mapMIToCloudEvent); +function* generateBatches(events: MISubmittedEvent[]) { + for (let i = 0; i < events.length; i += BATCH_SIZE) { + yield events.slice(i, i + BATCH_SIZE); + } +} +function buildMessage(event: MISubmittedEvent): PublishBatchRequestEntry { + return { + Id: event.id, + Message: JSON.stringify(event), + }; +} - for (let batch of generateBatches(cloudEvents)) { - await deps.snsClient.send(new PublishBatchCommand({ - TopicArn: deps.env.EVENTPUB_SNS_TOPIC_ARN, - PublishBatchRequestEntries: batch.map(buildMessage), - })); - } - } +export default function createHandler(deps: Deps): Handler { + return async (streamEvent: KinesisStreamEvent) => { + deps.logger.info({ description: "Received event", streamEvent }); - function* generateBatches(events: MISubmittedEvent[]) { - for (let i = 0; i < events.length; i += BATCH_SIZE) { - yield events.slice(i, i + BATCH_SIZE); - } - } + const cloudEvents: MISubmittedEvent[] = streamEvent.Records.map( + (record) => { + // Kinesis data is base64 encoded + const payload = Buffer.from(record.kinesis.data, "base64").toString( + "utf8", + ); + return JSON.parse(payload); + }, + ).map((element) => mapMIToCloudEvent(element)); - function buildMessage(event: MISubmittedEvent): PublishBatchRequestEntry { - return { - Id: event.id, - Message: JSON.stringify(event), + for (const batch of generateBatches(cloudEvents)) { + await deps.snsClient.send( + new PublishBatchCommand({ + TopicArn: deps.env.EVENTPUB_SNS_TOPIC_ARN, + PublishBatchRequestEntries: batch.map((element) => + buildMessage(element), + ), + }), + ); } - } + }; } From c8829ed3d50b7302128b2d2d4d4397e39038dadc Mon Sep 17 00:00:00 2001 From: David Wass Date: Tue, 2 Dec 2025 10:41:11 +0000 Subject: [PATCH 11/21] update lackage lock --- package-lock.json | 1550 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 1194 insertions(+), 356 deletions(-) diff --git a/package-lock.json b/package-lock.json index 79128371..882d8e4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3018,27 +3018,1137 @@ "version": "0.1.0", "dependencies": { "@aws-sdk/client-kinesis": "^3.0.0", - "aws-lambda": "^1.0.7" + "@aws-sdk/util-dynamodb": "^3.940.0", + "@internal/datastore": "^0.1.0", + "aws-lambda": "^1.0.7", + "jest-mock-extended": "^4.0.0", + "pino": "^10.1.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "typescript": "^5.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/client-dynamodb": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.940.0.tgz", + "integrity": "sha512-u2sXsNJazJbuHeWICvsj6RvNyJh3isedEfPvB21jK/kxcriK+dE/izlKC2cyxUjERCmku0zTFNzY9FhrLbYHjQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-node": "3.940.0", + "@aws-sdk/middleware-endpoint-discovery": "3.936.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/client-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz", + "integrity": "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/core": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz", + "integrity": "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz", + "integrity": "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz", + "integrity": "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz", + "integrity": "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-login": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-login": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz", + "integrity": "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz", + "integrity": "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-ini": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz", + "integrity": "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz", + "integrity": "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/client-sso": "3.940.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/token-providers": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz", + "integrity": "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.936.0.tgz", + "integrity": "sha512-wNJZ8PDw0eQK2x4z1q8JqiDvw9l9xd36EoklVT2CIBt8FnqGdrMGjAx93RRbH3G6Fmvwoe+D3VJXbWHBlhD0Bw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/endpoint-cache": "3.893.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", + "integrity": "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-logger": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.936.0.tgz", + "integrity": "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.936.0.tgz", + "integrity": "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws/lambda-invoke-store": "^0.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz", + "integrity": "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@smithy/core": "^3.18.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/nested-clients": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz", + "integrity": "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.936.0.tgz", + "integrity": "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/token-providers": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz", + "integrity": "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/types": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.936.0.tgz", + "integrity": "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-dynamodb": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.940.0.tgz", + "integrity": "sha512-T8UTYtCYSPxktnk68fKBdWztnqdTQItJwi/8N9lsvp20alJ15wCQsvQR+GKB5p4TCKxOPyNEirkcrNlf5TKppA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.940.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-endpoints": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz", + "integrity": "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-endpoints": "^3.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.936.0.tgz", + "integrity": "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz", + "integrity": "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "lambdas/mi-stream-forwarder/node_modules/@aws/lambda-invoke-store": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz", + "integrity": "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww==", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-stream-forwarder/node_modules/pino": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz", + "integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "lambdas/mi-stream-forwarder/node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "lambdas/mi-stream-forwarder/node_modules/zod": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "lambdas/mi-updates-transformer": { + "name": "nhs-notify-supplier-api-mi-updates-transformer", + "version": "0.0.1", + "dependencies": { + "@aws-sdk/client-sns": "^3.940.0", + "@internal/datastore": "^0.1.0", + "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", + "aws-lambda": "^1.0.7", + "esbuild": "^0.24.0", + "pino": "^10.1.0", + "zod": "^4.1.13" + }, + "devDependencies": { + "@tsconfig/node22": "^22.0.2", + "@types/aws-lambda": "^8.10.148", + "@types/jest": "^30.0.0", + "jest": "^30.2.0", + "jest-mock-extended": "^4.0.0", + "typescript": "^5.8.3" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-sns": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.940.0.tgz", + "integrity": "sha512-TtLmzU8ylChGESzPA21vzsJiN7KTW2uLoAhYb5JAkxK+AsZSqwfqK8ycLsbguOp7xLuM4cqMILoUvF5me5LXdw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-node": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz", + "integrity": "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/core": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz", + "integrity": "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz", + "integrity": "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz", + "integrity": "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz", + "integrity": "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-login": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-login": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz", + "integrity": "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz", + "integrity": "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.940.0", + "@aws-sdk/credential-provider-http": "3.940.0", + "@aws-sdk/credential-provider-ini": "3.940.0", + "@aws-sdk/credential-provider-process": "3.940.0", + "@aws-sdk/credential-provider-sso": "3.940.0", + "@aws-sdk/credential-provider-web-identity": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz", + "integrity": "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz", + "integrity": "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.940.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/token-providers": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz", + "integrity": "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", + "integrity": "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-logger": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.936.0.tgz", + "integrity": "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.936.0.tgz", + "integrity": "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws/lambda-invoke-store": "^0.2.0", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz", + "integrity": "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@smithy/core": "^3.18.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/nested-clients": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz", + "integrity": "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.940.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.940.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" }, - "devDependencies": { - "@types/aws-lambda": "^8.10.119", - "typescript": "^5.0.0" + "engines": { + "node": ">=18.0.0" } }, - "lambdas/mi-updates-transformer": { - "name": "nhs-notify-supplier-api-mi-updates-transformer", - "version": "0.0.1", + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.936.0.tgz", + "integrity": "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==", + "license": "Apache-2.0", "dependencies": { - "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", - "esbuild": "^0.24.0" + "@aws-sdk/types": "3.936.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" }, - "devDependencies": { - "@tsconfig/node22": "^22.0.2", - "@types/aws-lambda": "^8.10.148", - "@types/jest": "^30.0.0", - "jest": "^30.2.0", - "jest-mock-extended": "^4.0.0", - "typescript": "^5.8.3" + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/token-providers": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz", + "integrity": "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.940.0", + "@aws-sdk/nested-clients": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/types": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.936.0.tgz", + "integrity": "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/util-endpoints": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz", + "integrity": "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-endpoints": "^3.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.936.0.tgz", + "integrity": "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@smithy/types": "^4.9.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.940.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz", + "integrity": "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.940.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws/lambda-invoke-store": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz", + "integrity": "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" } }, "lambdas/mi-updates-transformer/node_modules/@esbuild/aix-ppc64": { @@ -3481,6 +4591,46 @@ "@esbuild/win32-x64": "0.24.2" } }, + "lambdas/mi-updates-transformer/node_modules/pino": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz", + "integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "lambdas/mi-updates-transformer/node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "lambdas/mi-updates-transformer/node_modules/zod": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", + "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "lambdas/upsert-letter": { "name": "nhs-notify-supplier-api-upsert-letter", "version": "0.0.1", @@ -6833,7 +7983,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -6848,7 +7997,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -6858,7 +8006,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -6889,7 +8036,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6899,7 +8045,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -6916,7 +8061,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -6933,7 +8077,6 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -6943,7 +8086,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -6953,7 +8095,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -6967,7 +8108,6 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -6985,7 +8125,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -6995,7 +8134,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -7005,7 +8143,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -7015,7 +8152,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -7025,7 +8161,6 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -7039,7 +8174,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" @@ -7055,7 +8189,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7068,7 +8201,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7081,7 +8213,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -7094,7 +8225,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -7110,7 +8240,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -7126,7 +8255,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -7139,7 +8267,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7152,7 +8279,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -7168,7 +8294,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -7181,7 +8306,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7194,7 +8318,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -7207,7 +8330,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7220,7 +8342,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7233,7 +8354,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -7246,7 +8366,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -7262,7 +8381,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -7278,7 +8396,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -7304,7 +8421,6 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -7319,7 +8435,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -7338,7 +8453,6 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -7359,7 +8473,6 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, "license": "MIT" }, "node_modules/@borewit/text-codec": { @@ -7377,7 +8490,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -7390,7 +8503,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -7516,7 +8629,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -7528,7 +8640,6 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -7539,7 +8650,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -8492,7 +9602,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -8510,7 +9619,6 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8523,7 +9631,6 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8536,7 +9643,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -8554,7 +9660,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -8570,7 +9675,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -8588,7 +9692,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -8605,7 +9708,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -8615,7 +9717,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -8629,7 +9730,6 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -8643,7 +9743,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -8656,7 +9755,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -8672,7 +9770,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -8685,7 +9782,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8695,7 +9791,6 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8705,7 +9800,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -8723,7 +9817,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -8736,7 +9829,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -8757,7 +9849,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -8775,7 +9866,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -8790,7 +9880,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -8838,7 +9927,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -8851,7 +9939,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -8872,7 +9959,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -8890,7 +9976,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -8905,7 +9990,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", - "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -8915,7 +9999,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", - "dev": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "30.2.0", @@ -8977,7 +10060,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", - "dev": true, "license": "MIT", "dependencies": { "expect": "30.2.0", @@ -9004,7 +10086,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9022,7 +10103,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9035,7 +10115,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -9056,7 +10135,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9074,7 +10152,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -9089,7 +10166,6 @@ "version": "30.1.0", "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", - "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -9099,7 +10175,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -9115,7 +10190,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -9129,7 +10203,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", - "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", @@ -9172,7 +10245,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9185,7 +10257,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -9206,7 +10277,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9224,7 +10294,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -9239,7 +10308,6 @@ "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", - "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -9252,14 +10320,12 @@ "version": "0.34.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", - "dev": true, "license": "MIT" }, "node_modules/@jest/snapshot-utils": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9275,7 +10341,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -9290,7 +10355,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -9455,7 +10519,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -9482,7 +10545,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9500,7 +10562,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -9519,7 +10580,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -9530,7 +10590,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -9541,7 +10600,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -9551,14 +10609,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -9635,7 +10691,6 @@ "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -10204,7 +11259,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { @@ -10215,7 +11269,6 @@ "version": "0.2.9", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", - "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -10754,7 +11807,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -10764,7 +11816,6 @@ "version": "13.0.5", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -12149,28 +13200,28 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/@tsconfig/node22": { @@ -12184,7 +13235,6 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -12201,7 +13251,6 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -12215,7 +13264,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -12225,7 +13273,6 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -12236,7 +13283,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -12296,14 +13342,12 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -12313,7 +13357,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -12401,7 +13444,6 @@ "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -12455,7 +13497,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, "license": "MIT" }, "node_modules/@types/stylis": { @@ -12491,7 +13532,6 @@ "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", - "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -12501,7 +13541,6 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -12752,7 +13791,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12766,7 +13804,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12780,7 +13817,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12794,7 +13830,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12808,7 +13843,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12822,7 +13856,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12836,7 +13869,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12850,7 +13882,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12864,7 +13895,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12878,7 +13908,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12892,7 +13921,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12906,7 +13934,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12920,7 +13947,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12934,7 +13960,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12948,7 +13973,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12962,7 +13986,6 @@ "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -12979,7 +14002,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -12993,7 +14015,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13007,7 +14028,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13037,7 +14057,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -13060,7 +14080,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -13201,7 +14221,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -13241,7 +14260,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -13255,7 +14273,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -14063,7 +15080,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", - "dev": true, "license": "BSD-3-Clause", "workspaces": [ "test/babel-8" @@ -14099,7 +15115,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -14266,7 +15281,6 @@ "version": "2.8.28", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", - "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -14478,7 +15492,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -14488,7 +15501,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -14501,7 +15513,6 @@ "version": "4.28.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -14548,7 +15559,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" @@ -14593,7 +15603,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, "license": "MIT" }, "node_modules/buildcheck": { @@ -14703,7 +15712,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -14713,7 +15721,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -14733,7 +15740,6 @@ "version": "1.0.30001755", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -14792,7 +15798,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -14850,7 +15855,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", - "dev": true, "funding": [ { "type": "github", @@ -14866,7 +15870,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", - "dev": true, "license": "MIT" }, "node_modules/classnames": { @@ -15018,7 +16021,6 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, "license": "MIT", "engines": { "iojs": ">= 1.0.0", @@ -15029,7 +16031,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", - "dev": true, "license": "MIT" }, "node_modules/color-convert": { @@ -15350,7 +16351,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -16179,7 +17179,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -16347,7 +17347,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -16378,7 +17377,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", - "dev": true, "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -16409,7 +17407,6 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -16502,7 +17499,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -16512,7 +17508,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -16761,14 +17757,12 @@ "version": "1.5.254", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz", "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==", - "dev": true, "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -16810,7 +17804,6 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", - "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -18197,7 +19190,6 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -18207,7 +19199,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/expect-utils": "30.2.0", @@ -18225,7 +19216,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0" @@ -18238,7 +19228,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -18251,7 +19240,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -18267,7 +19255,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -18283,7 +19270,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -18304,7 +19290,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -18322,7 +19307,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -18374,7 +19358,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -18446,7 +19429,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" @@ -18539,7 +19521,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -18646,7 +19627,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -18702,14 +19682,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -18780,7 +19758,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -18795,6 +19772,18 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -18823,7 +19812,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -18935,7 +19923,6 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -19164,7 +20151,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, "license": "MIT" }, "node_modules/htmlparser2": { @@ -19311,7 +20297,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", - "dev": true, "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", @@ -19331,7 +20316,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -19368,7 +20352,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -19477,7 +20460,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -19708,7 +20690,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -19786,7 +20767,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -20035,7 +21015,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -20045,7 +21024,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -20062,7 +21040,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", @@ -20077,7 +21054,6 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", @@ -20092,7 +21068,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", @@ -20134,7 +21109,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -20150,7 +21124,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", - "dev": true, "license": "MIT", "dependencies": { "@jest/core": "30.2.0", @@ -20177,7 +21150,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", - "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1", @@ -20192,7 +21164,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -20759,7 +21730,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/core": "30.2.0", @@ -20792,7 +21762,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -20807,7 +21776,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -20825,7 +21793,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -20843,7 +21810,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -20862,7 +21828,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -20914,7 +21879,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", - "dev": true, "license": "MIT", "dependencies": { "@jest/test-result": "30.2.0", @@ -20930,7 +21894,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -20943,7 +21906,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/transform": "30.2.0", @@ -20965,7 +21927,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", - "dev": true, "license": "MIT", "dependencies": { "@types/babel__core": "^7.20.5" @@ -20978,7 +21939,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", - "dev": true, "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "30.2.0", @@ -20995,7 +21955,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -21027,7 +21986,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -21043,7 +22001,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -21060,7 +22017,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -21079,7 +22035,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -21095,7 +22050,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -21116,7 +22070,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21134,7 +22087,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -21149,7 +22101,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", - "dev": true, "funding": [ { "type": "individual", @@ -21182,7 +22133,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", - "dev": true, "license": "MIT", "dependencies": { "detect-newline": "^3.1.0" @@ -21386,7 +22336,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21411,7 +22360,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21452,7 +22400,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -21466,7 +22413,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21479,7 +22425,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -21562,7 +22507,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21577,7 +22521,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-4.0.0.tgz", "integrity": "sha512-7BZpfuvLam+/HC+NxifIi9b+5VXj/utUDMPUqrDJehGWVuXPtLS9Jqlob2mJLrI/pg2k1S8DMfKDvEB88QNjaQ==", - "dev": true, "license": "MIT", "dependencies": { "ts-essentials": "^10.0.2" @@ -21592,7 +22535,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21610,7 +22552,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -21628,7 +22569,6 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", - "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -21638,7 +22578,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", - "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", @@ -21658,7 +22597,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", - "dev": true, "license": "MIT", "dependencies": { "jest-regex-util": "30.0.1", @@ -21672,7 +22610,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21690,7 +22627,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", - "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -21724,7 +22660,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21737,7 +22672,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -21756,7 +22690,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -21777,7 +22710,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21795,7 +22727,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -21810,7 +22741,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -21844,7 +22774,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21857,7 +22786,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -21878,7 +22806,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21896,7 +22823,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -21911,7 +22837,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -21944,7 +22869,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0" @@ -21957,7 +22881,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21970,7 +22893,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", - "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -21986,7 +22908,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -22002,7 +22923,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -22023,7 +22943,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22041,7 +22960,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -22134,7 +23052,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", - "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -22152,7 +23069,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22165,7 +23081,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22178,7 +23093,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -22193,7 +23107,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", - "dev": true, "license": "MIT", "dependencies": { "@jest/test-result": "30.2.0", @@ -22213,7 +23126,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22231,7 +23143,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", - "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -22248,7 +23159,6 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", - "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22266,7 +23176,6 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -22301,7 +23210,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -22370,7 +23278,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -22390,7 +23297,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, "license": "MIT" }, "node_modules/json-pointer": { @@ -22435,7 +23341,6 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -22672,7 +23577,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -22696,7 +23600,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, "license": "MIT" }, "node_modules/load-esm": { @@ -22810,7 +23713,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -22837,7 +23739,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, "license": "MIT", "dependencies": { "semver": "^7.5.3" @@ -22853,14 +23754,13 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" @@ -22937,7 +23837,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -22951,7 +23850,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -22995,7 +23893,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -23020,7 +23917,6 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -23122,7 +24018,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mute-stream": { @@ -23163,7 +24058,6 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", - "dev": true, "license": "MIT", "bin": { "napi-postinstall": "lib/cli.js" @@ -23179,7 +24073,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, "license": "MIT" }, "node_modules/natural-compare-lite": { @@ -23343,7 +24236,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true, "license": "MIT" }, "node_modules/node-readfiles": { @@ -23360,7 +24252,6 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, "license": "MIT" }, "node_modules/node-sarif-builder": { @@ -23396,7 +24287,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -23647,7 +24537,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -23864,7 +24753,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -23896,7 +24784,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -23940,7 +24827,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -23960,7 +24846,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -23999,7 +24884,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -24009,7 +24893,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -24041,7 +24924,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -24058,7 +24940,6 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, "license": "ISC" }, "node_modules/path-to-regexp": { @@ -24083,14 +24964,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -24149,7 +25028,6 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -24159,7 +25037,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" @@ -24172,7 +25049,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -24186,7 +25062,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -24199,7 +25074,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -24215,7 +25089,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -24751,7 +25624,6 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==", - "dev": true, "license": "MIT" }, "node_modules/react-tabs": { @@ -25067,7 +25939,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" @@ -25080,7 +25951,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -25368,7 +26238,6 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -25739,7 +26608,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -25822,7 +26690,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -25892,7 +26759,6 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -25912,7 +26778,6 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -26010,7 +26875,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -26023,7 +26887,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -26086,7 +26949,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, "license": "MIT", "dependencies": { "char-regex": "^1.0.2", @@ -26115,7 +26977,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -26130,7 +26991,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/string-width/node_modules/emoji-regex": { @@ -26269,7 +27129,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -26282,7 +27141,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -26314,7 +27172,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -26459,7 +27316,6 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", - "dev": true, "license": "MIT", "dependencies": { "@pkgr/core": "^0.2.9" @@ -26502,7 +27358,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -26517,7 +27372,6 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -26529,7 +27383,6 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -26550,7 +27403,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -26677,14 +27529,12 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -26772,7 +27622,6 @@ "version": "10.1.1", "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.1.1.tgz", "integrity": "sha512-4aTB7KLHKmUvkjNj8V+EdnmuVTiECzn3K+zIbRthumvHu+j44x3w63xpfs0JL3NGIzGXqoQ7AV591xHO+XrOTw==", - "dev": true, "license": "MIT", "peerDependencies": { "typescript": ">=4.5.0" @@ -26853,7 +27702,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -26897,7 +27746,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/tsconfig-paths": { @@ -26986,7 +27835,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -26996,7 +27844,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -27087,7 +27934,6 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -27210,7 +28056,6 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", - "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -27245,7 +28090,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -27386,14 +28230,13 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", - "dev": true, "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -27482,7 +28325,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" @@ -27770,7 +28612,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -27788,14 +28629,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", - "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -27889,7 +28728,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -27951,7 +28789,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=6" @@ -27961,7 +28799,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -28055,6 +28892,7 @@ "@aws-sdk/client-s3": "^3.858.0", "@internal/datastore": "*", "esbuild": "^0.25.11", + "get-east-asian-width": "^1.4.0", "pino": "^9.7.0", "yargs": "^18.0.0" }, From f45330f9d24e052a648b0c1dc308b9719bca0577 Mon Sep 17 00:00:00 2001 From: David Wass Date: Tue, 2 Dec 2025 10:59:37 +0000 Subject: [PATCH 12/21] fix imports --- lambdas/mi-stream-forwarder/src/index.ts | 2 +- lambdas/mi-updates-transformer/src/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lambdas/mi-stream-forwarder/src/index.ts b/lambdas/mi-stream-forwarder/src/index.ts index f7e9ed4a..70e1399a 100644 --- a/lambdas/mi-stream-forwarder/src/index.ts +++ b/lambdas/mi-stream-forwarder/src/index.ts @@ -1,4 +1,4 @@ -import { createHandler } from "./mi-stream-forwarder"; +import createHandler from "./mi-stream-forwarder"; import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); diff --git a/lambdas/mi-updates-transformer/src/index.ts b/lambdas/mi-updates-transformer/src/index.ts index 91e8433c..9c40c783 100644 --- a/lambdas/mi-updates-transformer/src/index.ts +++ b/lambdas/mi-updates-transformer/src/index.ts @@ -1,4 +1,4 @@ -import { createHandler } from "./mi-updates-transformer"; +import createHandler from "./mi-updates-transformer"; import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); From 66a17f6d0105c517c298b6952513cc5bfb8cb4c2 Mon Sep 17 00:00:00 2001 From: David Wass Date: Tue, 2 Dec 2025 12:01:13 +0000 Subject: [PATCH 13/21] back out export changes --- .../components/api/event_source_mapping_mi_updates.tf | 2 +- .../src/__tests__/mi-stream-forwarder.test.ts | 2 +- lambdas/mi-stream-forwarder/src/index.ts | 5 ++--- lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts | 2 +- .../src/__tests__/mi-updates-transformer.test.ts | 4 ++-- lambdas/mi-updates-transformer/src/index.ts | 6 ++---- .../src/mappers/__tests__/mi-mapper.test.ts | 2 +- lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts | 2 +- .../mi-updates-transformer/src/mi-updates-transformer.ts | 4 ++-- 9 files changed, 13 insertions(+), 16 deletions(-) diff --git a/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf b/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf index 8acdae3d..b733c852 100644 --- a/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf +++ b/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf @@ -1,7 +1,7 @@ resource "aws_lambda_event_source_mapping" "mi_stream_forwarder_dynamodb" { event_source_arn = aws_dynamodb_table.mi.stream_arn function_name = module.mi_stream_forwarder.function_arn - starting_position = "LATEST" + starting_position = "TRIM_HORIZON" batch_size = 10 maximum_batching_window_in_seconds = 1 diff --git a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts index ce4dd439..5bb256ab 100644 --- a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts +++ b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts @@ -4,7 +4,7 @@ import { mockDeep } from "jest-mock-extended"; import { Context, DynamoDBStreamEvent } from "aws-lambda"; import { Deps } from "../deps"; import { EnvVars } from "../env"; -import createHandler from "../mi-stream-forwarder"; +import { createHandler } from "../mi-stream-forwarder"; describe("mi-stream-forwarder Lambda", () => { const mockedDeps: jest.Mocked = { diff --git a/lambdas/mi-stream-forwarder/src/index.ts b/lambdas/mi-stream-forwarder/src/index.ts index 70e1399a..999b9a99 100644 --- a/lambdas/mi-stream-forwarder/src/index.ts +++ b/lambdas/mi-stream-forwarder/src/index.ts @@ -1,7 +1,6 @@ -import createHandler from "./mi-stream-forwarder"; +import { createHandler } from "./mi-stream-forwarder"; import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); -const handler = createHandler(container); -export default handler; +export const handler = createHandler(container); diff --git a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts index c4a27d9c..bd50bcec 100644 --- a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts +++ b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts @@ -4,7 +4,7 @@ import { PutRecordCommand } from "@aws-sdk/client-kinesis"; import { unmarshall } from "@aws-sdk/util-dynamodb"; import { Deps } from "./deps"; -export default function createHandler( +export function createHandler( deps: Deps, ): Handler { return async (event: DynamoDBStreamEvent): Promise => { diff --git a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts index 945d4441..49dde4cc 100644 --- a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts +++ b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts @@ -7,10 +7,10 @@ import { } from "aws-lambda"; import { mockDeep } from "jest-mock-extended"; import { MI } from "@internal/datastore"; -import createHandler from "../mi-updates-transformer"; +import { createHandler } from "../mi-updates-transformer"; import { Deps } from "../deps"; import { EnvVars } from "../env"; -import mapMIToCloudEvent from "../mappers/mi-mapper"; +import { mapMIToCloudEvent } from "../mappers/mi-mapper"; // Make crypto return consistent values, since we're calling it in both prod and test code and comparing the values const realCrypto = jest.requireActual("crypto"); diff --git a/lambdas/mi-updates-transformer/src/index.ts b/lambdas/mi-updates-transformer/src/index.ts index 9c40c783..f7c8a4df 100644 --- a/lambdas/mi-updates-transformer/src/index.ts +++ b/lambdas/mi-updates-transformer/src/index.ts @@ -1,8 +1,6 @@ -import createHandler from "./mi-updates-transformer"; +import { createHandler } from "./mi-updates-transformer"; import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); -const handler = createHandler(container); - -export default handler; +export const handler = createHandler(container); diff --git a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts index b46ceddc..3adf4dfe 100644 --- a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts +++ b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts @@ -1,6 +1,6 @@ import { $MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; import { MI } from "@internal/datastore"; -import mapMIToCloudEvent from "../mi-mapper"; +import { mapMIToCloudEvent } from "../mi-mapper"; describe("mi-mapper", () => { it("maps an MI to an MI event", async () => { diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts index f9999653..d0eb1bc1 100644 --- a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -2,7 +2,7 @@ import { MI } from "@internal/datastore"; import { MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; import { randomBytes, randomUUID } from "node:crypto"; -export default function mapMIToCloudEvent(mi: MI): MISubmittedEvent { +export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { const now = new Date().toISOString(); const eventId = randomUUID(); const dataschemaversion = "1.0.0"; diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index 7029465d..c9a4dbca 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -4,7 +4,7 @@ import { PublishBatchRequestEntry, } from "@aws-sdk/client-sns"; import { MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; -import mapMIToCloudEvent from "./mappers/mi-mapper"; +import { mapMIToCloudEvent } from "./mappers/mi-mapper"; import { Deps } from "./deps"; // SNS PublishBatchCommand supports up to 10 messages per batch const BATCH_SIZE = 10; @@ -22,7 +22,7 @@ function buildMessage(event: MISubmittedEvent): PublishBatchRequestEntry { }; } -export default function createHandler(deps: Deps): Handler { +export function createHandler(deps: Deps): Handler { return async (streamEvent: KinesisStreamEvent) => { deps.logger.info({ description: "Received event", streamEvent }); From d20f66eb4f074cb15d7e2e0b44e731b15c90adca Mon Sep 17 00:00:00 2001 From: David Wass Date: Wed, 3 Dec 2025 10:11:01 +0000 Subject: [PATCH 14/21] Remove stream forwarder and pass direct from db to kinesis --- .../terraform/components/api/README.md | 1 - .../api/event_source_mapping_mi_updates.tf | 12 --- .../api/kinesis_mi_change_stream.tf | 6 ++ .../api/module_lambda_mi_stream_forwarder.tf | 74 ------------------- lambdas/mi-stream-forwarder/.eslintignore | 1 - lambdas/mi-stream-forwarder/.gitignore | 4 - lambdas/mi-stream-forwarder/jest.config.ts | 60 --------------- lambdas/mi-stream-forwarder/package.json | 26 ------- .../src/__tests__/mi-stream-forwarder.test.ts | 66 ----------------- lambdas/mi-stream-forwarder/src/deps.ts | 17 ----- lambdas/mi-stream-forwarder/src/env.ts | 9 --- lambdas/mi-stream-forwarder/src/index.ts | 6 -- .../src/mi-stream-forwarder.ts | 28 ------- lambdas/mi-stream-forwarder/tsconfig.json | 7 -- .../src/mappers/__tests__/mi-mapper.test.ts | 3 +- .../src/mappers/mi-mapper.ts | 5 +- 16 files changed, 10 insertions(+), 315 deletions(-) delete mode 100644 infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf delete mode 100644 lambdas/mi-stream-forwarder/.eslintignore delete mode 100644 lambdas/mi-stream-forwarder/.gitignore delete mode 100644 lambdas/mi-stream-forwarder/jest.config.ts delete mode 100644 lambdas/mi-stream-forwarder/package.json delete mode 100644 lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts delete mode 100644 lambdas/mi-stream-forwarder/src/deps.ts delete mode 100644 lambdas/mi-stream-forwarder/src/env.ts delete mode 100644 lambdas/mi-stream-forwarder/src/index.ts delete mode 100644 lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts delete mode 100644 lambdas/mi-stream-forwarder/tsconfig.json diff --git a/infrastructure/terraform/components/api/README.md b/infrastructure/terraform/components/api/README.md index 9d188ae5..e50afd21 100644 --- a/infrastructure/terraform/components/api/README.md +++ b/infrastructure/terraform/components/api/README.md @@ -47,7 +47,6 @@ No requirements. | [letter\_status\_updates\_queue](#module\_letter\_status\_updates\_queue) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-sqs.zip | n/a | | [letter\_updates\_transformer](#module\_letter\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [logging\_bucket](#module\_logging\_bucket) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-s3bucket.zip | n/a | -| [mi\_stream\_forwarder](#module\_mi\_stream\_forwarder) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [mi\_updates\_transformer](#module\_mi\_updates\_transformer) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [patch\_letter](#module\_patch\_letter) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip | n/a | | [post\_letters](#module\_post\_letters) | https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.24/terraform-lambda.zip | n/a | diff --git a/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf b/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf index b733c852..73e7d394 100644 --- a/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf +++ b/infrastructure/terraform/components/api/event_source_mapping_mi_updates.tf @@ -1,15 +1,3 @@ -resource "aws_lambda_event_source_mapping" "mi_stream_forwarder_dynamodb" { - event_source_arn = aws_dynamodb_table.mi.stream_arn - function_name = module.mi_stream_forwarder.function_arn - starting_position = "TRIM_HORIZON" - batch_size = 10 - maximum_batching_window_in_seconds = 1 - - depends_on = [ - module.mi_stream_forwarder # ensures stream forwarder exists - ] -} - resource "aws_lambda_event_source_mapping" "mi_updates_transformer_kinesis" { event_source_arn = aws_kinesis_stream.mi_change_stream.arn function_name = module.mi_updates_transformer.function_arn diff --git a/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf b/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf index 8afff084..0bb644be 100644 --- a/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf +++ b/infrastructure/terraform/components/api/kinesis_mi_change_stream.tf @@ -3,3 +3,9 @@ resource "aws_kinesis_stream" "mi_change_stream" { shard_count = 1 retention_period = 24 } + +resource "aws_dynamodb_kinesis_streaming_destination" "mi_streaming_destination" { + stream_arn = aws_kinesis_stream.mi_change_stream.arn + table_name = aws_dynamodb_table.mi.name + approximate_creation_date_time_precision = "MILLISECOND" +} diff --git a/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf b/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf deleted file mode 100644 index e8c3dc88..00000000 --- a/infrastructure/terraform/components/api/module_lambda_mi_stream_forwarder.tf +++ /dev/null @@ -1,74 +0,0 @@ -module "mi_stream_forwarder" { - source = "https://github.com/NHSDigital/nhs-notify-shared-modules/releases/download/v2.0.26/terraform-lambda.zip" - - function_name = "mi-stream-forwarder" - description = "Kinesis stream forwarder for DDB mi status updates" - - 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.mi_stream_forwarder_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 = "mi-stream-forwarder/dist" - function_include_common = true - handler_function_name = "handler" - runtime = "nodejs22.x" - memory = 128 - timeout = 5 - log_level = var.log_level - - force_lambda_code_deploy = var.force_lambda_code_deploy - enable_lambda_insights = false - - send_to_firehose = true - log_destination_arn = local.destination_arn - log_subscription_role_arn = local.acct.log_subscription_role_arn - - lambda_env_vars = merge(local.common_lambda_env_vars, { - MI_CHANGE_STREAM_ARN = "${aws_kinesis_stream.mi_change_stream.arn}" - }) -} - -data "aws_iam_policy_document" "mi_stream_forwarder_lambda" { - - statement { - sid = "AllowDynamoDBStream" - effect = "Allow" - - actions = [ - "dynamodb:GetRecords", - "dynamodb:GetShardIterator", - "dynamodb:DescribeStream", - "dynamodb:ListStreams", - ] - - resources = [ - "${aws_dynamodb_table.mi.arn}/stream/*" - ] - } - - statement { - sid = "AllowKinesisPut" - effect = "Allow" - - actions = [ - "kinesis:DescribeStream", - "kinesis:PutRecord", - ] - - resources = [ - aws_kinesis_stream.mi_change_stream.arn - ] - } -} diff --git a/lambdas/mi-stream-forwarder/.eslintignore b/lambdas/mi-stream-forwarder/.eslintignore deleted file mode 100644 index 1521c8b7..00000000 --- a/lambdas/mi-stream-forwarder/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -dist diff --git a/lambdas/mi-stream-forwarder/.gitignore b/lambdas/mi-stream-forwarder/.gitignore deleted file mode 100644 index 80323f7c..00000000 --- a/lambdas/mi-stream-forwarder/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -coverage -node_modules -dist -.reports diff --git a/lambdas/mi-stream-forwarder/jest.config.ts b/lambdas/mi-stream-forwarder/jest.config.ts deleted file mode 100644 index f88e7277..00000000 --- a/lambdas/mi-stream-forwarder/jest.config.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { Config } from "jest"; - -export const baseJestConfig: Config = { - preset: "ts-jest", - - // Automatically clear mock calls, instances, contexts and results before every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // The directory where Jest should output its coverage files - coverageDirectory: "./.reports/unit/coverage", - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "babel", - - coverageThreshold: { - global: { - branches: 100, - functions: 100, - lines: 100, - statements: -10, - }, - }, - - coveragePathIgnorePatterns: ["/__tests__/"], - transform: { "^.+\\.ts$": "ts-jest" }, - testPathIgnorePatterns: [".build"], - testMatch: ["**/?(*.)+(spec|test).[jt]s?(x)"], - - // Use this configuration option to add custom reporters to Jest - reporters: [ - "default", - [ - "jest-html-reporter", - { - pageTitle: "Test Report", - outputPath: "./.reports/unit/test-report.html", - includeFailureMsg: true, - }, - ], - ], - - // The test environment that will be used for testing - testEnvironment: "jsdom", -}; - -const utilsJestConfig = { - ...baseJestConfig, - - testEnvironment: "node", - - coveragePathIgnorePatterns: [ - ...(baseJestConfig.coveragePathIgnorePatterns ?? []), - "zod-validators.ts", - ], -}; - -export default utilsJestConfig; diff --git a/lambdas/mi-stream-forwarder/package.json b/lambdas/mi-stream-forwarder/package.json deleted file mode 100644 index bcab62db..00000000 --- a/lambdas/mi-stream-forwarder/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "dependencies": { - "@aws-sdk/client-kinesis": "^3.0.0", - "@aws-sdk/util-dynamodb": "^3.940.0", - "@internal/datastore": "^0.1.0", - "aws-lambda": "^1.0.7", - "jest-mock-extended": "^4.0.0", - "pino": "^10.1.0", - "zod": "^4.1.13" - }, - "devDependencies": { - "@types/aws-lambda": "^8.10.119", - "typescript": "^5.0.0" - }, - "main": "src/index.ts", - "name": "mi-stream-forwarder", - "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.1.0" -} diff --git a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts b/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts deleted file mode 100644 index 5bb256ab..00000000 --- a/lambdas/mi-stream-forwarder/src/__tests__/mi-stream-forwarder.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { KinesisClient } from "@aws-sdk/client-kinesis"; -import * as pino from "pino"; -import { mockDeep } from "jest-mock-extended"; -import { Context, DynamoDBStreamEvent } from "aws-lambda"; -import { Deps } from "../deps"; -import { EnvVars } from "../env"; -import { createHandler } from "../mi-stream-forwarder"; - -describe("mi-stream-forwarder Lambda", () => { - const mockedDeps: jest.Mocked = { - kinesisClient: { send: jest.fn() } as unknown as KinesisClient, - logger: { - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - } as unknown as pino.Logger, - env: { - MI_CHANGE_STREAM_ARN: "test-stream", - } as unknown as EnvVars, - } as Deps; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - it("forwards INSERT records to Kinesis", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "INSERT", - dynamodb: { - NewImage: { id: { S: "mi-123" }, foo: { S: "bar" } }, - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - expect(mockedDeps.kinesisClient.send).toHaveBeenCalledWith( - expect.objectContaining({ - input: expect.objectContaining({ - StreamARN: "test-stream", - PartitionKey: "mi-123", - }), - }), - ); - }); - - it("does not forward non-INSERT records", async () => { - const event: DynamoDBStreamEvent = { - Records: [ - { - eventName: "MODIFY", - dynamodb: { - NewImage: { id: { S: "mi-123" }, foo: { S: "baz" } }, - }, - }, - ], - }; - - const handler = createHandler(mockedDeps); - await handler(event, mockDeep(), jest.fn()); - expect(mockedDeps.kinesisClient.send).not.toHaveBeenCalled(); - }); -}); diff --git a/lambdas/mi-stream-forwarder/src/deps.ts b/lambdas/mi-stream-forwarder/src/deps.ts deleted file mode 100644 index b051e20b..00000000 --- a/lambdas/mi-stream-forwarder/src/deps.ts +++ /dev/null @@ -1,17 +0,0 @@ -import pino from "pino"; -import { KinesisClient } from "@aws-sdk/client-kinesis"; -import { EnvVars, envVars } from "./env"; - -export type Deps = { - kinesisClient: KinesisClient; - logger: pino.Logger; - env: EnvVars; -}; - -export function createDependenciesContainer(): Deps { - return { - kinesisClient: new KinesisClient({}), - logger: pino(), - env: envVars, - }; -} diff --git a/lambdas/mi-stream-forwarder/src/env.ts b/lambdas/mi-stream-forwarder/src/env.ts deleted file mode 100644 index df8d9d04..00000000 --- a/lambdas/mi-stream-forwarder/src/env.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { z } from "zod"; - -const EnvVarsSchema = z.object({ - MI_CHANGE_STREAM_ARN: z.string(), -}); - -export type EnvVars = z.infer; - -export const envVars = EnvVarsSchema.parse(process.env); diff --git a/lambdas/mi-stream-forwarder/src/index.ts b/lambdas/mi-stream-forwarder/src/index.ts deleted file mode 100644 index 999b9a99..00000000 --- a/lambdas/mi-stream-forwarder/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { createHandler } from "./mi-stream-forwarder"; -import { createDependenciesContainer } from "./deps"; - -const container = createDependenciesContainer(); - -export const handler = createHandler(container); diff --git a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts b/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts deleted file mode 100644 index bd50bcec..00000000 --- a/lambdas/mi-stream-forwarder/src/mi-stream-forwarder.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { MI } from "@internal/datastore"; -import { DynamoDBStreamEvent, Handler } from "aws-lambda"; -import { PutRecordCommand } from "@aws-sdk/client-kinesis"; -import { unmarshall } from "@aws-sdk/util-dynamodb"; -import { Deps } from "./deps"; - -export function createHandler( - deps: Deps, -): Handler { - return async (event: DynamoDBStreamEvent): Promise => { - deps.logger.info({ description: "Received event", event }); - const insertedRecords = event.Records.filter( - (record) => record.eventName === "INSERT", - ); - - for (const record of insertedRecords) { - const newImage = record.dynamodb?.NewImage!; - const miRecord = unmarshall(newImage as any) as MI; - await deps.kinesisClient.send( - new PutRecordCommand({ - StreamARN: deps.env.MI_CHANGE_STREAM_ARN, - PartitionKey: miRecord.id, - Data: Buffer.from(JSON.stringify(miRecord)), - }), - ); - } - }; -} diff --git a/lambdas/mi-stream-forwarder/tsconfig.json b/lambdas/mi-stream-forwarder/tsconfig.json deleted file mode 100644 index ea37d696..00000000 --- a/lambdas/mi-stream-forwarder/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "@tsconfig/node22/tsconfig.json", - "include": [ - "src/**/*", - "jest.config.ts" - ] -} diff --git a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts index 3adf4dfe..014d8e61 100644 --- a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts +++ b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts @@ -23,8 +23,9 @@ describe("mi-mapper", () => { // Check it conforms to the MI event schema - parse will throw an error if not $MISubmittedEvent.parse(event); expect(event.type).toBe("uk.nhs.notify.supplier-api.mi.SUBMITTED.v1"); + expect(event.plane).toBe("data"); expect(event.dataschema).toBe( - "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.0.0.schema.json", + "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.1.4.schema.json", ); expect(event.subject).toBe("mi/id1"); expect(event.time).toBe("2025-11-24T15:55:18.000Z"); diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts index d0eb1bc1..7df91cd4 100644 --- a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -5,15 +5,14 @@ import { randomBytes, randomUUID } from "node:crypto"; export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { const now = new Date().toISOString(); const eventId = randomUUID(); - const dataschemaversion = "1.0.0"; + const dataschemaversion = "1.1.4"; return { specversion: "1.0", id: eventId, type: `uk.nhs.notify.supplier-api.mi.SUBMITTED.v1`, - plane: "data-plane", + plane: "data", dataschema: `https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.${dataschemaversion}.schema.json`, - dataschemaversion, source: "/data-plane/supplier-api/mi", subject: `mi/${mi.id}`, From a6b7a52277a52dfccab77310dc1b183101018d2b Mon Sep 17 00:00:00 2001 From: David Wass Date: Wed, 3 Dec 2025 14:08:05 +0000 Subject: [PATCH 15/21] rebase updates --- .../src/mappers/__tests__/mi-mapper.test.ts | 3 +- .../src/mappers/mi-mapper.ts | 3 +- package-lock.json | 980 +++++++----------- 3 files changed, 355 insertions(+), 631 deletions(-) diff --git a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts index 014d8e61..30e15251 100644 --- a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts +++ b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts @@ -25,8 +25,9 @@ describe("mi-mapper", () => { expect(event.type).toBe("uk.nhs.notify.supplier-api.mi.SUBMITTED.v1"); expect(event.plane).toBe("data"); expect(event.dataschema).toBe( - "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.1.4.schema.json", + "https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.1.1.5.schema.json", ); + expect(event.dataschemaversion).toBe("1.1.5"); expect(event.subject).toBe("mi/id1"); expect(event.time).toBe("2025-11-24T15:55:18.000Z"); expect(event.recordedtime).toBe("2025-11-24T15:55:18.000Z"); diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts index 7df91cd4..3726e3e1 100644 --- a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -5,7 +5,7 @@ import { randomBytes, randomUUID } from "node:crypto"; export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { const now = new Date().toISOString(); const eventId = randomUUID(); - const dataschemaversion = "1.1.4"; + const dataschemaversion = "1.1.5"; return { specversion: "1.0", @@ -13,6 +13,7 @@ export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { type: `uk.nhs.notify.supplier-api.mi.SUBMITTED.v1`, plane: "data", dataschema: `https://notify.nhs.uk/cloudevents/schemas/supplier-api/mi.SUBMITTED.${dataschemaversion}.schema.json`, + dataschemaversion, source: "/data-plane/supplier-api/mi", subject: `mi/${mi.id}`, diff --git a/package-lock.json b/package-lock.json index 882d8e4a..a1ac0537 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3016,617 +3016,19 @@ }, "lambdas/mi-stream-forwarder": { "version": "0.1.0", + "extraneous": true, "dependencies": { - "@aws-sdk/client-kinesis": "^3.0.0", - "@aws-sdk/util-dynamodb": "^3.940.0", - "@internal/datastore": "^0.1.0", - "aws-lambda": "^1.0.7", - "jest-mock-extended": "^4.0.0", - "pino": "^10.1.0", - "zod": "^4.1.13" - }, - "devDependencies": { - "@types/aws-lambda": "^8.10.119", - "typescript": "^5.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/client-dynamodb": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.940.0.tgz", - "integrity": "sha512-u2sXsNJazJbuHeWICvsj6RvNyJh3isedEfPvB21jK/kxcriK+dE/izlKC2cyxUjERCmku0zTFNzY9FhrLbYHjQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.940.0", - "@aws-sdk/credential-provider-node": "3.940.0", - "@aws-sdk/middleware-endpoint-discovery": "3.936.0", - "@aws-sdk/middleware-host-header": "3.936.0", - "@aws-sdk/middleware-logger": "3.936.0", - "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.940.0", - "@aws-sdk/region-config-resolver": "3.936.0", - "@aws-sdk/types": "3.936.0", - "@aws-sdk/util-endpoints": "3.936.0", - "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.940.0", - "@smithy/config-resolver": "^4.4.3", - "@smithy/core": "^3.18.5", - "@smithy/fetch-http-handler": "^5.3.6", - "@smithy/hash-node": "^4.2.5", - "@smithy/invalid-dependency": "^4.2.5", - "@smithy/middleware-content-length": "^4.2.5", - "@smithy/middleware-endpoint": "^4.3.12", - "@smithy/middleware-retry": "^4.4.12", - "@smithy/middleware-serde": "^4.2.6", - "@smithy/middleware-stack": "^4.2.5", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/node-http-handler": "^4.4.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/smithy-client": "^4.9.8", - "@smithy/types": "^4.9.0", - "@smithy/url-parser": "^4.2.5", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.11", - "@smithy/util-defaults-mode-node": "^4.2.14", - "@smithy/util-endpoints": "^3.2.5", - "@smithy/util-middleware": "^4.2.5", - "@smithy/util-retry": "^4.2.5", - "@smithy/util-utf8": "^4.2.0", - "@smithy/util-waiter": "^4.2.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/client-sso": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz", - "integrity": "sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.940.0", - "@aws-sdk/middleware-host-header": "3.936.0", - "@aws-sdk/middleware-logger": "3.936.0", - "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.940.0", - "@aws-sdk/region-config-resolver": "3.936.0", - "@aws-sdk/types": "3.936.0", - "@aws-sdk/util-endpoints": "3.936.0", - "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.940.0", - "@smithy/config-resolver": "^4.4.3", - "@smithy/core": "^3.18.5", - "@smithy/fetch-http-handler": "^5.3.6", - "@smithy/hash-node": "^4.2.5", - "@smithy/invalid-dependency": "^4.2.5", - "@smithy/middleware-content-length": "^4.2.5", - "@smithy/middleware-endpoint": "^4.3.12", - "@smithy/middleware-retry": "^4.4.12", - "@smithy/middleware-serde": "^4.2.6", - "@smithy/middleware-stack": "^4.2.5", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/node-http-handler": "^4.4.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/smithy-client": "^4.9.8", - "@smithy/types": "^4.9.0", - "@smithy/url-parser": "^4.2.5", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.11", - "@smithy/util-defaults-mode-node": "^4.2.14", - "@smithy/util-endpoints": "^3.2.5", - "@smithy/util-middleware": "^4.2.5", - "@smithy/util-retry": "^4.2.5", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/core": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz", - "integrity": "sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@aws-sdk/xml-builder": "3.930.0", - "@smithy/core": "^3.18.5", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/property-provider": "^4.2.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/signature-v4": "^5.3.5", - "@smithy/smithy-client": "^4.9.8", - "@smithy/types": "^4.9.0", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-middleware": "^4.2.5", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-env": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz", - "integrity": "sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/property-provider": "^4.2.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-http": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz", - "integrity": "sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/fetch-http-handler": "^5.3.6", - "@smithy/node-http-handler": "^4.4.5", - "@smithy/property-provider": "^4.2.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/smithy-client": "^4.9.8", - "@smithy/types": "^4.9.0", - "@smithy/util-stream": "^4.5.6", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz", - "integrity": "sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/credential-provider-env": "3.940.0", - "@aws-sdk/credential-provider-http": "3.940.0", - "@aws-sdk/credential-provider-login": "3.940.0", - "@aws-sdk/credential-provider-process": "3.940.0", - "@aws-sdk/credential-provider-sso": "3.940.0", - "@aws-sdk/credential-provider-web-identity": "3.940.0", - "@aws-sdk/nested-clients": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/credential-provider-imds": "^4.2.5", - "@smithy/property-provider": "^4.2.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-login": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz", - "integrity": "sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/nested-clients": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/property-provider": "^4.2.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz", - "integrity": "sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/credential-provider-env": "3.940.0", - "@aws-sdk/credential-provider-http": "3.940.0", - "@aws-sdk/credential-provider-ini": "3.940.0", - "@aws-sdk/credential-provider-process": "3.940.0", - "@aws-sdk/credential-provider-sso": "3.940.0", - "@aws-sdk/credential-provider-web-identity": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/credential-provider-imds": "^4.2.5", - "@smithy/property-provider": "^4.2.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-process": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz", - "integrity": "sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/property-provider": "^4.2.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz", - "integrity": "sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/client-sso": "3.940.0", - "@aws-sdk/core": "3.940.0", - "@aws-sdk/token-providers": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/property-provider": "^4.2.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz", - "integrity": "sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/nested-clients": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/property-provider": "^4.2.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.936.0.tgz", - "integrity": "sha512-wNJZ8PDw0eQK2x4z1q8JqiDvw9l9xd36EoklVT2CIBt8FnqGdrMGjAx93RRbH3G6Fmvwoe+D3VJXbWHBlhD0Bw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/endpoint-cache": "3.893.0", - "@aws-sdk/types": "3.936.0", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-host-header": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", - "integrity": "sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@smithy/protocol-http": "^5.3.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-logger": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.936.0.tgz", - "integrity": "sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-recursion-detection": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.936.0.tgz", - "integrity": "sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@aws/lambda-invoke-store": "^0.2.0", - "@smithy/protocol-http": "^5.3.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/middleware-user-agent": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz", - "integrity": "sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@aws-sdk/util-endpoints": "3.936.0", - "@smithy/core": "^3.18.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/nested-clients": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz", - "integrity": "sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.940.0", - "@aws-sdk/middleware-host-header": "3.936.0", - "@aws-sdk/middleware-logger": "3.936.0", - "@aws-sdk/middleware-recursion-detection": "3.936.0", - "@aws-sdk/middleware-user-agent": "3.940.0", - "@aws-sdk/region-config-resolver": "3.936.0", - "@aws-sdk/types": "3.936.0", - "@aws-sdk/util-endpoints": "3.936.0", - "@aws-sdk/util-user-agent-browser": "3.936.0", - "@aws-sdk/util-user-agent-node": "3.940.0", - "@smithy/config-resolver": "^4.4.3", - "@smithy/core": "^3.18.5", - "@smithy/fetch-http-handler": "^5.3.6", - "@smithy/hash-node": "^4.2.5", - "@smithy/invalid-dependency": "^4.2.5", - "@smithy/middleware-content-length": "^4.2.5", - "@smithy/middleware-endpoint": "^4.3.12", - "@smithy/middleware-retry": "^4.4.12", - "@smithy/middleware-serde": "^4.2.6", - "@smithy/middleware-stack": "^4.2.5", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/node-http-handler": "^4.4.5", - "@smithy/protocol-http": "^5.3.5", - "@smithy/smithy-client": "^4.9.8", - "@smithy/types": "^4.9.0", - "@smithy/url-parser": "^4.2.5", - "@smithy/util-base64": "^4.3.0", - "@smithy/util-body-length-browser": "^4.2.0", - "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.11", - "@smithy/util-defaults-mode-node": "^4.2.14", - "@smithy/util-endpoints": "^3.2.5", - "@smithy/util-middleware": "^4.2.5", - "@smithy/util-retry": "^4.2.5", - "@smithy/util-utf8": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/region-config-resolver": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.936.0.tgz", - "integrity": "sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@smithy/config-resolver": "^4.4.3", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/token-providers": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz", - "integrity": "sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/core": "3.940.0", - "@aws-sdk/nested-clients": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/property-provider": "^4.2.5", - "@smithy/shared-ini-file-loader": "^4.4.0", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/types": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.936.0.tgz", - "integrity": "sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-dynamodb": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.940.0.tgz", - "integrity": "sha512-T8UTYtCYSPxktnk68fKBdWztnqdTQItJwi/8N9lsvp20alJ15wCQsvQR+GKB5p4TCKxOPyNEirkcrNlf5TKppA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.940.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-endpoints": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz", - "integrity": "sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@smithy/types": "^4.9.0", - "@smithy/url-parser": "^4.2.5", - "@smithy/util-endpoints": "^3.2.5", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-user-agent-browser": { - "version": "3.936.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.936.0.tgz", - "integrity": "sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/types": "3.936.0", - "@smithy/types": "^4.9.0", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws-sdk/util-user-agent-node": { - "version": "3.940.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz", - "integrity": "sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A==", - "license": "Apache-2.0", - "peer": true, - "dependencies": { - "@aws-sdk/middleware-user-agent": "3.940.0", - "@aws-sdk/types": "3.936.0", - "@smithy/node-config-provider": "^4.3.5", - "@smithy/types": "^4.9.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "aws-crt": ">=1.0.0" - }, - "peerDependenciesMeta": { - "aws-crt": { - "optional": true - } - } - }, - "lambdas/mi-stream-forwarder/node_modules/@aws/lambda-invoke-store": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.1.tgz", - "integrity": "sha512-sIyFcoPZkTtNu9xFeEoynMef3bPJIAbOfUh+ueYcfhVl6xm2VRtMcMclSxmZCMnHHd4hlYKJeq/aggmBEWynww==", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=18.0.0" - } - }, - "lambdas/mi-stream-forwarder/node_modules/pino": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/pino/-/pino-10.1.0.tgz", - "integrity": "sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==", - "license": "MIT", - "dependencies": { - "@pinojs/redact": "^0.4.0", - "atomic-sleep": "^1.0.0", - "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "^2.0.0", - "pino-std-serializers": "^7.0.0", - "process-warning": "^5.0.0", - "quick-format-unescaped": "^4.0.3", - "real-require": "^0.2.0", - "safe-stable-stringify": "^2.3.1", - "sonic-boom": "^4.0.1", - "thread-stream": "^3.0.0" + "@aws-sdk/client-kinesis": "^3.0.0", + "@aws-sdk/util-dynamodb": "^3.940.0", + "@internal/datastore": "^0.1.0", + "aws-lambda": "^1.0.7", + "jest-mock-extended": "^4.0.0", + "pino": "^10.1.0", + "zod": "^4.1.13" }, - "bin": { - "pino": "bin.js" - } - }, - "lambdas/mi-stream-forwarder/node_modules/safe-stable-stringify": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", - "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "lambdas/mi-stream-forwarder/node_modules/zod": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" + "devDependencies": { + "@types/aws-lambda": "^8.10.119", + "typescript": "^5.0.0" } }, "lambdas/mi-updates-transformer": { @@ -7983,6 +7385,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -7997,6 +7400,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8006,6 +7410,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -8036,6 +7441,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8045,6 +7451,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.5", @@ -8061,6 +7468,7 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.27.2", @@ -8077,6 +7485,7 @@ "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8086,6 +7495,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8095,6 +7505,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -8108,6 +7519,7 @@ "version": "7.28.3", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.27.1", @@ -8125,6 +7537,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8134,6 +7547,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8143,6 +7557,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8152,6 +7567,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -8161,6 +7577,7 @@ "version": "7.28.4", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.27.2", @@ -8174,6 +7591,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.5" @@ -8189,6 +7607,7 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8201,6 +7620,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8213,6 +7633,7 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" @@ -8225,6 +7646,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -8240,6 +7662,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -8255,6 +7678,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -8267,6 +7691,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8279,6 +7704,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -8294,6 +7720,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -8306,6 +7733,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8318,6 +7746,7 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" @@ -8330,6 +7759,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8342,6 +7772,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8354,6 +7785,7 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" @@ -8366,6 +7798,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -8381,6 +7814,7 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" @@ -8396,6 +7830,7 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" @@ -8421,6 +7856,7 @@ "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -8435,6 +7871,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -8453,6 +7890,7 @@ "version": "7.28.5", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -8473,6 +7911,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, "license": "MIT" }, "node_modules/@borewit/text-codec": { @@ -8490,7 +7929,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" @@ -8503,7 +7942,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -8629,6 +8068,7 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz", "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -8640,6 +8080,7 @@ "version": "1.7.1", "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz", "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -8650,6 +8091,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -9602,6 +9044,7 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -9619,6 +9062,7 @@ "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9631,6 +9075,7 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -9643,6 +9088,7 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -9660,6 +9106,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -9675,6 +9122,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -9692,6 +9140,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, "license": "ISC", "dependencies": { "camelcase": "^5.3.1", @@ -9708,6 +9157,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" @@ -9717,6 +9167,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -9730,6 +9181,7 @@ "version": "3.14.2", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "dev": true, "license": "MIT", "dependencies": { "argparse": "^1.0.7", @@ -9743,6 +9195,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -9755,6 +9208,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -9770,6 +9224,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -9782,6 +9237,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9791,6 +9247,7 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9800,6 +9257,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/console/-/console-30.2.0.tgz", "integrity": "sha512-+O1ifRjkvYIkBqASKWgLxrpEhQAAE7hY77ALLUufSk5717KfOShg6IbqLmdsLMPdUiFvA2kTs0R7YZy+l0IzZQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9817,6 +9275,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9829,6 +9288,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -9849,6 +9309,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9866,6 +9327,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -9880,6 +9342,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-30.2.0.tgz", "integrity": "sha512-03W6IhuhjqTlpzh/ojut/pDB2LPRygyWX8ExpgHtQA8H/3K7+1vKmcINx5UzeOX1se6YEsBsOHQ1CRzf3fOwTQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -9927,6 +9390,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -9939,6 +9403,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -9959,6 +9424,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -9976,6 +9442,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -9990,6 +9457,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.0.1.tgz", "integrity": "sha512-n5H8QLDJ47QqbCNn5SuFjCRDrOLEZ0h8vAHCK5RL9Ls7Xa8AQLa/YxAc9UjFqoEDM48muwtBGjtMY5cr0PLDCw==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -9999,6 +9467,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.2.0.tgz", "integrity": "sha512-/QPTL7OBJQ5ac09UDRa3EQes4gt1FTEG/8jZ/4v5IVzx+Cv7dLxlVIvfvSVRiiX2drWyXeBjkMSR8hvOWSog5g==", + "dev": true, "license": "MIT", "dependencies": { "@jest/fake-timers": "30.2.0", @@ -10060,6 +9529,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.2.0.tgz", "integrity": "sha512-V9yxQK5erfzx99Sf+7LbhBwNWEZ9eZay8qQ9+JSC0TrMR1pMDHLMY+BnVPacWU6Jamrh252/IKo4F1Xn/zfiqA==", + "dev": true, "license": "MIT", "dependencies": { "expect": "30.2.0", @@ -10086,6 +9556,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.2.0.tgz", "integrity": "sha512-HI3tRLjRxAbBy0VO8dqqm7Hb2mIa8d5bg/NJkyQcOk7V118ObQML8RC5luTF/Zsg4474a+gDvhce7eTnP4GhYw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -10103,6 +9574,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10115,6 +9587,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -10135,6 +9608,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -10152,6 +9626,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -10166,6 +9641,7 @@ "version": "30.1.0", "resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz", "integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -10175,6 +9651,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.2.0.tgz", "integrity": "sha512-b63wmnKPaK+6ZZfpYhz9K61oybvbI1aMcIs80++JI1O1rR1vaxHUCNqo3ITu6NU0d4V34yZFoHMn/uoKr/Rwfw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -10190,6 +9667,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz", "integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -10203,6 +9681,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-30.2.0.tgz", "integrity": "sha512-DRyW6baWPqKMa9CzeiBjHwjd8XeAyco2Vt8XbcLFjiwCOEKOvy82GJ8QQnJE9ofsxCMPjH4MfH8fCWIHHDKpAQ==", + "dev": true, "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", @@ -10245,6 +9724,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -10257,6 +9737,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -10277,6 +9758,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -10294,6 +9776,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -10308,6 +9791,7 @@ "version": "30.0.5", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz", "integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==", + "dev": true, "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.34.0" @@ -10320,12 +9804,14 @@ "version": "0.34.41", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.41.tgz", "integrity": "sha512-6gS8pZzSXdyRHTIqoqSVknxolr1kzfy4/CeDnrzsVz8TTIWUbOBr6gnzOmTYJ3eXQNh4IYHIGi5aIL7sOZ2G/g==", + "dev": true, "license": "MIT" }, "node_modules/@jest/snapshot-utils": { "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.2.0.tgz", "integrity": "sha512-0aVxM3RH6DaiLcjj/b0KrIBZhSX1373Xci4l3cW5xiUWPctZ59zQ7jj4rqcJQ/Z8JuN/4wX3FpJSa3RssVvCug==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -10341,6 +9827,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-30.0.1.tgz", "integrity": "sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", @@ -10355,6 +9842,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-30.2.0.tgz", "integrity": "sha512-RF+Z+0CCHkARz5HT9mcQCBulb1wgCP3FBvl9VFokMX27acKphwyQsNuWH3c+ojd1LeWBLoTYoxF0zm6S/66mjg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -10519,6 +10007,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.2.0.tgz", "integrity": "sha512-XsauDV82o5qXbhalKxD7p4TZYYdwcaEXC77PPD2HixEFF+6YGppjrAAQurTl2ECWcEomHBMMNS9AH3kcCFx8jA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -10545,6 +10034,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -10562,6 +10052,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/types/-/types-30.2.0.tgz", "integrity": "sha512-H9xg1/sfVvyfU7o3zMfBEjQ1gcsdeTMgqHoYdN79tuLqfTtuu7WckRA1R5whDwOzxaZAeMKTYWqP+WCAi0CHsg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/pattern": "30.0.1", @@ -10580,6 +10071,7 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -10590,6 +10082,7 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -10600,6 +10093,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -10609,12 +10103,14 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -10691,6 +10187,7 @@ "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -11259,6 +10756,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, "license": "MIT", "optional": true, "engines": { @@ -11269,6 +10767,7 @@ "version": "0.2.9", "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz", "integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==", + "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.18.0 || >=16.0.0" @@ -11807,6 +11306,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" @@ -11816,6 +11316,7 @@ "version": "13.0.5", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -13200,28 +12701,28 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node22": { @@ -13235,6 +12736,7 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -13251,6 +12753,7 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", @@ -13264,6 +12767,7 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" @@ -13273,6 +12777,7 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", @@ -13283,6 +12788,7 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.2" @@ -13342,12 +12848,14 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" @@ -13357,6 +12865,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" @@ -13444,6 +12953,7 @@ "version": "24.10.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -13497,6 +13007,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, "license": "MIT" }, "node_modules/@types/stylis": { @@ -13532,6 +13043,7 @@ "version": "17.0.35", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "dev": true, "license": "MIT", "dependencies": { "@types/yargs-parser": "*" @@ -13541,6 +13053,7 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -13791,6 +13304,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13804,6 +13318,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13817,6 +13332,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13830,6 +13346,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13843,6 +13360,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13856,6 +13374,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13869,6 +13388,7 @@ "cpu": [ "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13882,6 +13402,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13895,6 +13416,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13908,6 +13430,7 @@ "cpu": [ "ppc64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13921,6 +13444,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13934,6 +13458,7 @@ "cpu": [ "riscv64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13947,6 +13472,7 @@ "cpu": [ "s390x" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13960,6 +13486,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13973,6 +13500,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -13986,6 +13514,7 @@ "cpu": [ "wasm32" ], + "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -14002,6 +13531,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14015,6 +13545,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14028,6 +13559,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -14057,7 +13589,7 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "devOptional": true, + "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -14080,7 +13612,7 @@ "version": "8.3.4", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "acorn": "^8.11.0" @@ -14221,6 +13753,7 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, "license": "MIT", "dependencies": { "type-fest": "^0.21.3" @@ -14260,6 +13793,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -14273,6 +13807,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -15080,6 +14615,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, "license": "BSD-3-Clause", "workspaces": [ "test/babel-8" @@ -15115,6 +14651,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -15281,6 +14818,7 @@ "version": "2.8.28", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.28.tgz", "integrity": "sha512-gYjt7OIqdM0PcttNYP2aVrr2G0bMALkBaoehD4BuRGjAOtipg0b6wHg1yNL+s5zSnLZZrGHOw4IrND8CD+3oIQ==", + "dev": true, "license": "Apache-2.0", "bin": { "baseline-browser-mapping": "dist/cli.js" @@ -15492,6 +15030,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -15501,6 +15040,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -15513,6 +15053,7 @@ "version": "4.28.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "dev": true, "funding": [ { "type": "opencollective", @@ -15559,6 +15100,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" @@ -15603,6 +15145,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, "license": "MIT" }, "node_modules/buildcheck": { @@ -15712,6 +15255,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -15721,6 +15265,7 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -15740,6 +15285,7 @@ "version": "1.0.30001755", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001755.tgz", "integrity": "sha512-44V+Jm6ctPj7R52Na4TLi3Zri4dWUljJd+RDm+j8LtNCc/ihLCT+X1TzoOAkRETEWqjuLnh9581Tl80FvK7jVA==", + "dev": true, "funding": [ { "type": "opencollective", @@ -15798,6 +15344,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -15855,6 +15402,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, "funding": [ { "type": "github", @@ -15870,6 +15418,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-2.1.1.tgz", "integrity": "sha512-+CmxIZ/L2vNcEfvNtLdU0ZQ6mbq3FZnwAP2PPTiKP+1QOoKwlKlPgb8UKV0Dds7QVaMnHm+FwSft2VB0s/SLjQ==", + "dev": true, "license": "MIT" }, "node_modules/classnames": { @@ -16021,6 +15570,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, "license": "MIT", "engines": { "iojs": ">= 1.0.0", @@ -16031,6 +15581,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz", "integrity": "sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==", + "dev": true, "license": "MIT" }, "node_modules/color-convert": { @@ -16351,6 +15902,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -17179,7 +16731,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { @@ -17347,6 +16899,7 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -17377,6 +16930,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.0.tgz", "integrity": "sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==", + "dev": true, "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -17407,6 +16961,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -17499,6 +17054,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -17508,7 +17064,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" @@ -17757,12 +17313,14 @@ "version": "1.5.254", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.254.tgz", "integrity": "sha512-DcUsWpVhv9svsKRxnSCZ86SjD+sp32SGidNB37KpqXJncp1mfUgKbHvBomE89WJDbfVKw1mdv5+ikrvd43r+Bg==", + "dev": true, "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -17804,6 +17362,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -19190,6 +18749,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/exit-x/-/exit-x-0.2.2.tgz", "integrity": "sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==", + "dev": true, "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -19199,6 +18759,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/expect/-/expect-30.2.0.tgz", "integrity": "sha512-u/feCi0GPsI+988gU2FLcsHyAHTU0MX1Wg68NhAnN7z/+C5wqG+CY8J53N9ioe8RXgaoz0nBR/TYMf3AycUuPw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/expect-utils": "30.2.0", @@ -19216,6 +18777,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0" @@ -19228,6 +18790,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -19240,6 +18803,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -19255,6 +18819,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -19270,6 +18835,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -19290,6 +18856,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -19307,6 +18874,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -19358,6 +18926,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -19429,6 +18998,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" @@ -19521,6 +19091,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -19627,6 +19198,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.6", @@ -19682,12 +19254,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -19758,6 +19332,7 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -19812,6 +19387,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.0.0" @@ -19923,6 +19499,7 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -20151,6 +19728,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, "license": "MIT" }, "node_modules/htmlparser2": { @@ -20297,6 +19875,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", @@ -20316,6 +19895,7 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.8.19" @@ -20352,6 +19932,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -20460,6 +20041,7 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -20690,6 +20272,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -20767,6 +20350,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -21015,6 +20599,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=8" @@ -21024,6 +20609,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", @@ -21040,6 +20626,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", @@ -21054,6 +20641,7 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "@jridgewell/trace-mapping": "^0.3.23", @@ -21068,6 +20656,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", @@ -21109,6 +20698,7 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -21124,6 +20714,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest/-/jest-30.2.0.tgz", "integrity": "sha512-F26gjC0yWN8uAA5m5Ss8ZQf5nDHWGlN/xWZIh8S5SRbsEKBovwZhxGd6LJlbZYxBgCYOtreSUyb8hpXyGC5O4A==", + "dev": true, "license": "MIT", "dependencies": { "@jest/core": "30.2.0", @@ -21150,6 +20741,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-30.2.0.tgz", "integrity": "sha512-L8lR1ChrRnSdfeOvTrwZMlnWV8G/LLjQ0nG9MBclwWZidA2N5FviRki0Bvh20WRMOX31/JYvzdqTJrk5oBdydQ==", + "dev": true, "license": "MIT", "dependencies": { "execa": "^5.1.1", @@ -21164,6 +20756,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21730,6 +21323,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-30.2.0.tgz", "integrity": "sha512-Os9ukIvADX/A9sLt6Zse3+nmHtHaE6hqOsjQtNiugFTbKRHYIYtZXNGNK9NChseXy7djFPjndX1tL0sCTlfpAA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/core": "30.2.0", @@ -21762,6 +21356,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -21776,6 +21371,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -21793,6 +21389,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -21810,6 +21407,7 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -21828,6 +21426,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-30.2.0.tgz", "integrity": "sha512-g4WkyzFQVWHtu6uqGmQR4CQxz/CH3yDSlhzXMWzNjDx843gYjReZnMRanjRCq5XZFuQrGDxgUaiYWE8BRfVckA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -21879,6 +21478,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-30.2.0.tgz", "integrity": "sha512-wXKgU/lk8fKXMu/l5Hog1R61bL4q5GCdT6OJvdAFz1P+QrpoFuLU68eoKuVc4RbrTtNnTL5FByhWdLgOPSph+Q==", + "dev": true, "license": "MIT", "dependencies": { "@jest/test-result": "30.2.0", @@ -21894,6 +21494,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -21906,6 +21507,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-30.2.0.tgz", "integrity": "sha512-0YiBEOxWqKkSQWL9nNGGEgndoeL0ZpWrbLMNL5u/Kaxrli3Eaxlt3ZtIDktEvXt4L/R9r3ODr2zKwGM/2BjxVw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/transform": "30.2.0", @@ -21927,6 +21529,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-30.2.0.tgz", "integrity": "sha512-ftzhzSGMUnOzcCXd6WHdBGMyuwy15Wnn0iyyWGKgBDLxf9/s5ABuraCSpBX2uG0jUg4rqJnxsLc5+oYBqoxVaA==", + "dev": true, "license": "MIT", "dependencies": { "@types/babel__core": "^7.20.5" @@ -21939,6 +21542,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-30.2.0.tgz", "integrity": "sha512-US4Z3NOieAQumwFnYdUWKvUKh8+YSnS/gB3t6YBiz0bskpu7Pine8pPCheNxlPEW4wnUkma2a94YuW2q3guvCQ==", + "dev": true, "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "30.2.0", @@ -21955,6 +21559,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-30.2.0.tgz", "integrity": "sha512-Fh0096NC3ZkFx05EP2OXCxJAREVxj1BcW/i6EWqqymcgYKWjyyDpral3fMxVcHXg6oZM7iULer9wGRFvfpl+Tg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -21986,6 +21591,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -22001,6 +21607,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-30.2.0.tgz", "integrity": "sha512-lpWlJlM7bCUf1mfmuqTA8+j2lNURW9eNafOy99knBM01i5CQeY5UH1vZjgT9071nDJac1M4XsbyI44oNOdhlDQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -22017,6 +21624,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -22035,6 +21643,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -22050,6 +21659,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -22070,6 +21680,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22087,6 +21698,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -22101,6 +21713,7 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, "funding": [ { "type": "individual", @@ -22133,6 +21746,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-30.2.0.tgz", "integrity": "sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==", + "dev": true, "license": "MIT", "dependencies": { "detect-newline": "^3.1.0" @@ -22336,6 +21950,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.2.0.tgz", "integrity": "sha512-sQA/jCb9kNt+neM0anSj6eZhLZUIhQgwDt7cPGjumgLM4rXsfb9kpnlacmvZz3Q5tb80nS+oG/if+NBKrHC+Xw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22360,6 +21975,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22400,6 +22016,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-30.2.0.tgz", "integrity": "sha512-M6jKAjyzjHG0SrQgwhgZGy9hFazcudwCNovY/9HPIicmNSBuockPSedAP9vlPK6ONFJ1zfyH/M2/YYJxOz5cdQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -22413,6 +22030,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22425,6 +22043,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -22507,6 +22126,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.2.0.tgz", "integrity": "sha512-JNNNl2rj4b5ICpmAcq+WbLH83XswjPbjH4T7yvGzfAGCPh1rw+xVNbtk+FnRslvt9lkCcdn9i1oAoKUuFsOxRw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22521,6 +22141,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/jest-mock-extended/-/jest-mock-extended-4.0.0.tgz", "integrity": "sha512-7BZpfuvLam+/HC+NxifIi9b+5VXj/utUDMPUqrDJehGWVuXPtLS9Jqlob2mJLrI/pg2k1S8DMfKDvEB88QNjaQ==", + "dev": true, "license": "MIT", "dependencies": { "ts-essentials": "^10.0.2" @@ -22535,6 +22156,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22552,6 +22174,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -22569,6 +22192,7 @@ "version": "30.0.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz", "integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==", + "dev": true, "license": "MIT", "engines": { "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" @@ -22578,6 +22202,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-30.2.0.tgz", "integrity": "sha512-TCrHSxPlx3tBY3hWNtRQKbtgLhsXa1WmbJEqBlTBrGafd5fiQFByy2GNCEoGR+Tns8d15GaL9cxEzKOO3GEb2A==", + "dev": true, "license": "MIT", "dependencies": { "chalk": "^4.1.2", @@ -22597,6 +22222,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-30.2.0.tgz", "integrity": "sha512-xTOIGug/0RmIe3mmCqCT95yO0vj6JURrn1TKWlNbhiAefJRWINNPgwVkrVgt/YaerPzY3iItufd80v3lOrFJ2w==", + "dev": true, "license": "MIT", "dependencies": { "jest-regex-util": "30.0.1", @@ -22610,6 +22236,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22627,6 +22254,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-30.2.0.tgz", "integrity": "sha512-PqvZ2B2XEyPEbclp+gV6KO/F1FIFSbIwewRgmROCMBo/aZ6J1w8Qypoj2pEOcg3G2HzLlaP6VUtvwCI8dM3oqQ==", + "dev": true, "license": "MIT", "dependencies": { "@jest/console": "30.2.0", @@ -22660,6 +22288,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22672,6 +22301,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-30.2.0.tgz", "integrity": "sha512-ElU8v92QJ9UrYsKrxDIKCxu6PfNj4Hdcktcn0JX12zqNdqWHB0N+hwOnnBBXvjLd2vApZtuLUGs1QSY+MsXoNA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -22690,6 +22320,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -22710,6 +22341,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22727,6 +22359,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -22741,6 +22374,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-30.2.0.tgz", "integrity": "sha512-p1+GVX/PJqTucvsmERPMgCPvQJpFt4hFbM+VN3n8TMo47decMUcJbt+rgzwrEme0MQUA/R+1de2axftTHkKckg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/environment": "30.2.0", @@ -22774,6 +22408,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22786,6 +22421,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -22806,6 +22442,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22823,6 +22460,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -22837,6 +22475,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.2.0.tgz", "integrity": "sha512-5WEtTy2jXPFypadKNpbNkZ72puZCa6UjSr/7djeecHWOu7iYhSXSnHScT8wBz3Rn8Ena5d5RYRcsyKIeqG1IyA==", + "dev": true, "license": "MIT", "dependencies": { "@babel/core": "^7.27.4", @@ -22869,6 +22508,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.2.0.tgz", "integrity": "sha512-1JnRfhqpD8HGpOmQp180Fo9Zt69zNtC+9lR+kT7NVL05tNXIi+QC8Csz7lfidMoVLPD3FnOtcmp0CEFnxExGEA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0" @@ -22881,6 +22521,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -22893,6 +22534,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.2.0.tgz", "integrity": "sha512-dQHFo3Pt4/NLlG5z4PxZ/3yZTZ1C7s9hveiOj+GCN+uT109NC2QgsoVZsVOAvbJ3RgKkvyLGXZV9+piDpWbm6A==", + "dev": true, "license": "MIT", "dependencies": { "@jest/diff-sequences": "30.0.1", @@ -22908,6 +22550,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.2.0.tgz", "integrity": "sha512-dQ94Nq4dbzmUWkQ0ANAWS9tBRfqCrn0bV9AMYdOi/MHW726xn7eQmMeRTpX2ViC00bpNaWXq+7o4lIQ3AX13Hg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -22923,6 +22566,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.2.0.tgz", "integrity": "sha512-y4DKFLZ2y6DxTWD4cDe07RglV88ZiNEdlRfGtqahfbIjfsw1nMCPx49Uev4IA/hWn3sDKyAnSPwoYSsAEdcimw==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -22943,6 +22587,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -22960,6 +22605,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -23052,6 +22698,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-30.2.0.tgz", "integrity": "sha512-FBGWi7dP2hpdi8nBoWxSsLvBFewKAg0+uSQwBaof4Y4DPgBabXgpSYC5/lR7VmnIlSpASmCi/ntRWPbv7089Pw==", + "dev": true, "license": "MIT", "dependencies": { "@jest/get-type": "30.1.0", @@ -23069,6 +22716,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -23081,6 +22729,7 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -23093,6 +22742,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.2.0.tgz", "integrity": "sha512-9uBdv/B4EefsuAL+pWqueZyZS2Ba+LxfFeQ9DN14HU4bN8bhaxKdkpjpB6fs9+pSjIBu+FXQHImEg8j/Lw0+vA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/schemas": "30.0.5", @@ -23107,6 +22757,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-30.2.0.tgz", "integrity": "sha512-PYxa28dxJ9g777pGm/7PrbnMeA0Jr7osHP9bS7eJy9DuAjMgdGtxgf0uKMyoIsTWAkIbUW5hSDdJ3urmgXBqxg==", + "dev": true, "license": "MIT", "dependencies": { "@jest/test-result": "30.2.0", @@ -23126,6 +22777,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -23143,6 +22795,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.2.0.tgz", "integrity": "sha512-0Q4Uk8WF7BUwqXHuAjc23vmopWJw5WH7w2tqBoUOZpOjW/ZnR44GXXd1r82RvnmI2GZge3ivrYXk/BE2+VtW2g==", + "dev": true, "license": "MIT", "dependencies": { "@types/node": "*", @@ -23159,6 +22812,7 @@ "version": "30.2.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.2.0.tgz", "integrity": "sha512-QKNsM0o3Xe6ISQU869e+DhG+4CK/48aHYdJZGlFQVTjnbvgpcKyxpzk29fGiO7i/J8VENZ+d2iGnSsvmuHywlA==", + "dev": true, "license": "MIT", "dependencies": { "@jest/types": "30.2.0", @@ -23176,6 +22830,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -23210,6 +22865,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -23278,6 +22934,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -23297,6 +22954,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, "license": "MIT" }, "node_modules/json-pointer": { @@ -23341,6 +22999,7 @@ "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, "license": "MIT", "bin": { "json5": "lib/cli.js" @@ -23577,6 +23236,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -23600,6 +23260,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, "license": "MIT" }, "node_modules/load-esm": { @@ -23713,6 +23374,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^3.0.2" @@ -23739,6 +23401,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, "license": "MIT", "dependencies": { "semver": "^7.5.3" @@ -23754,13 +23417,14 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true, + "dev": true, "license": "ISC" }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" @@ -23829,14 +23493,11 @@ "node": ">= 8" } }, - "node_modules/mi-stream-forwarder": { - "resolved": "lambdas/mi-stream-forwarder", - "link": true - }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -23850,6 +23511,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -23893,6 +23555,7 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -23917,6 +23580,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -24018,6 +23682,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, "license": "MIT" }, "node_modules/mute-stream": { @@ -24058,6 +23723,7 @@ "version": "0.3.4", "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", + "dev": true, "license": "MIT", "bin": { "napi-postinstall": "lib/cli.js" @@ -24073,6 +23739,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, "license": "MIT" }, "node_modules/natural-compare-lite": { @@ -24236,6 +23903,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, "license": "MIT" }, "node_modules/node-readfiles": { @@ -24252,6 +23920,7 @@ "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, "license": "MIT" }, "node_modules/node-sarif-builder": { @@ -24287,6 +23956,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -24537,6 +24207,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -24753,6 +24424,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -24784,6 +24456,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -24827,6 +24500,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { @@ -24846,6 +24520,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", @@ -24884,6 +24559,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -24893,6 +24569,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -24924,6 +24601,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -24940,6 +24618,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, "license": "ISC" }, "node_modules/path-to-regexp": { @@ -24964,12 +24643,14 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -25028,6 +24709,7 @@ "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -25037,6 +24719,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, "license": "MIT", "dependencies": { "find-up": "^4.0.0" @@ -25049,6 +24732,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -25062,6 +24746,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -25074,6 +24759,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -25089,6 +24775,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -25624,6 +25311,7 @@ "version": "19.0.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==", + "dev": true, "license": "MIT" }, "node_modules/react-tabs": { @@ -25939,6 +25627,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" @@ -25951,6 +25640,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -26238,6 +25928,7 @@ "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -26608,6 +26299,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -26690,6 +26382,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -26759,6 +26452,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -26778,6 +26472,7 @@ "version": "0.5.13", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", @@ -26875,6 +26570,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" @@ -26887,6 +26583,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -26949,6 +26646,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, "license": "MIT", "dependencies": { "char-regex": "^1.0.2", @@ -26977,6 +26675,7 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -26991,6 +26690,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, "license": "MIT" }, "node_modules/string-width/node_modules/emoji-regex": { @@ -27129,6 +26829,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -27141,6 +26842,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -27172,6 +26874,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -27316,6 +27019,7 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.11.tgz", "integrity": "sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==", + "dev": true, "license": "MIT", "dependencies": { "@pkgr/core": "^0.2.9" @@ -27358,6 +27062,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", @@ -27372,6 +27077,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -27383,6 +27089,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -27403,6 +27110,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -27529,12 +27237,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -27622,6 +27332,7 @@ "version": "10.1.1", "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-10.1.1.tgz", "integrity": "sha512-4aTB7KLHKmUvkjNj8V+EdnmuVTiECzn3K+zIbRthumvHu+j44x3w63xpfs0JL3NGIzGXqoQ7AV591xHO+XrOTw==", + "dev": true, "license": "MIT", "peerDependencies": { "typescript": ">=4.5.0" @@ -27702,7 +27413,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -27746,7 +27457,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/tsconfig-paths": { @@ -27835,6 +27546,7 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -27844,6 +27556,7 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" @@ -27934,6 +27647,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -28056,6 +27770,7 @@ "version": "1.11.1", "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -28090,6 +27805,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "dev": true, "funding": [ { "type": "opencollective", @@ -28230,13 +27946,14 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", @@ -28325,6 +28042,7 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" @@ -28612,6 +28330,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -28629,12 +28348,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, "license": "ISC" }, "node_modules/write-file-atomic": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", @@ -28728,6 +28449,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, "license": "ISC" }, "node_modules/yaml": { @@ -28789,7 +28511,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -28799,6 +28521,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -28892,7 +28615,6 @@ "@aws-sdk/client-s3": "^3.858.0", "@internal/datastore": "*", "esbuild": "^0.25.11", - "get-east-asian-width": "^1.4.0", "pino": "^9.7.0", "yargs": "^18.0.0" }, From 5cf2883fb7227eca37b72c04ec3d4b8a38924d15 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 4 Dec 2025 09:16:34 +0000 Subject: [PATCH 16/21] logging and refactor --- .../src/mi-updates-transformer.ts | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index c9a4dbca..8eb7075e 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -1,4 +1,5 @@ -import { Handler, KinesisStreamEvent } from "aws-lambda"; +import { Handler, KinesisStreamEvent, KinesisStreamRecord } from "aws-lambda"; +import { MI } from "@internal/datastore"; import { PublishBatchCommand, PublishBatchRequestEntry, @@ -15,25 +16,30 @@ function* generateBatches(events: MISubmittedEvent[]) { } } -function buildMessage(event: MISubmittedEvent): PublishBatchRequestEntry { - return { +function buildMessage( + event: MISubmittedEvent, + deps: Deps, +): PublishBatchRequestEntry { + const message = { Id: event.id, Message: JSON.stringify(event), }; + deps.logger.info({ description: "Built message", message }); + return message; +} + +function extractPayload(record: KinesisStreamRecord, deps: Deps): MI { + const payload = Buffer.from(record.kinesis.data, "base64").toString("utf8"); + deps.logger.info({ description: "Extracted payload", payload }); + return JSON.parse(payload); } export function createHandler(deps: Deps): Handler { return async (streamEvent: KinesisStreamEvent) => { deps.logger.info({ description: "Received event", streamEvent }); - const cloudEvents: MISubmittedEvent[] = streamEvent.Records.map( - (record) => { - // Kinesis data is base64 encoded - const payload = Buffer.from(record.kinesis.data, "base64").toString( - "utf8", - ); - return JSON.parse(payload); - }, + const cloudEvents: MISubmittedEvent[] = streamEvent.Records.map((record) => + extractPayload(record, deps), ).map((element) => mapMIToCloudEvent(element)); for (const batch of generateBatches(cloudEvents)) { @@ -41,7 +47,7 @@ export function createHandler(deps: Deps): Handler { new PublishBatchCommand({ TopicArn: deps.env.EVENTPUB_SNS_TOPIC_ARN, PublishBatchRequestEntries: batch.map((element) => - buildMessage(element), + buildMessage(element, deps), ), }), ); From 80cfca22fe8da827c77abc2e468a85a09acfc578 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 4 Dec 2025 11:49:04 +0000 Subject: [PATCH 17/21] logging for investigation --- .../src/__tests__/mi-updates-transformer.test.ts | 10 +++++----- .../src/mappers/__tests__/mi-mapper.test.ts | 14 +++++++++++++- .../src/mappers/mi-mapper.ts | 5 ++++- .../src/mi-updates-transformer.ts | 6 +++--- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts index 49dde4cc..225eb674 100644 --- a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts +++ b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts @@ -70,7 +70,7 @@ describe("mi-updates-transformer Lambda", () => { const miEvents = generateMIEvents(1); const expectedEntries = [ expect.objectContaining({ - Message: JSON.stringify(mapMIToCloudEvent(miEvents[0])), + Message: JSON.stringify(mapMIToCloudEvent(miEvents[0], mockedDeps)), }), ]; @@ -95,7 +95,7 @@ describe("mi-updates-transformer Lambda", () => { const miEvents = generateMIEvents(10); const expectedEntries = miEvents.map((miEvent) => expect.objectContaining({ - Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + Message: JSON.stringify(mapMIToCloudEvent(miEvent, mockedDeps)), }), ); @@ -121,17 +121,17 @@ describe("mi-updates-transformer Lambda", () => { const expectedEntries = [ miEvents.slice(0, 10).map((miEvent) => expect.objectContaining({ - Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + Message: JSON.stringify(mapMIToCloudEvent(miEvent, mockedDeps)), }), ), miEvents.slice(10, 20).map((miEvent) => expect.objectContaining({ - Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + Message: JSON.stringify(mapMIToCloudEvent(miEvent, mockedDeps)), }), ), miEvents.slice(20).map((miEvent) => expect.objectContaining({ - Message: JSON.stringify(mapMIToCloudEvent(miEvent)), + Message: JSON.stringify(mapMIToCloudEvent(miEvent, mockedDeps)), }), ), ]; diff --git a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts index 30e15251..b3a4a8a2 100644 --- a/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts +++ b/lambdas/mi-updates-transformer/src/mappers/__tests__/mi-mapper.test.ts @@ -1,8 +1,20 @@ +import { SNSClient } from "@aws-sdk/client-sns"; +import * as pino from "pino"; import { $MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; import { MI } from "@internal/datastore"; import { mapMIToCloudEvent } from "../mi-mapper"; +import { EnvVars } from "../../env"; +import { Deps } from "../../deps"; describe("mi-mapper", () => { + const mockedDeps: jest.Mocked = { + snsClient: { send: jest.fn() } as unknown as SNSClient, + logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger, + env: { + EVENTPUB_SNS_TOPIC_ARN: "arn:aws:sns:region:account:topic", + } as unknown as EnvVars, + } as Deps; + it("maps an MI to an MI event", async () => { const mi: MI = { id: "id1", @@ -18,7 +30,7 @@ describe("mi-mapper", () => { stockRemaining: 500, }; jest.useFakeTimers().setSystemTime(new Date("2025-11-24T15:55:18Z")); - const event = mapMIToCloudEvent(mi); + const event = mapMIToCloudEvent(mi, mockedDeps); // Check it conforms to the MI event schema - parse will throw an error if not $MISubmittedEvent.parse(event); diff --git a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts index 3726e3e1..26153c24 100644 --- a/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts +++ b/lambdas/mi-updates-transformer/src/mappers/mi-mapper.ts @@ -1,12 +1,15 @@ import { MI } from "@internal/datastore"; import { MISubmittedEvent } from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src"; import { randomBytes, randomUUID } from "node:crypto"; +import { Deps } from "../deps"; -export function mapMIToCloudEvent(mi: MI): MISubmittedEvent { +export function mapMIToCloudEvent(mi: MI, deps: Deps): MISubmittedEvent { const now = new Date().toISOString(); const eventId = randomUUID(); const dataschemaversion = "1.1.5"; + deps.logger.info({ description: "Mapping MI to CloudEvent", mi, eventId }); + return { specversion: "1.0", id: eventId, diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index 8eb7075e..837eaa7f 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -38,9 +38,9 @@ export function createHandler(deps: Deps): Handler { return async (streamEvent: KinesisStreamEvent) => { deps.logger.info({ description: "Received event", streamEvent }); - const cloudEvents: MISubmittedEvent[] = streamEvent.Records.map((record) => - extractPayload(record, deps), - ).map((element) => mapMIToCloudEvent(element)); + const cloudEvents: MISubmittedEvent[] = streamEvent.Records + .map((record) => extractPayload(record, deps)) + .map((payload) => mapMIToCloudEvent(payload, deps)); for (const batch of generateBatches(cloudEvents)) { await deps.snsClient.send( From 9f3836e4b5fcd73a31b289c796335266079bacf8 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 4 Dec 2025 12:54:17 +0000 Subject: [PATCH 18/21] fix extract payload --- .../src/mi-updates-transformer.ts | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index 837eaa7f..67962c5c 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -1,5 +1,10 @@ -import { Handler, KinesisStreamEvent, KinesisStreamRecord } from "aws-lambda"; -import { MI } from "@internal/datastore"; +import { + DynamoDBRecord, + Handler, + KinesisStreamEvent, + KinesisStreamRecord, +} from "aws-lambda"; +import { MI, MISchema } from "@internal/datastore"; import { PublishBatchCommand, PublishBatchRequestEntry, @@ -28,18 +33,28 @@ function buildMessage( return message; } -function extractPayload(record: KinesisStreamRecord, deps: Deps): MI { +function extractPayload( + record: KinesisStreamRecord, + deps: Deps, +): DynamoDBRecord { const payload = Buffer.from(record.kinesis.data, "base64").toString("utf8"); deps.logger.info({ description: "Extracted payload", payload }); return JSON.parse(payload); } +function extractMIData(record: DynamoDBRecord): MI { + const newImage = record.dynamodb?.NewImage!; + return MISchema.parse(unmarshall(newImage as any)); +} + export function createHandler(deps: Deps): Handler { return async (streamEvent: KinesisStreamEvent) => { deps.logger.info({ description: "Received event", streamEvent }); - const cloudEvents: MISubmittedEvent[] = streamEvent.Records - .map((record) => extractPayload(record, deps)) + const cloudEvents: MISubmittedEvent[] = streamEvent.Records.map((record) => + extractPayload(record, deps), + ) + .map((element) => extractMIData(element)) .map((payload) => mapMIToCloudEvent(payload, deps)); for (const batch of generateBatches(cloudEvents)) { From b3425a4e00f9a6e6563b5a9330b1b8fd13bef040 Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 4 Dec 2025 13:49:57 +0000 Subject: [PATCH 19/21] fix mapping --- lambdas/mi-updates-transformer/package.json | 1 + .../__tests__/mi-updates-transformer.test.ts | 45 +- .../src/mi-updates-transformer.ts | 1 + package-lock.json | 488 ++++++++++++++++++ 4 files changed, 520 insertions(+), 15 deletions(-) diff --git a/lambdas/mi-updates-transformer/package.json b/lambdas/mi-updates-transformer/package.json index 8f0f0c36..c0ff2fc5 100644 --- a/lambdas/mi-updates-transformer/package.json +++ b/lambdas/mi-updates-transformer/package.json @@ -1,6 +1,7 @@ { "dependencies": { "@aws-sdk/client-sns": "^3.940.0", + "@aws-sdk/util-dynamodb": "^3.943.0", "@internal/datastore": "^0.1.0", "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", "aws-lambda": "^1.0.7", diff --git a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts index 225eb674..ceebfc2a 100644 --- a/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts +++ b/lambdas/mi-updates-transformer/src/__tests__/mi-updates-transformer.test.ts @@ -1,7 +1,9 @@ import { SNSClient } from "@aws-sdk/client-sns"; import * as pino from "pino"; import { + AttributeValue, Context, + DynamoDBRecord, KinesisStreamEvent, KinesisStreamRecordPayload, } from "aws-lambda"; @@ -48,6 +50,25 @@ function generateMIEvents(numMIEvents: number): MI[] { })); } +function toAttr(value: unknown): AttributeValue { + if (value === null || value === undefined) return { NULL: true }; + if (typeof value === "string") return { S: value }; + if (typeof value === "number") return { N: String(value) }; + if (typeof value === "boolean") return { BOOL: value }; + // fallback: stringify anything else + return { S: JSON.stringify(value) }; +} + +function generateInsertRecord(newMI: MI): DynamoDBRecord { + const newImage = Object.fromEntries( + Object.entries(newMI).map(([key, value]) => [key, toAttr(value)]), + ); + return { + eventName: "INSERT", + dynamodb: { NewImage: newImage }, + }; +} + describe("mi-updates-transformer Lambda", () => { const mockedDeps: jest.Mocked = { snsClient: { send: jest.fn() } as unknown as SNSClient, @@ -74,11 +95,9 @@ describe("mi-updates-transformer Lambda", () => { }), ]; - await handler( - generateKinesisEvent(miEvents), - mockDeep(), - jest.fn(), - ); + const insertMI = generateInsertRecord(miEvents[0]); + const testData = generateKinesisEvent([insertMI]); + await handler(testData, mockDeep(), jest.fn()); expect(mockedDeps.snsClient.send).toHaveBeenCalledWith( expect.objectContaining({ @@ -99,11 +118,9 @@ describe("mi-updates-transformer Lambda", () => { }), ); - await handler( - generateKinesisEvent(miEvents), - mockDeep(), - jest.fn(), - ); + const insertMIs = miEvents.map((miEvent) => generateInsertRecord(miEvent)); + const testData = generateKinesisEvent(insertMIs); + await handler(testData, mockDeep(), jest.fn()); expect(mockedDeps.snsClient.send).toHaveBeenCalledWith( expect.objectContaining({ @@ -136,11 +153,9 @@ describe("mi-updates-transformer Lambda", () => { ), ]; - await handler( - generateKinesisEvent(miEvents), - mockDeep(), - jest.fn(), - ); + const insertMIs = miEvents.map((miEvent) => generateInsertRecord(miEvent)); + const testData = generateKinesisEvent(insertMIs); + await handler(testData, mockDeep(), jest.fn()); expect(mockedDeps.snsClient.send).toHaveBeenNthCalledWith( 1, diff --git a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts index 67962c5c..7891398e 100644 --- a/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts +++ b/lambdas/mi-updates-transformer/src/mi-updates-transformer.ts @@ -4,6 +4,7 @@ import { KinesisStreamEvent, KinesisStreamRecord, } from "aws-lambda"; +import { unmarshall } from "@aws-sdk/util-dynamodb"; import { MI, MISchema } from "@internal/datastore"; import { PublishBatchCommand, diff --git a/package-lock.json b/package-lock.json index a1ac0537..1e4f7a22 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3036,6 +3036,7 @@ "version": "0.0.1", "dependencies": { "@aws-sdk/client-sns": "^3.940.0", + "@aws-sdk/util-dynamodb": "^3.943.0", "@internal/datastore": "^0.1.0", "@nhsdigital/nhs-notify-event-schemas-supplier-api": "*", "aws-lambda": "^1.0.7", @@ -3052,6 +3053,414 @@ "typescript": "^5.8.3" } }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.943.0.tgz", + "integrity": "sha512-1VvbsDSBrrvQ2UwdDab+YNpygyoDRSlOQ452KlEPh3jo155bMkiiY1siXaaXj0EMVwhPsLyKvbM4eBSl0Bi0yA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.943.0", + "@aws-sdk/credential-provider-node": "3.943.0", + "@aws-sdk/dynamodb-codec": "3.943.0", + "@aws-sdk/middleware-endpoint-discovery": "3.936.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.943.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.943.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "@smithy/util-waiter": "^4.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/client-sso": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.943.0.tgz", + "integrity": "sha512-kOTO2B8Ks2qX73CyKY8PAajtf5n39aMe2spoiOF5EkgSzGV7hZ/HONRDyADlyxwfsX39Q2F2SpPUaXzon32IGw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.943.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.943.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.943.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/core": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.943.0.tgz", + "integrity": "sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.943.0.tgz", + "integrity": "sha512-WnS5w9fK9CTuoZRVSIHLOMcI63oODg9qd1vXMYb7QGLGlfwUm4aG3hdu7i9XvYrpkQfE3dzwWLtXF4ZBuL1Tew==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.943.0.tgz", + "integrity": "sha512-SA8bUcYDEACdhnhLpZNnWusBpdmj4Vl67Vxp3Zke7SvoWSYbuxa+tiDiC+c92Z4Yq6xNOuLPW912ZPb9/NsSkA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-stream": "^4.5.6", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.943.0.tgz", + "integrity": "sha512-BcLDb8l4oVW+NkuqXMlO7TnM6lBOWW318ylf4FRED/ply5eaGxkQYqdGvHSqGSN5Rb3vr5Ek0xpzSjeYD7C8Kw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/credential-provider-env": "3.943.0", + "@aws-sdk/credential-provider-http": "3.943.0", + "@aws-sdk/credential-provider-login": "3.943.0", + "@aws-sdk/credential-provider-process": "3.943.0", + "@aws-sdk/credential-provider-sso": "3.943.0", + "@aws-sdk/credential-provider-web-identity": "3.943.0", + "@aws-sdk/nested-clients": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-login": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.943.0.tgz", + "integrity": "sha512-9iCOVkiRW+evxiJE94RqosCwRrzptAVPhRhGWv4osfYDhjNAvUMyrnZl3T1bjqCoKNcETRKEZIU3dqYHnUkcwQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/nested-clients": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.943.0.tgz", + "integrity": "sha512-14eddaH/gjCWoLSAELVrFOQNyswUYwWphIt+PdsJ/FqVfP4ay2HsiZVEIYbQtmrKHaoLJhiZKwBQRjcqJDZG0w==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "3.943.0", + "@aws-sdk/credential-provider-http": "3.943.0", + "@aws-sdk/credential-provider-ini": "3.943.0", + "@aws-sdk/credential-provider-process": "3.943.0", + "@aws-sdk/credential-provider-sso": "3.943.0", + "@aws-sdk/credential-provider-web-identity": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/credential-provider-imds": "^4.2.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.943.0.tgz", + "integrity": "sha512-GIY/vUkthL33AdjOJ8r9vOosKf/3X+X7LIiACzGxvZZrtoOiRq0LADppdiKIB48vTL63VvW+eRIOFAxE6UDekw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.943.0.tgz", + "integrity": "sha512-1c5G11syUrru3D9OO6Uk+ul5e2lX1adb+7zQNyluNaLPXP6Dina6Sy6DFGRLu7tM8+M7luYmbS3w63rpYpaL+A==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/client-sso": "3.943.0", + "@aws-sdk/core": "3.943.0", + "@aws-sdk/token-providers": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.943.0.tgz", + "integrity": "sha512-VtyGKHxICSb4kKGuaqotxso8JVM8RjCS3UYdIMOxUt9TaFE/CZIfZKtjTr+IJ7M0P7t36wuSUb/jRLyNmGzUUA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/nested-clients": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.943.0.tgz", + "integrity": "sha512-956n4kVEwFNXndXfhSAN5wO+KRgqiWEEY+ECwLvxmmO8uQ0NWOa8l6l65nTtyuiWzMX81c9BvlyNR5EgUeeUvA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@smithy/core": "^3.18.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/nested-clients": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.943.0.tgz", + "integrity": "sha512-anFtB0p2FPuyUnbOULwGmKYqYKSq1M73c9uZ08jR/NCq6Trjq9cuF5TFTeHwjJyPRb4wMf2Qk859oiVfFqnQiw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.943.0", + "@aws-sdk/middleware-host-header": "3.936.0", + "@aws-sdk/middleware-logger": "3.936.0", + "@aws-sdk/middleware-recursion-detection": "3.936.0", + "@aws-sdk/middleware-user-agent": "3.943.0", + "@aws-sdk/region-config-resolver": "3.936.0", + "@aws-sdk/types": "3.936.0", + "@aws-sdk/util-endpoints": "3.936.0", + "@aws-sdk/util-user-agent-browser": "3.936.0", + "@aws-sdk/util-user-agent-node": "3.943.0", + "@smithy/config-resolver": "^4.4.3", + "@smithy/core": "^3.18.5", + "@smithy/fetch-http-handler": "^5.3.6", + "@smithy/hash-node": "^4.2.5", + "@smithy/invalid-dependency": "^4.2.5", + "@smithy/middleware-content-length": "^4.2.5", + "@smithy/middleware-endpoint": "^4.3.12", + "@smithy/middleware-retry": "^4.4.12", + "@smithy/middleware-serde": "^4.2.6", + "@smithy/middleware-stack": "^4.2.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/node-http-handler": "^4.4.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/url-parser": "^4.2.5", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.11", + "@smithy/util-defaults-mode-node": "^4.2.14", + "@smithy/util-endpoints": "^3.2.5", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-retry": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/token-providers": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.943.0.tgz", + "integrity": "sha512-cRKyIzwfkS+XztXIFPoWORuaxlIswP+a83BJzelX4S1gUZ7FcXB4+lj9Jxjn8SbQhR4TPU3Owbpu+S7pd6IRbQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@aws-sdk/nested-clients": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/property-provider": "^4.2.5", + "@smithy/shared-ini-file-loader": "^4.4.0", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.943.0.tgz", + "integrity": "sha512-gn+ILprVRrgAgTIBk2TDsJLRClzIOdStQFeFTcN0qpL8Z4GBCqMFhw7O7X+MM55Stt5s4jAauQ/VvoqmCADnQg==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.943.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, "lambdas/mi-updates-transformer/node_modules/@aws-sdk/client-sns": { "version": "3.940.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sns/-/client-sns-3.940.0.tgz", @@ -3333,6 +3742,70 @@ "node": ">=18.0.0" } }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/dynamodb-codec": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.943.0.tgz", + "integrity": "sha512-dGUjOPWt+35r0vTcb19bFluumf3XprdjzkA1Qa+va1mEiBuGi9lHZJSI9E2JX2wt/qUtlPeW1kjlEaHZk0nYcA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/core": "3.943.0", + "@smithy/core": "^3.18.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.943.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/dynamodb-codec/node_modules/@aws-sdk/core": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.943.0.tgz", + "integrity": "sha512-8CBy2hI9ABF7RBVQuY1bgf/ue+WPmM/hl0adrXFlhnhkaQP0tFY5zhiy1Y+n7V+5f3/ORoHBmCCQmcHDDYJqJQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/types": "3.936.0", + "@aws-sdk/xml-builder": "3.930.0", + "@smithy/core": "^3.18.5", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/property-provider": "^4.2.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/signature-v4": "^5.3.5", + "@smithy/smithy-client": "^4.9.8", + "@smithy/types": "^4.9.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.5", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-endpoint-discovery": { + "version": "3.936.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.936.0.tgz", + "integrity": "sha512-wNJZ8PDw0eQK2x4z1q8JqiDvw9l9xd36EoklVT2CIBt8FnqGdrMGjAx93RRbH3G6Fmvwoe+D3VJXbWHBlhD0Bw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@aws-sdk/endpoint-cache": "3.893.0", + "@aws-sdk/types": "3.936.0", + "@smithy/node-config-provider": "^4.3.5", + "@smithy/protocol-http": "^5.3.5", + "@smithy/types": "^4.9.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "lambdas/mi-updates-transformer/node_modules/@aws-sdk/middleware-host-header": { "version": "3.936.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz", @@ -3492,6 +3965,21 @@ "node": ">=18.0.0" } }, + "lambdas/mi-updates-transformer/node_modules/@aws-sdk/util-dynamodb": { + "version": "3.943.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.943.0.tgz", + "integrity": "sha512-F2qVauKYoTleiv/Kv423P7zin93sSuwRkIKUKh+dR4oP7P9EP43/I3NHHeA3AlifIFGZG9jzuHi4MvhF4yC2yg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.943.0" + } + }, "lambdas/mi-updates-transformer/node_modules/@aws-sdk/util-endpoints": { "version": "3.936.0", "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz", From b46838b4b25291bf40547918b17ffeda03fca8cf Mon Sep 17 00:00:00 2001 From: David Wass Date: Thu, 4 Dec 2025 14:56:50 +0000 Subject: [PATCH 20/21] Fix default export in index.ts --- lambdas/mi-updates-transformer/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lambdas/mi-updates-transformer/src/index.ts b/lambdas/mi-updates-transformer/src/index.ts index f7c8a4df..6544d924 100644 --- a/lambdas/mi-updates-transformer/src/index.ts +++ b/lambdas/mi-updates-transformer/src/index.ts @@ -3,4 +3,5 @@ import { createDependenciesContainer } from "./deps"; const container = createDependenciesContainer(); +// eslint-disable-next-line import-x/prefer-default-export export const handler = createHandler(container); From 9fcbc8eef12241b260acb011871446c178a9244c Mon Sep 17 00:00:00 2001 From: David Wass Date: Tue, 16 Dec 2025 08:35:40 +0000 Subject: [PATCH 21/21] rebase fix --- .../terraform/components/api/ddb_table_letters.tf | 2 -- infrastructure/terraform/components/api/ddb_table_mi.tf | 2 -- .../components/api/module_lambda_mi_updates_transformer.tf | 2 +- internal/events/src/events/letter-events.ts | 6 +++--- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/infrastructure/terraform/components/api/ddb_table_letters.tf b/infrastructure/terraform/components/api/ddb_table_letters.tf index 04d2606e..6a3c3e48 100644 --- a/infrastructure/terraform/components/api/ddb_table_letters.tf +++ b/infrastructure/terraform/components/api/ddb_table_letters.tf @@ -1,8 +1,6 @@ resource "aws_dynamodb_table" "letters" { name = "${local.csi}-letters" billing_mode = "PAY_PER_REQUEST" - stream_enabled = true - stream_view_type = "NEW_AND_OLD_IMAGES" hash_key = "supplierId" range_key = "id" diff --git a/infrastructure/terraform/components/api/ddb_table_mi.tf b/infrastructure/terraform/components/api/ddb_table_mi.tf index 7fdffb64..712cd85d 100644 --- a/infrastructure/terraform/components/api/ddb_table_mi.tf +++ b/infrastructure/terraform/components/api/ddb_table_mi.tf @@ -1,8 +1,6 @@ resource "aws_dynamodb_table" "mi" { name = "${local.csi}-mi" billing_mode = "PAY_PER_REQUEST" - stream_enabled = true - stream_view_type = "NEW_IMAGE" hash_key = "supplierId" range_key = "id" diff --git a/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf b/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf index 4a63ba51..48f0acbe 100644 --- a/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf +++ b/infrastructure/terraform/components/api/module_lambda_mi_updates_transformer.tf @@ -25,7 +25,7 @@ module "mi_updates_transformer" { handler_function_name = "handler" runtime = "nodejs22.x" memory = 128 - timeout = 5 + timeout = 29 log_level = var.log_level force_lambda_code_deploy = var.force_lambda_code_deploy diff --git a/internal/events/src/events/letter-events.ts b/internal/events/src/events/letter-events.ts index ea4960d5..49795068 100644 --- a/internal/events/src/events/letter-events.ts +++ b/internal/events/src/events/letter-events.ts @@ -13,7 +13,7 @@ export const $LetterEvent = EventEnvelope( "letter", "letter", $Letter, - $LetterStatus.options.map((status) => status.toLowerCase()), + $LetterStatus.options, "letter-origin", ).meta({ title: `letter.* Event`, @@ -27,13 +27,13 @@ export type LetterEvent = z.infer; */ const eventSchema = (status: LetterStatus) => EventEnvelope( - `letter.${status.toLowerCase()}`, + `letter.${status}`, "letter", $Letter, [status], "letter-origin", ).meta({ - title: `letter.${status.toLowerCase()} Event`, + title: `letter.${status} Event`, description: `Event schema for letter status change to ${status}`, });