diff --git a/.vscode/eps-prescription-status-update-api.code-workspace b/.vscode/eps-prescription-status-update-api.code-workspace index d647e1ccf..80845c46a 100644 --- a/.vscode/eps-prescription-status-update-api.code-workspace +++ b/.vscode/eps-prescription-status-update-api.code-workspace @@ -12,6 +12,10 @@ "name": "packages/updatePrescriptionStatus", "path": "../packages/updatePrescriptionStatus" }, + { + "name": "packages/gsul", + "path": "../packages/gsul" + }, { "name": "packages/sandbox", "path": "../packages/sandbox" diff --git a/Makefile b/Makefile index 6a2a525db..309488db4 100644 --- a/Makefile +++ b/Makefile @@ -99,6 +99,7 @@ compile: compile-node lint-node: compile-node npm run lint --workspace packages/specification npm run lint --workspace packages/updatePrescriptionStatus + npm run lint --workspace packages/gsul npm run lint --workspace packages/sandbox lint-samtemplates: @@ -117,6 +118,7 @@ lint: lint-node lint-samtemplates lint-python lint-githubactions lint-githubacti test: compile npm run test --workspace packages/updatePrescriptionStatus + npm run test --workspace packages/gsul npm run test --workspace packages/sandbox npm run test --workspace packages/specification diff --git a/SAMtemplates/functions/main.yaml b/SAMtemplates/functions/main.yaml index 1e9df35d0..5cefcbea6 100644 --- a/SAMtemplates/functions/main.yaml +++ b/SAMtemplates/functions/main.yaml @@ -1,4 +1,4 @@ -AWSTemplateFormatVersion: '2010-09-09' +AWSTemplateFormatVersion: "2010-09-09" Transform: AWS::Serverless-2016-10-31 Description: | PSU lambda functions and related resources @@ -12,7 +12,7 @@ Globals: Runtime: nodejs20.x Environment: Variables: - NODE_OPTIONS: '--enable-source-maps' + NODE_OPTIONS: "--enable-source-maps" Layers: - !Sub arn:aws:lambda:${AWS::Region}:580247275435:layer:LambdaInsightsExtension:49 @@ -20,17 +20,17 @@ Parameters: StackName: Type: String Default: none - + PrescriptionStatusUpdatesTableName: Type: String Default: none - + LogLevel: Type: String - + LogRetentionInDays: Type: Number - + EnableSplunk: Type: String @@ -55,7 +55,7 @@ Resources: tsconfig: updatePrescriptionStatus/tsconfig.json EntryPoints: - updatePrescriptionStatus/src/updatePrescriptionStatus.ts - + UpdatePrescriptionStatusResources: Type: AWS::Serverless::Application Properties: @@ -66,7 +66,7 @@ Resources: LambdaArn: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${StackName}-UpdatePrescriptionStatus IncludeAdditionalPolicies: true AdditionalPolicies: !Join - - ',' + - "," - - Fn::ImportValue: !Sub ${StackName}:tables:${PrescriptionStatusUpdatesTableName}:TableWritePolicyArn LogRetentionInDays: !Ref LogRetentionInDays CloudWatchKMSKeyId: !ImportValue account-resources:CloudwatchLogsKmsKeyArn @@ -74,6 +74,45 @@ Resources: SplunkSubscriptionFilterRole: !ImportValue lambda-resources:SplunkSubscriptionFilterRole SplunkDeliveryStreamArn: !ImportValue lambda-resources:SplunkDeliveryStream + GetStatusUpdates: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub ${StackName}-GetStatusUpdates + CodeUri: ../../packages + Handler: getStatusUpdates.handler + Role: !GetAtt GetStatusUpdatesResources.Outputs.LambdaRoleArn + Environment: + Variables: + TABLE_NAME: !Ref PrescriptionStatusUpdatesTableName + LOG_LEVEL: !Ref LogLevel + Metadata: + BuildMethod: esbuild + BuildProperties: + Minify: true + Target: es2020 + Sourcemap: true + tsconfig: gsul/tsconfig.json + EntryPoints: + - gsul/src/getStatusUpdates.ts + + GetStatusUpdatesResources: + Type: AWS::Serverless::Application + Properties: + Location: lambda_resources.yaml + Parameters: + StackName: !Ref StackName + LambdaName: !Sub ${StackName}-GetStatusUpdates + LambdaArn: !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${StackName}-GetStatusUpdates + IncludeAdditionalPolicies: true + AdditionalPolicies: !Join + - "," + - - Fn::ImportValue: !Sub ${StackName}:tables:${PrescriptionStatusUpdatesTableName}:TableReadPolicyArn + LogRetentionInDays: !Ref LogRetentionInDays + CloudWatchKMSKeyId: !ImportValue account-resources:CloudwatchLogsKmsKeyArn + EnableSplunk: !Ref EnableSplunk + SplunkSubscriptionFilterRole: !ImportValue lambda-resources:SplunkSubscriptionFilterRole + SplunkDeliveryStreamArn: !ImportValue lambda-resources:SplunkDeliveryStream + Outputs: UpdatePrescriptionStatusFunctionName: Description: The function name of the UpdatePrescriptionStatus lambda @@ -81,4 +120,14 @@ Outputs: UpdatePrescriptionStatusFunctionArn: Description: The function ARN of the UpdatePrescriptionStatus lambda - Value: !GetAtt UpdatePrescriptionStatus.Arn + Value: !GetAtt UpdatePrescriptionStatus.Arn + + GetStatusUpdatesFunctionName: + Description: The function name of the GetStatusUpdates lambda + Value: !Ref GetStatusUpdates + + GetStatusUpdatesFunctionArn: + Description: The function ARN of the GetStatusUpdates lambda + Value: !GetAtt GetStatusUpdates.Arn + Export: + Name: !Sub ${StackName}:functions:GetStatusUpdates:FunctionArn diff --git a/package-lock.json b/package-lock.json index 207a9acfc..d53d2bf5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "workspaces": [ "packages/specification", "packages/updatePrescriptionStatus", + "packages/gsul", "packages/sandbox" ], "dependencies": { @@ -34,6 +35,7 @@ "jest-junit": "^16.0.0", "license-checker": "^25.0.1", "prettier": "^3.2.5", + "prettier-eslint": "^16.3.0", "semantic-release": "^23.0.8", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", @@ -244,21 +246,18 @@ }, "node_modules/@aws-crypto/ie11-detection": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", - "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "license": "Apache-2.0", "dependencies": { "tslib": "^1.11.1" } }, "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-crypto/sha256-browser": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", - "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/ie11-detection": "^3.0.0", "@aws-crypto/sha256-js": "^3.0.0", @@ -272,13 +271,11 @@ }, "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-crypto/sha256-js": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", - "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/util": "^3.0.0", "@aws-sdk/types": "^3.222.0", @@ -287,26 +284,22 @@ }, "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-crypto/supports-web-crypto": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", - "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^1.11.1" } }, "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-crypto/util": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", - "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "^3.222.0", "@aws-sdk/util-utf8-browser": "^3.0.0", @@ -315,18 +308,15 @@ }, "node_modules/@aws-crypto/util/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "license": "0BSD" }, "node_modules/@aws-lambda-powertools/commons": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/commons/-/commons-2.1.0.tgz", - "integrity": "sha512-pFIlGa2IreeQ8elvuWlqxp6q/R4Zx7EqzCAlj0yXg12XpQprF4BhuE3NpeF09MA/QkyCot5Hxu3kG95E35XETA==" + "license": "MIT-0" }, "node_modules/@aws-lambda-powertools/logger": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@aws-lambda-powertools/logger/-/logger-2.1.0.tgz", - "integrity": "sha512-vsxB2ESJYm4hXCC3rrClzjBXNdGJI1qr6wQATuvS6Is0UcbqWbN7N3lnA4hYSknDmh+HKxAn9E4bcelMmuSBew==", + "license": "MIT-0", "dependencies": { "@aws-lambda-powertools/commons": "^2.1.0", "lodash.merge": "^4.6.2" @@ -342,8 +332,7 @@ }, "node_modules/@aws-sdk/client-dynamodb": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.556.0.tgz", - "integrity": "sha512-Msb/LxTbboX/v5HlR5zcMJ9JI61X83yI6pqsL85CcFrEuzAi+QqSmt84sT9sYU263RKkmo8Py4WazM7uIGs+mw==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -406,8 +395,7 @@ }, "node_modules/@aws-sdk/client-sso": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.556.0.tgz", - "integrity": "sha512-unXdWS7uvHqCcOyC1de+Fr8m3F2vMg2m24GPea0bg7rVGTYmiyn9mhUX11VCt+ozydrw+F50FQwL6OqoqPocmw==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -454,8 +442,7 @@ }, "node_modules/@aws-sdk/client-sso-oidc": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.556.0.tgz", - "integrity": "sha512-AXKd2TB6nNrksu+OfmHl8uI07PdgzOo4o8AxoRO8SHlwoMAGvcT9optDGVSYoVfgOKTymCoE7h8/UoUfPc11wQ==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -506,8 +493,7 @@ }, "node_modules/@aws-sdk/client-sts": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.556.0.tgz", - "integrity": "sha512-TsK3js7Suh9xEmC886aY+bv0KdLLYtzrcmVt6sJ/W6EnDXYQhBuKYFhp03NrN2+vSvMGpqJwR62DyfKe1G0QzQ==", + "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "3.0.0", "@aws-crypto/sha256-js": "3.0.0", @@ -557,8 +543,7 @@ }, "node_modules/@aws-sdk/core": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.556.0.tgz", - "integrity": "sha512-vJaSaHw2kPQlo11j/Rzuz0gk1tEaKdz+2ser0f0qZ5vwFlANjt08m/frU17ctnVKC1s58bxpctO/1P894fHLrA==", + "license": "Apache-2.0", "dependencies": { "@smithy/core": "^1.4.2", "@smithy/protocol-http": "^3.3.0", @@ -574,8 +559,7 @@ }, "node_modules/@aws-sdk/credential-provider-env": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.535.0.tgz", - "integrity": "sha512-XppwO8c0GCGSAvdzyJOhbtktSEaShg14VJKg8mpMa1XcgqzmcqqHQjtDWbx5rZheY1VdpXZhpEzJkB6LpQejpA==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/property-provider": "^2.2.0", @@ -588,8 +572,7 @@ }, "node_modules/@aws-sdk/credential-provider-http": { "version": "3.552.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.552.0.tgz", - "integrity": "sha512-vsmu7Cz1i45pFEqzVb4JcFmAmVnWFNLsGheZc8SCptlqCO5voETrZZILHYIl4cjKkSDk3pblBOf0PhyjqWW6WQ==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/fetch-http-handler": "^2.5.0", @@ -607,8 +590,7 @@ }, "node_modules/@aws-sdk/credential-provider-ini": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.556.0.tgz", - "integrity": "sha512-0Nz4ErOlXhe3muxWYMbPwRMgfKmVbBp36BAE2uv/z5wTbfdBkcgUwaflEvlKCLUTdHzuZsQk+BFS/gVyaUeOuA==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sts": "3.556.0", "@aws-sdk/credential-provider-env": "3.535.0", @@ -628,8 +610,7 @@ }, "node_modules/@aws-sdk/credential-provider-node": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.556.0.tgz", - "integrity": "sha512-s1xVtKjyGc60O8qcNIzS1X3H+pWEwEfZ7TgNznVDNyuXvLrlNWiAcigPWGl2aAkc8tGcsSG0Qpyw2KYC939LFg==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/credential-provider-env": "3.535.0", "@aws-sdk/credential-provider-http": "3.552.0", @@ -650,8 +631,7 @@ }, "node_modules/@aws-sdk/credential-provider-process": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.535.0.tgz", - "integrity": "sha512-9O1OaprGCnlb/kYl8RwmH7Mlg8JREZctB8r9sa1KhSsWFq/SWO0AuJTyowxD7zL5PkeS4eTvzFFHWCa3OO5epA==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/property-provider": "^2.2.0", @@ -665,8 +645,7 @@ }, "node_modules/@aws-sdk/credential-provider-sso": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.556.0.tgz", - "integrity": "sha512-ETuBgcnpfxqadEAqhQFWpKoV1C/NAgvs5CbBc5EJbelJ8f4prTdErIHjrRtVT8c02MXj92QwczsiNYd5IoOqyw==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sso": "3.556.0", "@aws-sdk/token-providers": "3.556.0", @@ -682,8 +661,7 @@ }, "node_modules/@aws-sdk/credential-provider-web-identity": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.556.0.tgz", - "integrity": "sha512-R/YAL8Uh8i+dzVjzMnbcWLIGeeRi2mioHVGnVF+minmaIkCiQMZg2HPrdlKm49El+RljT28Nl5YHRuiqzEIwMA==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sts": "3.556.0", "@aws-sdk/types": "3.535.0", @@ -706,6 +684,22 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/lib-dynamodb": { + "version": "3.556.0", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/util-dynamodb": "3.556.0", + "@smithy/smithy-client": "^2.5.1", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-dynamodb": "^3.0.0" + } + }, "node_modules/@aws-sdk/middleware-endpoint-discovery": { "version": "3.535.0", "license": "Apache-2.0", @@ -723,8 +717,7 @@ }, "node_modules/@aws-sdk/middleware-host-header": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.535.0.tgz", - "integrity": "sha512-0h6TWjBWtDaYwHMQJI9ulafeS4lLaw1vIxRjbpH0svFRt6Eve+Sy8NlVhECfTU2hNz/fLubvrUxsXoThaLBIew==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/protocol-http": "^3.3.0", @@ -737,8 +730,7 @@ }, "node_modules/@aws-sdk/middleware-logger": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.535.0.tgz", - "integrity": "sha512-huNHpONOrEDrdRTvSQr1cJiRMNf0S52NDXtaPzdxiubTkP+vni2MohmZANMOai/qT0olmEVX01LhZ0ZAOgmg6A==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/types": "^2.12.0", @@ -750,8 +742,7 @@ }, "node_modules/@aws-sdk/middleware-recursion-detection": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.535.0.tgz", - "integrity": "sha512-am2qgGs+gwqmR4wHLWpzlZ8PWhm4ktj5bYSgDrsOfjhdBlWNxvPoID9/pDAz5RWL48+oH7I6SQzMqxXsFDikrw==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/protocol-http": "^3.3.0", @@ -764,8 +755,7 @@ }, "node_modules/@aws-sdk/middleware-user-agent": { "version": "3.540.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.540.0.tgz", - "integrity": "sha512-8Rd6wPeXDnOYzWj1XCmOKcx/Q87L0K1/EHqOBocGjLVbN3gmRxBvpmR1pRTjf7IsWfnnzN5btqtcAkfDPYQUMQ==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@aws-sdk/util-endpoints": "3.540.0", @@ -779,8 +769,7 @@ }, "node_modules/@aws-sdk/region-config-resolver": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.535.0.tgz", - "integrity": "sha512-IXOznDiaItBjsQy4Fil0kzX/J3HxIOknEphqHbOfUf+LpA5ugcsxuQQONrbEQusCBnfJyymrldBvBhFmtlU9Wg==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/node-config-provider": "^2.3.0", @@ -795,8 +784,7 @@ }, "node_modules/@aws-sdk/token-providers": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.556.0.tgz", - "integrity": "sha512-tvIiugNF0/+2wfuImMrpKjXMx4nCnFWQjQvouObny+wrif/PGqqQYrybwxPJDvzbd965bu1I+QuSv85/ug7xsg==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/client-sso-oidc": "3.556.0", "@aws-sdk/types": "3.535.0", @@ -822,8 +810,7 @@ }, "node_modules/@aws-sdk/util-dynamodb": { "version": "3.556.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-dynamodb/-/util-dynamodb-3.556.0.tgz", - "integrity": "sha512-SF7bEPt8uCiklHkCvDQfGmAl6qADDd/sHHjcWS0zGYPesLkKSJDo/uKUjwuLxzkpHEp+xvB8BYrHFMIefb28AQ==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -836,8 +823,7 @@ }, "node_modules/@aws-sdk/util-endpoints": { "version": "3.540.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.540.0.tgz", - "integrity": "sha512-1kMyQFAWx6f8alaI6UT65/5YW/7pDWAKAdNwL6vuJLea03KrZRX3PMoONOSJpAS5m3Ot7HlWZvf3wZDNTLELZw==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/types": "^2.12.0", @@ -850,8 +836,7 @@ }, "node_modules/@aws-sdk/util-locate-window": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.535.0.tgz", - "integrity": "sha512-PHJ3SL6d2jpcgbqdgiPxkXpu7Drc2PYViwxSIqvvMKhDwzSB1W3mMvtpzwKM4IE7zLFodZo0GKjJ9AsoXndXhA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -861,8 +846,7 @@ }, "node_modules/@aws-sdk/util-user-agent-browser": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.535.0.tgz", - "integrity": "sha512-RWMcF/xV5n+nhaA/Ff5P3yNP3Kur/I+VNZngog4TEs92oB/nwOdAg/2JL8bVAhUbMrjTjpwm7PItziYFQoqyig==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/types": "^2.12.0", @@ -872,8 +856,7 @@ }, "node_modules/@aws-sdk/util-user-agent-node": { "version": "3.535.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.535.0.tgz", - "integrity": "sha512-dRek0zUuIT25wOWJlsRm97nTkUlh1NDcLsQZIN2Y8KxhwoXXWtJs5vaDPT+qAg+OpcNj80i1zLR/CirqlFg/TQ==", + "license": "Apache-2.0", "dependencies": { "@aws-sdk/types": "3.535.0", "@smithy/node-config-provider": "^2.3.0", @@ -894,8 +877,7 @@ }, "node_modules/@aws-sdk/util-utf8-browser": { "version": "3.259.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", - "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.3.1" } @@ -1436,6 +1418,16 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.24.4", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.24.0", "dev": true, @@ -1638,8 +1630,6 @@ }, "node_modules/@faker-js/faker": { "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", - "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==", "dev": true, "funding": [ { @@ -1647,11 +1637,20 @@ "url": "https://opencollective.com/fakerjs" } ], + "license": "MIT", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0", "npm": ">=6.14.13" } }, + "node_modules/@fluent/syntax": { + "version": "0.18.1", + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0", + "npm": ">=7.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "dev": true, @@ -2117,10 +2116,76 @@ "url": "https://github.com/sponsors/willfarrell" } }, + "node_modules/@middy/util": { + "version": "5.3.2", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/willfarrell" + } + }, + "node_modules/@middy/validator": { + "version": "5.3.2", + "license": "MIT", + "dependencies": { + "@middy/util": "5.3.2", + "ajv": "8.12.0", + "ajv-errors": "3.0.0", + "ajv-formats": "2.1.1", + "ajv-formats-draft2019": "1.6.1", + "ajv-ftl-i18n": "0.1.1", + "ajv-keywords": "5.1.0", + "fast-uri": "2.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/willfarrell" + } + }, + "node_modules/@middy/validator/node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@middy/validator/node_modules/ajv-errors": { + "version": "3.0.0", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.0.1" + } + }, + "node_modules/@middy/validator/node_modules/ajv-keywords": { + "version": "5.1.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/@middy/validator/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, "node_modules/@nhs/fhir-middy-error-handler": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@nhs/fhir-middy-error-handler/-/fhir-middy-error-handler-2.0.2.tgz", - "integrity": "sha512-gEr1GBeTRhEs6dd9U59OfHFS7B7wH+6EON+BEH7f//2H7wabHOE6O7FaSaK2OkzptIg6EfHnxcySrFfxujlFag==", + "license": "MIT", "dependencies": { "@aws-lambda-powertools/logger": "^2.0.4", "@middy/core": "^5.3.2" @@ -2358,9 +2423,8 @@ }, "node_modules/@semantic-release/commit-analyzer": { "version": "12.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-12.0.0.tgz", - "integrity": "sha512-qG+md5gdes+xa8zP7lIo1fWE17zRdO8yMCaxh9lyL65TQleoSv8WHHOqRURfghTytUh+NpkSyBprQ5hrkxOKVQ==", "dev": true, + "license": "MIT", "dependencies": { "conventional-changelog-angular": "^7.0.0", "conventional-commits-filter": "^4.0.0", @@ -2725,9 +2789,8 @@ }, "node_modules/@semantic-release/release-notes-generator": { "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-13.0.0.tgz", - "integrity": "sha512-LEeZWb340keMYuREMyxrODPXJJ0JOL8D/mCl74B4LdzbxhtXV2LrPN2QBEcGJrlQhoqLO0RhxQb6masHytKw+A==", "dev": true, + "license": "MIT", "dependencies": { "conventional-changelog-angular": "^7.0.0", "conventional-changelog-writer": "^7.0.0", @@ -2837,8 +2900,7 @@ }, "node_modules/@smithy/config-resolver": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.2.0.tgz", - "integrity": "sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==", + "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^2.3.0", "@smithy/types": "^2.12.0", @@ -2852,8 +2914,7 @@ }, "node_modules/@smithy/core": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-1.4.2.tgz", - "integrity": "sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==", + "license": "Apache-2.0", "dependencies": { "@smithy/middleware-endpoint": "^2.5.1", "@smithy/middleware-retry": "^2.3.1", @@ -2870,8 +2931,7 @@ }, "node_modules/@smithy/credential-provider-imds": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.3.0.tgz", - "integrity": "sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==", + "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^2.3.0", "@smithy/property-provider": "^2.2.0", @@ -2885,8 +2945,7 @@ }, "node_modules/@smithy/fetch-http-handler": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.5.0.tgz", - "integrity": "sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==", + "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^3.3.0", "@smithy/querystring-builder": "^2.2.0", @@ -2897,8 +2956,7 @@ }, "node_modules/@smithy/hash-node": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.2.0.tgz", - "integrity": "sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "@smithy/util-buffer-from": "^2.2.0", @@ -2911,8 +2969,7 @@ }, "node_modules/@smithy/invalid-dependency": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.2.0.tgz", - "integrity": "sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" @@ -2920,8 +2977,7 @@ }, "node_modules/@smithy/is-array-buffer": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -2931,8 +2987,7 @@ }, "node_modules/@smithy/middleware-content-length": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.2.0.tgz", - "integrity": "sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==", + "license": "Apache-2.0", "dependencies": { "@smithy/protocol-http": "^3.3.0", "@smithy/types": "^2.12.0", @@ -2944,8 +2999,7 @@ }, "node_modules/@smithy/middleware-endpoint": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.5.1.tgz", - "integrity": "sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==", + "license": "Apache-2.0", "dependencies": { "@smithy/middleware-serde": "^2.3.0", "@smithy/node-config-provider": "^2.3.0", @@ -2961,8 +3015,7 @@ }, "node_modules/@smithy/middleware-retry": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.3.1.tgz", - "integrity": "sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==", + "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^2.3.0", "@smithy/protocol-http": "^3.3.0", @@ -2980,20 +3033,18 @@ }, "node_modules/@smithy/middleware-retry/node_modules/uuid": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/@smithy/middleware-serde": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.3.0.tgz", - "integrity": "sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" @@ -3004,8 +3055,7 @@ }, "node_modules/@smithy/middleware-stack": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.2.0.tgz", - "integrity": "sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" @@ -3029,8 +3079,7 @@ }, "node_modules/@smithy/node-http-handler": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", + "license": "Apache-2.0", "dependencies": { "@smithy/abort-controller": "^2.2.0", "@smithy/protocol-http": "^3.3.0", @@ -3066,8 +3115,7 @@ }, "node_modules/@smithy/querystring-builder": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "@smithy/util-uri-escape": "^2.2.0", @@ -3079,8 +3127,7 @@ }, "node_modules/@smithy/querystring-parser": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.2.0.tgz", - "integrity": "sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" @@ -3091,8 +3138,7 @@ }, "node_modules/@smithy/service-error-classification": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.1.5.tgz", - "integrity": "sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0" }, @@ -3113,8 +3159,7 @@ }, "node_modules/@smithy/signature-v4": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.3.0.tgz", - "integrity": "sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==", + "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "@smithy/types": "^2.12.0", @@ -3130,8 +3175,7 @@ }, "node_modules/@smithy/smithy-client": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.5.1.tgz", - "integrity": "sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==", + "license": "Apache-2.0", "dependencies": { "@smithy/middleware-endpoint": "^2.5.1", "@smithy/middleware-stack": "^2.2.0", @@ -3156,8 +3200,7 @@ }, "node_modules/@smithy/url-parser": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.2.0.tgz", - "integrity": "sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==", + "license": "Apache-2.0", "dependencies": { "@smithy/querystring-parser": "^2.2.0", "@smithy/types": "^2.12.0", @@ -3166,8 +3209,7 @@ }, "node_modules/@smithy/util-base64": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.3.0.tgz", - "integrity": "sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==", + "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "@smithy/util-utf8": "^2.3.0", @@ -3179,16 +3221,14 @@ }, "node_modules/@smithy/util-body-length-browser": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.2.0.tgz", - "integrity": "sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" } }, "node_modules/@smithy/util-body-length-node": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.3.0.tgz", - "integrity": "sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -3198,8 +3238,7 @@ }, "node_modules/@smithy/util-buffer-from": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "license": "Apache-2.0", "dependencies": { "@smithy/is-array-buffer": "^2.2.0", "tslib": "^2.6.2" @@ -3210,8 +3249,7 @@ }, "node_modules/@smithy/util-config-provider": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.3.0.tgz", - "integrity": "sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -3221,8 +3259,7 @@ }, "node_modules/@smithy/util-defaults-mode-browser": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.2.1.tgz", - "integrity": "sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==", + "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^2.2.0", "@smithy/smithy-client": "^2.5.1", @@ -3236,8 +3273,7 @@ }, "node_modules/@smithy/util-defaults-mode-node": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.3.1.tgz", - "integrity": "sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==", + "license": "Apache-2.0", "dependencies": { "@smithy/config-resolver": "^2.2.0", "@smithy/credential-provider-imds": "^2.3.0", @@ -3253,8 +3289,7 @@ }, "node_modules/@smithy/util-endpoints": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-1.2.0.tgz", - "integrity": "sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==", + "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^2.3.0", "@smithy/types": "^2.12.0", @@ -3266,8 +3301,7 @@ }, "node_modules/@smithy/util-hex-encoding": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.2.0.tgz", - "integrity": "sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -3277,8 +3311,7 @@ }, "node_modules/@smithy/util-middleware": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.2.0.tgz", - "integrity": "sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==", + "license": "Apache-2.0", "dependencies": { "@smithy/types": "^2.12.0", "tslib": "^2.6.2" @@ -3289,8 +3322,7 @@ }, "node_modules/@smithy/util-retry": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.2.0.tgz", - "integrity": "sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==", + "license": "Apache-2.0", "dependencies": { "@smithy/service-error-classification": "^2.1.5", "@smithy/types": "^2.12.0", @@ -3302,8 +3334,7 @@ }, "node_modules/@smithy/util-stream": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.2.0.tgz", - "integrity": "sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==", + "license": "Apache-2.0", "dependencies": { "@smithy/fetch-http-handler": "^2.5.0", "@smithy/node-http-handler": "^2.5.0", @@ -3320,8 +3351,7 @@ }, "node_modules/@smithy/util-uri-escape": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.2.0.tgz", - "integrity": "sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.6.2" }, @@ -3331,8 +3361,7 @@ }, "node_modules/@smithy/util-utf8": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "license": "Apache-2.0", "dependencies": { "@smithy/util-buffer-from": "^2.2.0", "tslib": "^2.6.2" @@ -3375,9 +3404,8 @@ }, "node_modules/@types/aws-lambda": { "version": "8.10.137", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.137.tgz", - "integrity": "sha512-YNFwzVarXAOXkjuFxONyDw1vgRNzyH8AuyN19s0bM+ChSu/bzxb5XPxYFLXoqoM+tvgzwR3k7fXcEOW125yJxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -3418,9 +3446,8 @@ }, "node_modules/@types/fhir": { "version": "0.0.41", - "resolved": "https://registry.npmjs.org/@types/fhir/-/fhir-0.0.41.tgz", - "integrity": "sha512-MAQAFufNZBZ6V0F94Nhknmmh/E3iMXFK4n/L8RkSNjKtOJnvaAJERivNOj35VVx9VCQBJbE0BHSzikfBahoRhA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -3462,15 +3489,13 @@ }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { "version": "20.12.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", - "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dev": true, + "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -3482,9 +3507,8 @@ }, "node_modules/@types/semver": { "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/sinon": { "version": "10.0.20", @@ -3524,9 +3548,8 @@ }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.7.1.tgz", - "integrity": "sha512-KwfdWXJBOviaBVhxO3p5TJiLpNuh2iyXyjmWN0f1nU87pwyvfS0EmjC6ukQVYVFJd/K1+0NWGPDXiyEyQorn0Q==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "7.7.1", @@ -3604,9 +3627,8 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.7.1.tgz", - "integrity": "sha512-ZksJLW3WF7o75zaBPScdW1Gbkwhd/lyeXGf1kQCxJaOeITscoSl0MjynVvCzuV5boUz/3fOI06Lz8La55mu29Q==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "7.7.1", "@typescript-eslint/utils": "7.7.1", @@ -3672,9 +3694,8 @@ }, "node_modules/@typescript-eslint/utils": { "version": "7.7.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.7.1.tgz", - "integrity": "sha512-QUvBxPEaBXf41ZBbaidKICgVL8Hin0p6prQDu6bbetWo39BKbWJxRsErOzMNT1rXvTll+J7ChrbmMCXM9rsvOQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.15", @@ -3784,7 +3805,6 @@ }, "node_modules/ajv": { "version": "6.12.6", - "dev": true, "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", @@ -3797,6 +3817,74 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats-draft2019": { + "version": "1.6.1", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1", + "schemes": "^1.4.0", + "smtp-address-parser": "^1.0.3", + "uri-js": "^4.4.1" + }, + "peerDependencies": { + "ajv": "*" + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.12.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/ajv-ftl-i18n": { + "version": "0.1.1", + "license": "MIT", + "dependencies": { + "commander": "10.0.0", + "fluent-transpiler": "0.2.1" + }, + "bin": { + "ajv-ftl": "cli.js" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/willfarrell" + } + }, + "node_modules/ajv-ftl-i18n/node_modules/commander": { + "version": "10.0.0", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "dev": true, @@ -3957,9 +4045,8 @@ }, "node_modules/aws-sdk-client-mock": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/aws-sdk-client-mock/-/aws-sdk-client-mock-4.0.0.tgz", - "integrity": "sha512-/rxo+pzCFaUozK7TyCqo3GYwzdBGn9Ai6EsT8ytXDoUXlD/Q5hw9hj2lOkCAyubECzGJFHMmQg9GZ1GOGlN/qQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/sinon": "^10.0.10", "sinon": "^16.1.3", @@ -4110,14 +4197,12 @@ }, "node_modules/bowser": { "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", - "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + "license": "MIT" }, "node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } @@ -4228,6 +4313,14 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "node_modules/camelcase": { "version": "5.3.1", "license": "MIT", @@ -4254,6 +4347,15 @@ ], "license": "CC-BY-4.0" }, + "node_modules/capital-case": { + "version": "1.0.4", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "node_modules/chalk": { "version": "4.1.2", "license": "MIT", @@ -4268,6 +4370,24 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "4.1.2", + "license": "MIT", + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/char-regex": { "version": "1.0.2", "dev": true, @@ -4425,6 +4545,14 @@ "dev": true, "license": "MIT" }, + "node_modules/common-tags": { + "version": "1.8.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/compare-func": { "version": "2.0.0", "dev": true, @@ -4448,6 +4576,15 @@ "proto-list": "~1.2.1" } }, + "node_modules/constant-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, "node_modules/conventional-changelog-angular": { "version": "7.0.0", "dev": true, @@ -4513,9 +4650,8 @@ }, "node_modules/convert-hrtime": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", - "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4762,6 +4898,15 @@ "node": ">=8" } }, + "node_modules/discontinuous-range": { + "version": "1.0.0", + "license": "MIT" + }, + "node_modules/dlv": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, "node_modules/doctrine": { "version": "3.0.0", "dev": true, @@ -4773,6 +4918,14 @@ "node": ">=6.0.0" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/dot-prop": { "version": "5.3.0", "dev": true, @@ -5364,6 +5517,10 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/extend": { + "version": "3.0.2", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "license": "MIT" @@ -5401,7 +5558,6 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { @@ -5409,10 +5565,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "2.3.0", + "license": "MIT" + }, "node_modules/fast-xml-parser": { "version": "4.2.5", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", - "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", "funding": [ { "type": "paypal", @@ -5423,6 +5581,7 @@ "url": "https://github.com/sponsors/NaturalIntelligence" } ], + "license": "MIT", "dependencies": { "strnum": "^1.0.5" }, @@ -5510,9 +5669,8 @@ }, "node_modules/find-versions": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", - "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", "dev": true, + "license": "MIT", "dependencies": { "semver-regex": "^4.0.5", "super-regex": "^1.0.0" @@ -5542,6 +5700,25 @@ "dev": true, "license": "ISC" }, + "node_modules/fluent-transpiler": { + "version": "0.2.1", + "license": "MIT", + "dependencies": { + "@fluent/syntax": "0.18.1", + "change-case": "4.1.2", + "commander": "9.4.0" + }, + "bin": { + "ftl": "cli.js" + } + }, + "node_modules/fluent-transpiler/node_modules/commander": { + "version": "9.4.0", + "license": "MIT", + "engines": { + "node": "^12.20.0 || >=14" + } + }, "node_modules/for-each": { "version": "0.3.3", "dev": true, @@ -5614,9 +5791,8 @@ }, "node_modules/function-timeout": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.1.tgz", - "integrity": "sha512-6yPMImFFuaMPNaTMTBuolA8EanHJWF5Vju0NHpObRURT105J6x1Mf2a7J4P7Sqk2xDxv24N5L0RatEhTBhNmdA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -5806,6 +5982,10 @@ "dev": true, "license": "MIT" }, + "node_modules/gsul": { + "resolved": "packages/gsul", + "link": true + }, "node_modules/handlebars": { "version": "4.7.8", "dev": true, @@ -5826,6 +6006,25 @@ "uglify-js": "^3.1.4" } }, + "node_modules/has-ansi": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/has-flag": { "version": "4.0.0", "license": "MIT", @@ -5891,6 +6090,14 @@ "node": ">= 0.4" } }, + "node_modules/header-case": { + "version": "2.0.4", + "license": "MIT", + "dependencies": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/highlight.js": { "version": "10.7.3", "dev": true, @@ -6934,9 +7141,19 @@ "dev": true, "license": "MIT" }, + "node_modules/json-schema-to-ts": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^1.2.2" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { @@ -7224,29 +7441,115 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "dev": true, + "license": "MIT" + }, + "node_modules/loglevel": { + "version": "1.9.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-colored-level-prefix": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/chalk": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/escape-string-regexp": { + "version": "1.0.5", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, - "node_modules/lodash.isstring": { - "version": "4.0.1", + "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": { + "version": "3.0.1", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/lodash.memoize": { - "version": "4.1.2", + "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": { + "version": "2.0.0", "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, - "node_modules/lodash.uniqby": { - "version": "4.7.0", - "dev": true, - "license": "MIT" + "node_modules/lower-case": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } }, "node_modules/lru-cache": { "version": "5.1.1", @@ -7409,9 +7712,8 @@ }, "node_modules/minimatch": { "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -7448,6 +7750,10 @@ "obliterator": "^1.6.1" } }, + "node_modules/moo": { + "version": "0.5.2", + "license": "BSD-3-Clause" + }, "node_modules/ms": { "version": "2.1.2", "dev": true, @@ -7468,6 +7774,30 @@ "dev": true, "license": "MIT" }, + "node_modules/nearley": { + "version": "2.20.1", + "license": "MIT", + "dependencies": { + "commander": "^2.19.0", + "moo": "^0.5.0", + "railroad-diagrams": "^1.0.0", + "randexp": "0.4.6" + }, + "bin": { + "nearley-railroad": "bin/nearley-railroad.js", + "nearley-test": "bin/nearley-test.js", + "nearley-unparse": "bin/nearley-unparse.js", + "nearleyc": "bin/nearleyc.js" + }, + "funding": { + "type": "individual", + "url": "https://nearley.js.org/#give-to-nearley" + } + }, + "node_modules/nearley/node_modules/commander": { + "version": "2.20.3", + "license": "MIT" + }, "node_modules/neo-async": { "version": "2.6.2", "dev": true, @@ -7498,6 +7828,14 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/no-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-emoji": { "version": "2.1.3", "dev": true, @@ -10524,6 +10862,14 @@ "node": ">=6" } }, + "node_modules/param-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "dev": true, @@ -10570,6 +10916,22 @@ "dev": true, "license": "MIT" }, + "node_modules/pascal-case": { + "version": "3.1.2", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-exists": { "version": "4.0.0", "license": "MIT", @@ -10805,6 +11167,152 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/prettier-eslint": { + "version": "16.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/parser": "^6.7.5", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^3.0.1", + "pretty-format": "^29.7.0", + "require-relative": "^0.8.7", + "typescript": "^5.2.2", + "vue-eslint-parser": "^9.1.0" + }, + "engines": { + "node": ">=16.10.0" + }, + "peerDependencies": { + "prettier-plugin-svelte": "^3.0.0", + "svelte-eslint-parser": "*" + }, + "peerDependenciesMeta": { + "prettier-plugin-svelte": { + "optional": true + }, + "svelte-eslint-parser": { + "optional": true + } + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/prettier-eslint/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", "dev": true, @@ -10917,6 +11425,21 @@ ], "license": "MIT" }, + "node_modules/railroad-diagrams": { + "version": "1.0.0", + "license": "CC0-1.0" + }, + "node_modules/randexp": { + "version": "0.4.6", + "license": "MIT", + "dependencies": { + "discontinuous-range": "1.0.0", + "ret": "~0.1.10" + }, + "engines": { + "node": ">=0.12" + } + }, "node_modules/rc": { "version": "1.2.8", "dev": true, @@ -10981,9 +11504,8 @@ }, "node_modules/read-package-up": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", - "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up-simple": "^1.0.0", "read-pkg": "^9.0.0", @@ -10998,9 +11520,8 @@ }, "node_modules/read-package-up/node_modules/type-fest": { "version": "4.15.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.15.0.tgz", - "integrity": "sha512-tB9lu0pQpX5KJq54g+oHOLumOx+pMep4RaM6liXh2PKmVRFF+/vAtUP0ZaJ0kOySfVNjF6doBWPHhBhISKdlIA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=16" }, @@ -11185,6 +11706,10 @@ "once": "^1.3.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, "node_modules/registry-auth-token": { "version": "5.0.2", "dev": true, @@ -11214,6 +11739,11 @@ "version": "2.0.0", "license": "ISC" }, + "node_modules/require-relative": { + "version": "0.8.7", + "dev": true, + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.8", "dev": true, @@ -11265,6 +11795,13 @@ "node": ">=10" } }, + "node_modules/ret": { + "version": "0.1.15", + "license": "MIT", + "engines": { + "node": ">=0.12" + } + }, "node_modules/reusify": { "version": "1.0.4", "dev": true, @@ -11337,11 +11874,17 @@ "dev": true, "license": "ISC" }, + "node_modules/schemes": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "extend": "^3.0.0" + } + }, "node_modules/semantic-release": { "version": "23.0.8", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.8.tgz", - "integrity": "sha512-yZkuWcTTfh5h/DrR4Q4QvJSARJdb6wjwn/sN0qKMYEkvwaVFek8YWfrgtL8oWaRdl0fLte0Y1wWMzLbwoaII1g==", "dev": true, + "license": "MIT", "dependencies": { "@semantic-release/commit-analyzer": "^12.0.0", "@semantic-release/error": "^4.0.0", @@ -11620,9 +12163,8 @@ }, "node_modules/semver-regex": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -11646,6 +12188,15 @@ "dev": true, "license": "ISC" }, + "node_modules/sentence-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "node_modules/set-blocking": { "version": "2.0.0", "license": "ISC" @@ -11835,6 +12386,24 @@ "node": "*" } }, + "node_modules/smtp-address-parser": { + "version": "1.0.10", + "license": "MIT", + "dependencies": { + "nearley": "^2.20.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/source-map": { "version": "0.6.1", "dev": true, @@ -12047,14 +12616,12 @@ }, "node_modules/strnum": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", - "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + "license": "MIT" }, "node_modules/super-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz", - "integrity": "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==", "dev": true, + "license": "MIT", "dependencies": { "function-timeout": "^1.0.1", "time-span": "^5.1.0" @@ -12272,9 +12839,8 @@ }, "node_modules/time-span": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", - "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", "dev": true, + "license": "MIT", "dependencies": { "convert-hrtime": "^5.0.0" }, @@ -12328,6 +12894,10 @@ "node": ">=0.6" } }, + "node_modules/ts-algebra": { + "version": "1.2.2", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "1.3.0", "dev": true, @@ -12459,9 +13029,8 @@ }, "node_modules/typescript": { "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -12566,6 +13135,20 @@ "resolved": "packages/updatePrescriptionStatus", "link": true }, + "node_modules/upper-case": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/uri-js": { "version": "4.4.1", "license": "BSD-2-Clause", @@ -12652,6 +13235,29 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/vue-eslint-parser": { + "version": "9.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, "node_modules/walker": { "version": "1.0.8", "dev": true, @@ -12836,6 +13442,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/gsul": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@aws-lambda-powertools/commons": "^2.0.0", + "@aws-lambda-powertools/logger": "^2.0.0", + "@aws-sdk/client-dynamodb": "^3.540.0", + "@aws-sdk/lib-dynamodb": "^3.540.0", + "@aws-sdk/util-dynamodb": "^3.540.0", + "@middy/core": "^5.2.6", + "@middy/input-output-logger": "^5.2.6", + "@middy/validator": "^5.3.2", + "@nhs/fhir-middy-error-handler": "^2.0.0", + "json-schema-to-ts": "^3.0.1" + } + }, "packages/sandbox": { "version": "1.0.0", "license": "MIT", diff --git a/package.json b/package.json index ceee03d7b..169868987 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "workspaces": [ "packages/specification", "packages/updatePrescriptionStatus", + "packages/gsul", "packages/sandbox" ], "devDependencies": { @@ -36,6 +37,7 @@ "jest-junit": "^16.0.0", "license-checker": "^25.0.1", "prettier": "^3.2.5", + "prettier-eslint": "^16.3.0", "semantic-release": "^23.0.8", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", diff --git a/packages/gsul/.eslintrc b/packages/gsul/.eslintrc new file mode 100644 index 000000000..437314157 --- /dev/null +++ b/packages/gsul/.eslintrc @@ -0,0 +1,39 @@ +{ + "root": true, + "env": { + "node": true + }, + "ignorePatterns": ["**/lib/*"], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint", "import-newlines"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/array-type": ["error", {"default": "generic"}], + "@typescript-eslint/consistent-type-assertions": [ + "error", + {"assertionStyle": "as", "objectLiteralTypeAssertions": "never"} + ], + "block-spacing": "error", + "brace-style": ["error", "1tbs"], + "comma-dangle": ["error", "never"], + "comma-spacing": ["error", {"before": false, "after": true}], + "dot-location": ["error", "property"], + "eol-last": ["error", "always"], + "eqeqeq": "error", + "func-call-spacing": "error", + "func-style": ["error", "declaration", {"allowArrowFunctions": true}], + "import-newlines/enforce": ["error", {"items": 3, "max-len": 120, "semi": false}], + "indent": ["error", 2, {"SwitchCase": 1}], + "max-len": ["error", 120], + "no-multi-spaces": "error", + "no-multiple-empty-lines": ["error", {"max": 1}], + "no-trailing-spaces": "error", + "object-curly-spacing": ["error", "never"], + "quotes": ["error", "double", {"allowTemplateLiterals": true, "avoidEscape": true}], + "semi": ["error", "never"] + } +} diff --git a/packages/gsul/.vscode/launch.json b/packages/gsul/.vscode/launch.json new file mode 100644 index 000000000..8acf7f038 --- /dev/null +++ b/packages/gsul/.vscode/launch.json @@ -0,0 +1,35 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "name": "vscode-jest-tests.v2", + "request": "launch", + "args": [ + "--runInBand", + "--watchAll=false", + "--testNamePattern", + "${jest.testNamePattern}", + "--runTestsByPath", + "${jest.testFile}", + "--config", + "${workspaceFolder}/jest.debug.config.ts" + ], + "cwd": "${workspaceFolder}", + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen", + "disableOptimisticBPs": true, + "program": "${workspaceFolder}/../../node_modules/.bin/jest", + "windows": { + "program": "${workspaceFolder}/node_modules/jest/bin/jest" + }, + "env": { + "POWERTOOLS_DEV": true, + "NODE_OPTIONS": "--experimental-vm-modules" + } + } + ] +} diff --git a/packages/gsul/.vscode/settings.json b/packages/gsul/.vscode/settings.json new file mode 100644 index 000000000..350126494 --- /dev/null +++ b/packages/gsul/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "jest.jestCommandLine": "/workspaces/eps-prescription-status-update-api/node_modules/.bin/jest --no-cache", + "jest.nodeEnv": { + "POWERTOOLS_DEV": true, + "NODE_OPTIONS": "--experimental-vm-modules" + } +} diff --git a/packages/gsul/jest.config.ts b/packages/gsul/jest.config.ts new file mode 100644 index 000000000..fb4d05f26 --- /dev/null +++ b/packages/gsul/jest.config.ts @@ -0,0 +1,9 @@ +import type {JestConfigWithTsJest} from "ts-jest" +import defaultConfig from "../../jest.default.config" + +const jestConfig: JestConfigWithTsJest = { + ...defaultConfig, + "rootDir": "./" +} + +export default jestConfig diff --git a/packages/gsul/jest.debug.config.ts b/packages/gsul/jest.debug.config.ts new file mode 100644 index 000000000..a30627383 --- /dev/null +++ b/packages/gsul/jest.debug.config.ts @@ -0,0 +1,9 @@ +import config from "./jest.config" +import type {JestConfigWithTsJest} from "ts-jest" + +const debugConfig: JestConfigWithTsJest = { + ...config, + "preset": "ts-jest" +} + +export default debugConfig diff --git a/packages/gsul/package.json b/packages/gsul/package.json new file mode 100644 index 000000000..8c0912994 --- /dev/null +++ b/packages/gsul/package.json @@ -0,0 +1,28 @@ +{ + "name": "gsul", + "version": "1.0.0", + "description": "Get status update lambda", + "main": "getStatusUpdates.js", + "author": "NHS Digital", + "license": "MIT", + "type": "module", + "scripts": { + "unit": "POWERTOOLS_DEV=true NODE_OPTIONS=--experimental-vm-modules jest --no-cache --coverage", + "lint": "eslint . --ext .ts --max-warnings 0 --fix", + "compile": "tsc", + "test": "npm run compile && npm run unit", + "check-licenses": "license-checker --failOn GPL --failOn LGPL --start ../.." + }, + "dependencies": { + "@aws-lambda-powertools/commons": "^2.0.0", + "@aws-lambda-powertools/logger": "^2.0.0", + "@aws-sdk/client-dynamodb": "^3.540.0", + "@aws-sdk/lib-dynamodb": "^3.540.0", + "@aws-sdk/util-dynamodb": "^3.540.0", + "@middy/core": "^5.2.6", + "@middy/input-output-logger": "^5.2.6", + "@middy/validator": "^5.3.2", + "@nhs/fhir-middy-error-handler": "^2.0.0", + "json-schema-to-ts": "^3.0.1" + } +} diff --git a/packages/gsul/src/dynamoDBclient.ts b/packages/gsul/src/dynamoDBclient.ts new file mode 100644 index 000000000..23ca1122e --- /dev/null +++ b/packages/gsul/src/dynamoDBclient.ts @@ -0,0 +1,52 @@ +import {DynamoDBClient} from "@aws-sdk/client-dynamodb" +import {DynamoDBDocumentClient, QueryCommand, QueryCommandInput} from "@aws-sdk/lib-dynamodb" +import {Logger} from "@aws-lambda-powertools/logger" +import {itemType} from "./schema/response.ts" +import {NativeAttributeValue} from "@aws-sdk/util-dynamodb" + +const tableName = process.env.TABLE_NAME +const client = new DynamoDBClient() +const docClient = DynamoDBDocumentClient.from(client) + +export async function getItemsUpdatesForPrescription( + prescriptionID: string, + odsCode: string, + logger: Logger +): Promise> { + // helper function to deal with pagination of results from dynamodb + const getAllData = async (query: QueryCommandInput) => { + const _getAllData = async (query: QueryCommandInput, startKey: Record) => { + if (startKey) { + query.ExclusiveStartKey = startKey + } + const command = new QueryCommand(query) + logger.info("running query", {query}) + return docClient.send(command) + } + let lastEvaluatedKey = null + let rows = [] + do { + const result = await _getAllData(query, lastEvaluatedKey) + rows = rows.concat(result.Items) + lastEvaluatedKey = result.LastEvaluatedKey + } while (lastEvaluatedKey) + return rows + } + + const items = await getAllData({ + TableName: tableName, + IndexName: "PharmacyODSCodePrescriptionIDIndex", + KeyConditionExpression: "PrescriptionID = :inputPrescriptionID AND PharmacyODSCode = :inputPharmacyODSCode", + ExpressionAttributeValues: { + ":inputPharmacyODSCode": odsCode, + ":inputPrescriptionID": prescriptionID + } + }) + + return items.map((singleUpdate) => ({ + itemId: String(singleUpdate.LineItemID), + latestStatus: String(singleUpdate.Status), + isTerminalState: String(singleUpdate.TerminalStatus), + lastUpdateDateTime: String(singleUpdate.LastModified) + })) +} diff --git a/packages/gsul/src/errorHandler.ts b/packages/gsul/src/errorHandler.ts new file mode 100644 index 000000000..4abbe685a --- /dev/null +++ b/packages/gsul/src/errorHandler.ts @@ -0,0 +1,53 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {MiddlewareObj} from "@middy/core" +import {Logger} from "@aws-lambda-powertools/logger" +import{responseType} from "./schema/response.ts" + +type MockLogger = { + error: (error: Error, message: string) => void +} +type HandlerLogger = Console | MockLogger | Logger +type LoggerAndLevel = { + logger?: HandlerLogger + level?: string +} + +// custom middy error handler to just log the error and return isSuccess = false + +function errorHandler({logger = console, level = "error"}: LoggerAndLevel) { + return { + onError: async (handler) => { + const error: any = handler.error + + // if there are a `statusCode` and an `error` field + // this is a valid http error object + if (typeof logger[level] === "function") { + logger[level]( + { + error: ((e) => ({ + name: e.name, + message: e.message, + stack: e.stack, + details: e.details, + cause: e.cause, + status: e.status, + statusCode: e.statusCode, + expose: e.expose + }))(error) + }, + `${error.name}: ${error.message}` + ) + } + + const responseBody: responseType = { + schemaVersion: 1, + isSuccess: false, + prescriptions: [] + } + + handler.response = responseBody + } + } satisfies MiddlewareObj +} + +export {errorHandler} diff --git a/packages/gsul/src/getStatusUpdates.ts b/packages/gsul/src/getStatusUpdates.ts new file mode 100644 index 000000000..4dbba031d --- /dev/null +++ b/packages/gsul/src/getStatusUpdates.ts @@ -0,0 +1,73 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {Logger} from "@aws-lambda-powertools/logger" +import {injectLambdaContext} from "@aws-lambda-powertools/logger/middleware" +import middy from "@middy/core" +import inputOutputLogger from "@middy/input-output-logger" +import validator from "@middy/validator" +import {transpileSchema} from "@middy/validator/transpile" +import {errorHandler} from "./errorHandler.ts" +import {getItemsUpdatesForPrescription} from "./dynamoDBclient.ts" +import {requestSchema, requestType, inputPrescriptionType} from "./schema/request.ts" +import {responseType, outputPrescriptionType, itemType} from "./schema/response.ts" + +const logger = new Logger({serviceName: "GSUL"}) + +const lambdaHandler = async (event: requestType): Promise => { + // there are deliberately no try..catch blocks in this as any errors are caught by custom middy error handler + // and an error response is sent + + // this is an async map so it returns an array of promises + const itemResults = event.prescriptions.map(async (prescription) => { + const queryResult = await getItemsUpdatesForPrescription(prescription.prescriptionID, prescription.odsCode, logger) + return buildResult(prescription, queryResult) + }) + + // wait for all the promises to complete + const finalResults = await Promise.all(itemResults) + const response = { + schemaVersion: 1, + isSuccess: true, + prescriptions: finalResults + } + return response +} + +export const buildResult = ( + inputPrescription: inputPrescriptionType, + items: Array +): outputPrescriptionType => { + // get unique item ids with the latest update based on lastUpdateDateTime + const uniqueItems: Array = Object.values( + items.reduce(function (r, e) { + if (!r[e.itemId] || Date.parse(e.lastUpdateDateTime) > Date.parse(r[e.itemId].lastUpdateDateTime)) r[e.itemId] = e + return r + }, {}) + ) + + const result: outputPrescriptionType = { + prescriptionID: inputPrescription.prescriptionID, + onboarded: items.length > 0, + items: uniqueItems + } + return result +} + +export const handler = middy(lambdaHandler) + .use(injectLambdaContext(logger, {clearState: true})) + .use( + inputOutputLogger({ + logger: (request) => { + if (request.response) { + logger.info(request.response) + } else { + logger.info(request) + } + } + }) + ) + .use(errorHandler({logger: logger})) + .use( + validator({ + eventSchema: transpileSchema(requestSchema) + }) + ) diff --git a/packages/gsul/src/schema/request.ts b/packages/gsul/src/schema/request.ts new file mode 100644 index 000000000..e329df69c --- /dev/null +++ b/packages/gsul/src/schema/request.ts @@ -0,0 +1,34 @@ +import {FromSchema} from "json-schema-to-ts" + +const inputPrescriptionSchema = { + type: "object", + required: ["prescriptionID", "odsCode"], + properties: { + prescriptionID: { + type: "string" + }, + odsCode: { + type: "string" + } + } +} as const + +const requestSchema = { + type: "object", + required: ["schemaVersion", "prescriptions"], + properties: { + schemaVersion: { + type: "number", + minimum: 1, + maximum: 1 + }, + prescriptions: { + type: "array", + items: inputPrescriptionSchema + } + } +} as const + +type requestType = FromSchema +type inputPrescriptionType = FromSchema +export {requestSchema, requestType, inputPrescriptionSchema, inputPrescriptionType} diff --git a/packages/gsul/src/schema/response.ts b/packages/gsul/src/schema/response.ts new file mode 100644 index 000000000..9138197d6 --- /dev/null +++ b/packages/gsul/src/schema/response.ts @@ -0,0 +1,58 @@ +import {FromSchema} from "json-schema-to-ts" + +const itemSchema = { + type: "object", + required: ["itemId", "latestStatus", "isTerminalState", "lastUpdateDateTime"], + properties: { + itemId: { + type: "string" + }, + latestStatus: { + type: "string" + }, + isTerminalState: { + type: "string" + }, + lastUpdateDateTime: { + type: "string" + } + } +} as const + +const outputPrescriptionSchema = { + type: "object", + properties: { + prescriptionID: { + type: "string" + }, + onboarded: { + type: "boolean" + }, + items: { + type: "array", + items: itemSchema + } + } +} as const + +const responseSchema = { + type: "object", + required: ["schemaVersion", "isSuccess", "prescriptions"], + properties: { + schemaVersion: { + type: "number" + }, + isSuccess: { + type: "boolean" + }, + prescriptions: { + type: "array", + items: outputPrescriptionSchema + } + } +} as const + +type responseType = FromSchema +type outputPrescriptionType = FromSchema +type itemType = FromSchema +export {responseSchema, responseType, outputPrescriptionSchema, outputPrescriptionType, itemSchema, itemType} diff --git a/packages/gsul/tests/testBuildResult.test.ts b/packages/gsul/tests/testBuildResult.test.ts new file mode 100644 index 000000000..d0ff359c5 --- /dev/null +++ b/packages/gsul/tests/testBuildResult.test.ts @@ -0,0 +1,142 @@ +import {buildResult} from "../src/getStatusUpdates" +import {inputPrescriptionType} from "../src/schema/request" +import {outputPrescriptionType, itemType} from "../src/schema/response" + +type scenariosType = { + scenarioDescription: string + inputPrescriptions: inputPrescriptionType + queryResults: Array + expectedResult: outputPrescriptionType +} +const scenarios: Array = [ + { + scenarioDescription: "should return correct data when a matched prescription found", + inputPrescriptions: { + prescriptionID: "abc", + odsCode: "123" + }, + queryResults: [ + { + itemId: "item_1", + latestStatus: "latest_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + } + ], + expectedResult: { + prescriptionID: "abc", + onboarded: true, + items: [ + { + itemId: "item_1", + latestStatus: "latest_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + } + ] + } + }, + { + scenarioDescription: "should return no items when empty item status are found", + inputPrescriptions: { + prescriptionID: "abc", + odsCode: "123" + }, + queryResults: [], + expectedResult: { + prescriptionID: "abc", + onboarded: false, + items: [] + } + }, + { + scenarioDescription: "should return latest data when a multiple updates found", + inputPrescriptions: { + prescriptionID: "abc", + odsCode: "123" + }, + queryResults: [ + { + itemId: "item_1", + latestStatus: "early_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + }, + { + itemId: "item_1", + latestStatus: "latest_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1971-01-01T00:00:00Z" + } + ], + expectedResult: { + prescriptionID: "abc", + onboarded: true, + items: [ + { + itemId: "item_1", + latestStatus: "latest_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1971-01-01T00:00:00Z" + } + ] + } + }, + { + scenarioDescription: "should return correct data for multiple items", + inputPrescriptions: { + prescriptionID: "abc", + odsCode: "123" + }, + queryResults: [ + { + itemId: "item_1", + latestStatus: "item_1_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + }, + { + itemId: "item_1", + latestStatus: "latest_item_1_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1972-01-01T00:00:00Z" + }, + { + itemId: "item_2", + latestStatus: "item_2_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1971-01-01T00:00:00Z" + }, + { + itemId: "item_2", + latestStatus: "early_item_2_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + } + ], + expectedResult: { + prescriptionID: "abc", + onboarded: true, + items: [ + { + itemId: "item_1", + latestStatus: "latest_item_1_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1972-01-01T00:00:00Z" + }, + { + itemId: "item_2", + latestStatus: "item_2_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1971-01-01T00:00:00Z" + } + ] + } + } +] +describe("Unit tests for buildResults", () => { + it.each(scenarios)("$scenarioDescription", ({inputPrescriptions, queryResults, expectedResult}) => { + const result = buildResult(inputPrescriptions, queryResults) + expect(result).toMatchObject(expectedResult) + }) +}) diff --git a/packages/gsul/tests/testErrorHandler.test.ts b/packages/gsul/tests/testErrorHandler.test.ts new file mode 100644 index 000000000..064172e97 --- /dev/null +++ b/packages/gsul/tests/testErrorHandler.test.ts @@ -0,0 +1,67 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {errorHandler} from "../src/errorHandler" +import middy from "@middy/core" +import {expect, jest} from "@jest/globals" + +const mockEvent = { + foo: "bar" +} + +const dummyContext = { + callbackWaitsForEmptyEventLoop: true, + functionVersion: "$LATEST", + functionName: "foo-bar-function", + memoryLimitInMB: "128", + logGroupName: "/aws/lambda/foo-bar-function-123456abcdef", + logStreamName: "2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456", + invokedFunctionArn: "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function", + awsRequestId: "c6af9ac6-7b61-11e6-9a41-93e812345678", + getRemainingTimeInMillis: () => 1234, + done: () => console.log("Done!"), + fail: () => console.log("Failed!"), + succeed: () => console.log("Succeeded!") +} + +test("Middleware logs all error details", async () => { + type ErrorLogger = (error: any, message: string) => void + const mockErrorLogger: jest.MockedFunction = jest.fn() + const mockLogger = { + error: mockErrorLogger + } + + const handler = middy(() => { + throw new Error("error running lambda") + }) + + handler.use(errorHandler({logger: mockLogger})) + + await handler({}, dummyContext) + + expect(mockErrorLogger).toHaveBeenCalledTimes(1) + + const [errorObject, errorMessage] = mockErrorLogger.mock.calls[mockErrorLogger.mock.calls.length - 1] + expect(errorMessage).toBe("Error: error running lambda") + expect(errorObject.error.name).toBe("Error") + expect(errorObject.error.message).toBe("error running lambda") + expect(errorObject.error.stack).not.toBeNull() +}) + +test("Middleware returns details as valid fhir from lambda event", async () => { + const mockLogger = { + error: jest.fn(() => {}) + } + + const handler = middy(() => { + throw new Error("error running lambda") + }) + + handler.use(errorHandler({logger: mockLogger})) + + const response = await handler(mockEvent, dummyContext) + expect(response).toMatchObject({ + schemaVersion: 1, + isSuccess: false, + prescriptions: [] + }) + +}) diff --git a/packages/gsul/tests/testHander.test.ts b/packages/gsul/tests/testHander.test.ts new file mode 100644 index 000000000..5def4371a --- /dev/null +++ b/packages/gsul/tests/testHander.test.ts @@ -0,0 +1,102 @@ +import { + expect, + describe, + it, + jest +} from "@jest/globals" + +import {DynamoDBDocumentClient} from "@aws-sdk/lib-dynamodb" +import {handler} from "../src/getStatusUpdates" + +const dummyContext = { + callbackWaitsForEmptyEventLoop: true, + functionVersion: "$LATEST", + functionName: "foo-bar-function", + memoryLimitInMB: "128", + logGroupName: "/aws/lambda/foo-bar-function-123456abcdef", + logStreamName: "2021/03/09/[$LATEST]abcdef123456abcdef123456abcdef123456", + invokedFunctionArn: "arn:aws:lambda:eu-west-1:123456789012:function:foo-bar-function", + awsRequestId: "c6af9ac6-7b61-11e6-9a41-93e812345678", + getRemainingTimeInMillis: () => 1234, + done: () => console.log("Done!"), + fail: () => console.log("Failed!"), + succeed: () => console.log("Succeeded!") +} + +describe("test handler", () => { + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + }) + + it("respond with error when schema version is 2", async () => { + const response = await handler({ + "schemaVersion": 2, + "prescriptions": [{ + prescriptionID: "abc", + odsCode: "123" + }] + }, dummyContext) + expect(response).toMatchObject({ + schemaVersion: 1, + isSuccess: false, + prescriptions: [] + }) + }) + + it("respond with success for empty request", async () => { + const mockReply = { + Count: 0, + Items: [] + } + jest.spyOn(DynamoDBDocumentClient.prototype, "send").mockResolvedValue(mockReply as never) + + const response = await handler( + { + "schemaVersion": 1, + "prescriptions": [] + }, dummyContext) + expect(response).toMatchObject({ + schemaVersion: 1, + isSuccess: true, + prescriptions: [] + }) + }) + + it("respond with success when data passed in", async () => { + const mockReply = { + Count: 1, + Items: [{ + PrescriptionID: "abc", + LineItemID: "item_1", + Status: "latest_status", + TerminalStatus: "terminal", + LastModified: "1970-01-01T00:00:00Z" + }] + } + jest.spyOn(DynamoDBDocumentClient.prototype, "send").mockResolvedValue(mockReply as never) + + const response = await handler( + { + "schemaVersion": 1, + "prescriptions": [{ + prescriptionID: "abc", + odsCode: "123" + }] + }, dummyContext) + expect(response).toMatchObject({ + schemaVersion: 1, + isSuccess: true, + prescriptions: [{ + prescriptionID: "abc", + onboarded: true, + items: [{ + itemId: "item_1", + latestStatus: "latest_status", + isTerminalState: "terminal", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + }] + }] + }) + }) +}) diff --git a/packages/gsul/tests/testRunDynamoDBQueries.test.ts b/packages/gsul/tests/testRunDynamoDBQueries.test.ts new file mode 100644 index 000000000..2cd04979d --- /dev/null +++ b/packages/gsul/tests/testRunDynamoDBQueries.test.ts @@ -0,0 +1,105 @@ +import {DynamoDBDocumentClient} from "@aws-sdk/lib-dynamodb" +import {getItemsUpdatesForPrescription} from "../src/dynamoDBclient" +import {Logger} from "@aws-lambda-powertools/logger" +import { + expect, + describe, + it, + jest +} from "@jest/globals" + +const logger = new Logger({serviceName: "GSUL_TEST"}) + +describe("testing dynamoDBClient", () => { + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + const mockReply = { + Count: 1, + Items: [ + { + PrescriptionID: "abc", + LineItemID: "item_1", + Status: "latest_status", + TerminalStatus: "is_terminal_status", + LastModified: "1970-01-01T00:00:00Z" + } + ] + } + jest.spyOn(DynamoDBDocumentClient.prototype, "send").mockResolvedValue(mockReply as never) + }) + + it("should call dynamo once and return expected items", async () => { + const queryResults = await getItemsUpdatesForPrescription("prescriptionID", "odsCode", logger) + + expect(DynamoDBDocumentClient.prototype.send).toHaveBeenCalledTimes(1) + expect(queryResults).toMatchObject([ + { + itemId: "item_1", + latestStatus: "latest_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + } + ]) + }) +}) + +describe("testing pagination in dynamoDBClient", () => { + beforeEach(() => { + jest.resetModules() + jest.clearAllMocks() + const mockFirstReply = { + Count: 1, + Items: [ + { + PrescriptionID: "abc", + LineItemID: "item_1", + Status: "first_status", + TerminalStatus: "is_terminal_status", + LastModified: "1970-01-01T00:00:00Z" + } + ], + LastEvaluatedKey: { + PharmacyODSCode: "C9Z1O", + RequestID: "d90b88b-9cc8-4b70-9d9f-0144adcc38cc", + PrescriptionID: "16B2E0-A83008-81C13H" + } + } + const mockSecondReply = { + Count: 1, + Items: [ + { + PrescriptionID: "abc", + LineItemID: "item_1", + Status: "second_status", + TerminalStatus: "is_terminal_status", + LastModified: "1970-01-01T00:00:00Z" + } + ] + } + jest + .spyOn(DynamoDBDocumentClient.prototype, "send") + .mockResolvedValueOnce(mockFirstReply as never) + .mockResolvedValueOnce(mockSecondReply as never) + }) + + it("should handle pagination", async () => { + const queryResults = await getItemsUpdatesForPrescription("prescriptionID", "odsCode", logger) + + expect(queryResults).toMatchObject([ + { + itemId: "item_1", + latestStatus: "first_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + }, + { + itemId: "item_1", + latestStatus: "second_status", + isTerminalState: "is_terminal_status", + lastUpdateDateTime: "1970-01-01T00:00:00Z" + } + ]) + expect(DynamoDBDocumentClient.prototype.send).toHaveBeenCalledTimes(2) + }) +}) diff --git a/packages/gsul/tsconfig.json b/packages/gsul/tsconfig.json new file mode 100644 index 000000000..36cd8ba60 --- /dev/null +++ b/packages/gsul/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.defaults.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "lib", + "allowImportingTsExtensions": true, + "noEmit": true, + "strict": false + }, + "references": [], + "include": ["src/**/*", "tests/**/*"], + "exclude": ["node_modules"] +} diff --git a/packages/updatePrescriptionStatus/src/updatePrescriptionStatus.ts b/packages/updatePrescriptionStatus/src/updatePrescriptionStatus.ts index 3c7b8439b..adf6e27c4 100644 --- a/packages/updatePrescriptionStatus/src/updatePrescriptionStatus.ts +++ b/packages/updatePrescriptionStatus/src/updatePrescriptionStatus.ts @@ -32,16 +32,26 @@ export interface DataItem { } const lambdaHandler = async (event: APIGatewayProxyEvent): Promise => { + logger.appendKeys({ + "nhsd-correlation-id": event.headers["nhsd-correlation-id"], + "nhsd-request-id": event.headers["nhsd-request-id"], + "x-correlation-id": event.headers["x-correlation-id"], + "apigw-request-id": event.headers["apigw-request-id"] + }) let responseEntries: Array = [] const xRequestID = getXRequestID(event, responseEntries) + if (!xRequestID) { return response(400, responseEntries) } + logger.appendKeys({ + "x-request-id": xRequestID + }) const requestBody = event.body const requestBundle = castEventBody(requestBody, responseEntries) - if(!requestBundle) { + if (!requestBundle) { return response(400, responseEntries) } diff --git a/sonar-project.properties b/sonar-project.properties index 8752bd0fa..ed5c684dc 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,4 +3,4 @@ sonar.projectKey=NHSDigital_eps-prescription-status-update-api sonar.host.url=https://sonarcloud.io sonar.coverage.exclusions=**/*.test.*,**/jest.config.ts,scripts/*,packages/specification/* -sonar.javascript.lcov.reportPaths=packages/updatePrescriptionStatus/coverage/lcov.info,packages/sandbox/coverage/lcov.info,packages/specification/coverage/lcov.info +sonar.javascript.lcov.reportPaths=packages/updatePrescriptionStatus/coverage/lcov.info,packages/sandbox/coverage/lcov.info,packages/specification/coverage/lcov.info,packages/gsul/coverage/lcov.info diff --git a/tsconfig.build.json b/tsconfig.build.json index 038e2d821..6bfc91ada 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -5,6 +5,7 @@ // Building this project will build all of the following: "references": [ { "path": "packages/updatePrescriptionStatus" }, + { "path": "packages/gsul" }, { "path": "packages/sandbox" } ] }