From 78eddf4a4f0a5afa34947f6e2163e41f532f3b8a Mon Sep 17 00:00:00 2001 From: Angela DeGolier <39102333+adegolier@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:16:36 -0400 Subject: [PATCH 1/3] Platform/angela/16191/always execute send (#16308) * Added null transport for receivers with no transport configured * Changed TransportType to sealed at Kalish's suggestion, so we could remove the else from getTransport() in SendFunction --- prime-router/src/main/kotlin/Receiver.kt | 3 + prime-router/src/main/kotlin/TransportType.kt | 2 +- .../src/main/kotlin/azure/SendFunction.kt | 46 +++++++------ .../src/main/kotlin/azure/WorkflowEngine.kt | 4 ++ .../main/kotlin/transport/NullTransport.kt | 4 +- prime-router/src/test/kotlin/ReceiverTests.kt | 6 ++ .../test/kotlin/azure/SendFunctionTests.kt | 66 ++++++++++++++++--- 7 files changed, 95 insertions(+), 36 deletions(-) diff --git a/prime-router/src/main/kotlin/Receiver.kt b/prime-router/src/main/kotlin/Receiver.kt index ad7b2ed0908..5d0e74d3fe6 100644 --- a/prime-router/src/main/kotlin/Receiver.kt +++ b/prime-router/src/main/kotlin/Receiver.kt @@ -159,6 +159,9 @@ open class Receiver( @get:JsonIgnore val displayName: String get() = externalName ?: name + @get:JsonIgnore + val transportType: TransportType get() = transport ?: NullTransportType() + /** * Defines how batching of sending should proceed. Allows flexibility of * frequency and transmission time on daily basis, but not complete flexibility. diff --git a/prime-router/src/main/kotlin/TransportType.kt b/prime-router/src/main/kotlin/TransportType.kt index 88a1fdfc0bd..2950cc95f84 100644 --- a/prime-router/src/main/kotlin/TransportType.kt +++ b/prime-router/src/main/kotlin/TransportType.kt @@ -19,7 +19,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo JsonSubTypes.Type(GAENTransportType::class, name = "GAEN"), JsonSubTypes.Type(RESTTransportType::class, name = "REST") ) -abstract class TransportType(val type: String) +sealed class TransportType(val type: String) data class SFTPTransportType @JsonCreator constructor( diff --git a/prime-router/src/main/kotlin/azure/SendFunction.kt b/prime-router/src/main/kotlin/azure/SendFunction.kt index 1225af6da02..b1081c1a389 100644 --- a/prime-router/src/main/kotlin/azure/SendFunction.kt +++ b/prime-router/src/main/kotlin/azure/SendFunction.kt @@ -8,6 +8,7 @@ import com.microsoft.azure.functions.annotation.StorageAccount import gov.cdc.prime.router.AS2TransportType import gov.cdc.prime.router.BlobStoreTransportType import gov.cdc.prime.router.CustomerStatus +import gov.cdc.prime.router.EmailTransportType import gov.cdc.prime.router.GAENTransportType import gov.cdc.prime.router.NullTransportType import gov.cdc.prime.router.RESTTransportType @@ -25,7 +26,6 @@ import gov.cdc.prime.router.azure.observability.event.ReportStreamEventName import gov.cdc.prime.router.azure.observability.event.ReportStreamEventProperties import gov.cdc.prime.router.azure.observability.event.ReportStreamEventService import gov.cdc.prime.router.transport.ITransport -import gov.cdc.prime.router.transport.NullTransport import gov.cdc.prime.router.transport.RetryToken import org.apache.logging.log4j.kotlin.Logging import java.time.OffsetDateTime @@ -100,30 +100,26 @@ class SendFunction( receiverStatus = receiver.customerStatus val inputReportId = header.reportFile.reportId actionHistory.trackExistingInputReport(inputReportId) - val serviceName = receiver.fullName val nextRetryItems = mutableListOf() val externalFileName = Report.formExternalFilename(header, workflowEngine.reportService) val sentReportId = UUID.randomUUID() // each sent report gets its own UUID - if (receiver.transport == null) { - actionHistory.setActionType(TaskAction.send_warning) - actionHistory.trackActionResult("Not sending $inputReportId to $serviceName: No transports defined") - } else { - val retryItems = retryToken?.items - val nextRetry = getTransport(receiver.transport)?.send( - receiver.transport, - header, - sentReportId, - externalFileName, - retryItems, - context, - actionHistory, - reportEventService, - workflowEngine.reportService - ) - if (nextRetry != null) { - nextRetryItems += nextRetry - } + val retryItems = retryToken?.items + val transport = getTransport(receiver.transportType) + val nextRetry = transport.send( + receiver.transportType, + header, + sentReportId, + externalFileName, + retryItems, + context, + actionHistory, + reportEventService, + workflowEngine.reportService + ) + if (nextRetry != null) { + nextRetryItems += nextRetry } + logger.info("For $inputReportId: finished send(). Checking to see if a retry is needed.") handleRetry( nextRetryItems, @@ -154,7 +150,9 @@ class SendFunction( } } - private fun getTransport(transportType: TransportType): ITransport? { + private fun getTransport(transportType: TransportType): ITransport { + // IntelliJ complains about this when, but there's a ticket in for it https://youtrack.jetbrains.com/issue/KTIJ-21016 + // It should still compile, unless a TransportType was added without adding it here return when (transportType) { is SFTPTransportType -> workflowEngine.sftpTransport is BlobStoreTransportType -> workflowEngine.blobStoreTransport @@ -162,8 +160,8 @@ class SendFunction( is SoapTransportType -> workflowEngine.soapTransport is GAENTransportType -> workflowEngine.gaenTransport is RESTTransportType -> workflowEngine.restTransport - is NullTransportType -> NullTransport() - else -> null + is NullTransportType -> workflowEngine.nullTransport + is EmailTransportType -> workflowEngine.emailTransport } } diff --git a/prime-router/src/main/kotlin/azure/WorkflowEngine.kt b/prime-router/src/main/kotlin/azure/WorkflowEngine.kt index 7f79e289a97..240602e6855 100644 --- a/prime-router/src/main/kotlin/azure/WorkflowEngine.kt +++ b/prime-router/src/main/kotlin/azure/WorkflowEngine.kt @@ -31,7 +31,9 @@ import gov.cdc.prime.router.serializers.Hl7Serializer import gov.cdc.prime.router.serializers.ReadResult import gov.cdc.prime.router.transport.AS2Transport import gov.cdc.prime.router.transport.BlobStoreTransport +import gov.cdc.prime.router.transport.EmailTransport import gov.cdc.prime.router.transport.GAENTransport +import gov.cdc.prime.router.transport.NullTransport import gov.cdc.prime.router.transport.RESTTransport import gov.cdc.prime.router.transport.RetryItems import gov.cdc.prime.router.transport.RetryToken @@ -71,6 +73,8 @@ class WorkflowEngine( val soapTransport: SoapTransport = SoapTransport(), val gaenTransport: GAENTransport = GAENTransport(), val restTransport: RESTTransport = RESTTransport(), + val nullTransport: NullTransport = NullTransport(), + val emailTransport: EmailTransport = EmailTransport(), ) : BaseEngine(queue) { /** diff --git a/prime-router/src/main/kotlin/transport/NullTransport.kt b/prime-router/src/main/kotlin/transport/NullTransport.kt index 2bb329c9acc..b57367e37e8 100644 --- a/prime-router/src/main/kotlin/transport/NullTransport.kt +++ b/prime-router/src/main/kotlin/transport/NullTransport.kt @@ -10,7 +10,7 @@ import gov.cdc.prime.router.azure.observability.event.IReportStreamEventService import gov.cdc.prime.router.report.ReportService /** - * The Null transport is intended for testing and benchmarking purposes. + * The Null transport is used for testing and benchmarking purposes or when a transport is not configured for a receiver. */ class NullTransport : ITransport { override fun send( @@ -26,7 +26,7 @@ class NullTransport : ITransport { ): RetryItems? { if (header.content == null) error("No content for report ${header.reportFile.reportId}") val receiver = header.receiver ?: error("No receiver defined for report ${header.reportFile.reportId}") - val msg = "Sending to Null Transport" + val msg = "Sending to Null Transport. File can be downloaded by Receiver until it expires." actionHistory.trackActionResult(msg) actionHistory.trackSentReport( receiver, diff --git a/prime-router/src/test/kotlin/ReceiverTests.kt b/prime-router/src/test/kotlin/ReceiverTests.kt index 0a566d70613..084dc7059d2 100644 --- a/prime-router/src/test/kotlin/ReceiverTests.kt +++ b/prime-router/src/test/kotlin/ReceiverTests.kt @@ -267,4 +267,10 @@ internal class ReceiverTests { ) assertThat(receiver.schemaName).isEqualTo("CO") } + + @Test + fun `test receiver type with null transport`() { + val receiver = Receiver("elr", "IGNORE", Topic.COVID_19, CustomerStatus.INACTIVE, translatorConfig) + assertThat(receiver.transportType.type).isEqualTo("NULL") + } } \ No newline at end of file diff --git a/prime-router/src/test/kotlin/azure/SendFunctionTests.kt b/prime-router/src/test/kotlin/azure/SendFunctionTests.kt index 9c6695494aa..57c6eb9a0cf 100644 --- a/prime-router/src/test/kotlin/azure/SendFunctionTests.kt +++ b/prime-router/src/test/kotlin/azure/SendFunctionTests.kt @@ -14,6 +14,7 @@ import gov.cdc.prime.router.azure.db.tables.pojos.ReportFile import gov.cdc.prime.router.azure.db.tables.pojos.Task import gov.cdc.prime.router.azure.observability.event.InMemoryAzureEventService import gov.cdc.prime.router.report.ReportService +import gov.cdc.prime.router.transport.NullTransport import gov.cdc.prime.router.transport.RetryToken import gov.cdc.prime.router.transport.SftpTransport import gov.cdc.prime.router.unittest.UnitTestUtils @@ -23,6 +24,7 @@ import io.mockk.mockk import io.mockk.mockkClass import io.mockk.mockkConstructor import io.mockk.mockkObject +import io.mockk.unmockkAll import io.mockk.verify import org.jooq.Configuration import org.junit.jupiter.api.AfterEach @@ -38,6 +40,7 @@ class SendFunctionTests { val logger = mockkClass(Logger::class) val workflowEngine = mockkClass(WorkflowEngine::class) val sftpTransport = mockkClass(SftpTransport::class) + val nullTransport = mockkClass(NullTransport::class) val reportId = UUID.randomUUID() val task = Task( reportId, @@ -84,11 +87,12 @@ class SendFunctionTests { every { workflowEngine.settings }.returns(settings) every { workflowEngine.readBody(any()) }.returns("body".toByteArray()) every { workflowEngine.sftpTransport }.returns(sftpTransport) + every { workflowEngine.nullTransport }.returns(nullTransport) every { workflowEngine.azureEventService }.returns(InMemoryAzureEventService()) every { workflowEngine.reportService }.returns(mockk(relaxed = true)) } - fun makeHeader(): WorkflowEngine.Header { + fun makeIgnoreDotCSVHeader(): WorkflowEngine.Header { return WorkflowEngine.Header( task, reportFile, null, @@ -99,9 +103,21 @@ class SendFunctionTests { ) } + fun makeIgnoreDotHL7NullHeader(): WorkflowEngine.Header { + return WorkflowEngine.Header( + task, reportFile, + null, + settings.findOrganization("ignore"), + settings.findReceiver("ignore.HL7_NULL"), + metadata.findSchema("covid-19"), "hello".toByteArray(), + true + ) + } + @AfterEach fun reset() { clearAllMocks() + unmockkAll() } @Test @@ -113,10 +129,40 @@ class SendFunctionTests { every { workflowEngine.handleReportEvent(any(), any()) }.answers { val block = secondArg() as (header: WorkflowEngine.Header, retryToken: RetryToken?, txn: Configuration?) -> ReportEvent - val header = makeHeader() + val header = makeIgnoreDotCSVHeader() + nextEvent = block(header, null, null) + } + every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any()) }.returns(null) + every { workflowEngine.recordAction(any()) }.returns(Unit) + every { workflowEngine.azureEventService.trackEvent(any()) }.returns(Unit) + every { workflowEngine.reportService.getRootReports(any()) } returns reportList + every { workflowEngine.db } returns mockk() + mockkObject(Report.Companion) + every { Report.formExternalFilename(any(), any(), any(), any(), any(), any(), any()) } returns "" + + // Invoke + val event = ReportEvent(Event.EventAction.SEND, reportId, false) + SendFunction(workflowEngine).run(event.toQueueMessage(), context) + + // Verify + assertThat(nextEvent).isNotNull() + assertThat(nextEvent!!.eventAction).isEqualTo(Event.EventAction.NONE) + assertThat(nextEvent!!.retryToken).isNull() + } + + @Test + fun `Test with null transport`() { + var nextEvent: ReportEvent? = null + val reportList = listOf(reportFile) + setupLogger() + setupWorkflow() + every { workflowEngine.handleReportEvent(any(), any()) }.answers { + val block = secondArg() as + (header: WorkflowEngine.Header, retryToken: RetryToken?, txn: Configuration?) -> ReportEvent + val header = makeIgnoreDotHL7NullHeader() nextEvent = block(header, null, null) } - every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any(),) }.returns(null) + every { nullTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any()) }.returns(null) every { workflowEngine.recordAction(any()) }.returns(Unit) every { workflowEngine.azureEventService.trackEvent(any()) }.returns(Unit) every { workflowEngine.reportService.getRootReports(any()) } returns reportList @@ -129,6 +175,8 @@ class SendFunctionTests { SendFunction(workflowEngine).run(event.toQueueMessage(), context) // Verify + verify { nullTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any()) } + verify { workflowEngine.recordAction(match { it.action.actionName == TaskAction.send }) } assertThat(nextEvent).isNotNull() assertThat(nextEvent!!.eventAction).isEqualTo(Event.EventAction.NONE) assertThat(nextEvent!!.retryToken).isNull() @@ -144,11 +192,11 @@ class SendFunctionTests { every { workflowEngine.handleReportEvent(any(), any()) }.answers { val block = secondArg() as (header: WorkflowEngine.Header, retryToken: RetryToken?, txn: Configuration?) -> ReportEvent - val header = makeHeader() + val header = makeIgnoreDotCSVHeader() nextEvent = block(header, null, null) } setupWorkflow() - every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any(),) } + every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any()) } .returns(RetryToken.allItems) every { workflowEngine.recordAction(any()) }.returns(Unit) every { workflowEngine.db } returns mockk() @@ -175,13 +223,13 @@ class SendFunctionTests { val block = secondArg() as (header: WorkflowEngine.Header, retryToken: RetryToken?, txn: Configuration?) -> ReportEvent - val header = makeHeader() + val header = makeIgnoreDotCSVHeader() nextEvent = block( header, RetryToken(2, RetryToken.allItems), null ) } setupWorkflow() - every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any(),) } + every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any()) } .returns(RetryToken.allItems) every { workflowEngine.recordAction(any()) }.returns(Unit) every { workflowEngine.db } returns mockk() @@ -211,14 +259,14 @@ class SendFunctionTests { every { workflowEngine.handleReportEvent(any(), any()) }.answers { val block = secondArg() as (header: WorkflowEngine.Header, retryToken: RetryToken?, txn: Configuration?) -> ReportEvent - val header = makeHeader() + val header = makeIgnoreDotCSVHeader() // Should be high enough retry count that the next action should have an error nextEvent = block( header, RetryToken(100, RetryToken.allItems), null ) } setupWorkflow() - every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any(),) } + every { sftpTransport.send(any(), any(), any(), any(), any(), any(), any(), any(), any()) } .returns(RetryToken.allItems) every { workflowEngine.recordAction(any()) }.returns(Unit) every { workflowEngine.db } returns mockk(relaxed = true) From d415513f1bebd8df6a578ab38b66f082aafd9655 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:56:17 -0500 Subject: [PATCH 2/3] Bump vite from 5.4.9 to 5.4.10 in /frontend-react in the vite group (#16330) Bumps the vite group in /frontend-react with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Updates `vite` from 5.4.9 to 5.4.10 - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.4.10/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.4.10/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: direct:development update-type: version-update:semver-patch dependency-group: vite ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joseph Andersen <12385932+jpandersen87@users.noreply.github.com> --- frontend-react/package.json | 2 +- frontend-react/yarn.lock | 47 +++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 3 deletions(-) diff --git a/frontend-react/package.json b/frontend-react/package.json index a1a5e5ea824..2d2902b27bd 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -190,7 +190,7 @@ "tslib": "^2.8.0", "typescript": "^5.6.3", "undici": "^6.20.1", - "vite": "^5.4.9", + "vite": "^5.4.10", "vite-plugin-checker": "^0.8.0", "vite-plugin-svgr": "^4.2.0", "vitest": "^2.1.3" diff --git a/frontend-react/yarn.lock b/frontend-react/yarn.lock index 9c0111280a8..0209ac76909 100644 --- a/frontend-react/yarn.lock +++ b/frontend-react/yarn.lock @@ -10446,7 +10446,7 @@ __metadata: undici: ^6.20.1 use-deep-compare-effect: ^1.8.1 uuid: ^10.0.0 - vite: ^5.4.9 + vite: ^5.4.10 vite-plugin-checker: ^0.8.0 vite-plugin-svgr: ^4.2.0 vitest: ^2.1.3 @@ -12879,7 +12879,7 @@ __metadata: languageName: node linkType: hard -"vite@npm:^5.0.0, vite@npm:^5.4.9": +"vite@npm:^5.0.0": version: 5.4.9 resolution: "vite@npm:5.4.9" dependencies: @@ -12922,6 +12922,49 @@ __metadata: languageName: node linkType: hard +"vite@npm:^5.4.10": + version: 5.4.10 + resolution: "vite@npm:5.4.10" + dependencies: + esbuild: ^0.21.3 + fsevents: ~2.3.3 + postcss: ^8.4.43 + rollup: ^4.20.0 + peerDependencies: + "@types/node": ^18.0.0 || >=20.0.0 + less: "*" + lightningcss: ^1.21.0 + sass: "*" + sass-embedded: "*" + stylus: "*" + sugarss: "*" + terser: ^5.4.0 + dependenciesMeta: + fsevents: + optional: true + peerDependenciesMeta: + "@types/node": + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + bin: + vite: bin/vite.js + checksum: 4db3b8ca3eddbc312d0a95f505d16656e74c6dfa68d3b5eb54b6d6b0f7be1df348d469c43dc69db27dadc06b802f029d654da48f392324efd665ef2c0ca9ba9e + languageName: node + linkType: hard + "vitest@npm:^2.1.3": version: 2.1.3 resolution: "vitest@npm:2.1.3" From b23754a5f3b90c1dcd5646e8e97e5ea300ef3d26 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 29 Oct 2024 22:07:01 +0000 Subject: [PATCH 3/3] Bump the typescript group in /frontend-react with 2 updates (#16328) Bumps the typescript group in /frontend-react with 2 updates: [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) and [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser). Updates `@typescript-eslint/eslint-plugin` from 8.10.0 to 8.11.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.11.0/packages/eslint-plugin) Updates `@typescript-eslint/parser` from 8.10.0 to 8.11.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.11.0/packages/parser) --- updated-dependencies: - dependency-name: "@typescript-eslint/eslint-plugin" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: typescript - dependency-name: "@typescript-eslint/parser" dependency-type: direct:development update-type: version-update:semver-minor dependency-group: typescript ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Joseph Andersen <12385932+jpandersen87@users.noreply.github.com> --- frontend-react/package.json | 4 +- frontend-react/yarn.lock | 122 +++++++++--------------------------- 2 files changed, 33 insertions(+), 93 deletions(-) diff --git a/frontend-react/package.json b/frontend-react/package.json index 2d2902b27bd..f01e69902a5 100644 --- a/frontend-react/package.json +++ b/frontend-react/package.json @@ -144,8 +144,8 @@ "@types/react-router-dom": "^5.3.3", "@types/react-scroll-sync": "^0.9.0", "@types/sanitize-html": "^2.13.0", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", + "@typescript-eslint/eslint-plugin": "^8.11.0", + "@typescript-eslint/parser": "^8.11.0", "@vitejs/plugin-react": "^4.3.3", "@vitest/coverage-istanbul": "^2.1.3", "@vitest/ui": "^2.1.3", diff --git a/frontend-react/yarn.lock b/frontend-react/yarn.lock index 0209ac76909..95debdbdaf1 100644 --- a/frontend-react/yarn.lock +++ b/frontend-react/yarn.lock @@ -3032,15 +3032,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/eslint-plugin@npm:8.10.0" +"@typescript-eslint/eslint-plugin@npm:^8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.11.0" dependencies: "@eslint-community/regexpp": ^4.10.0 - "@typescript-eslint/scope-manager": 8.10.0 - "@typescript-eslint/type-utils": 8.10.0 - "@typescript-eslint/utils": 8.10.0 - "@typescript-eslint/visitor-keys": 8.10.0 + "@typescript-eslint/scope-manager": 8.11.0 + "@typescript-eslint/type-utils": 8.11.0 + "@typescript-eslint/utils": 8.11.0 + "@typescript-eslint/visitor-keys": 8.11.0 graphemer: ^1.4.0 ignore: ^5.3.1 natural-compare: ^1.4.0 @@ -3051,25 +3051,25 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 2bb311eb9a882d530fc94f790f3e1f4745cd4e3523fd8d62ee0ed14d65c4230dc0c797c490c3421c1456fd71349e9bfa146c0b78f63860b75aae6e2a32a6c27c + checksum: 5cfc337a957b1c1a868f0f05ed278d4b631aab3aad037c1ca52f458973dee53c2f79db5cb3ac0278d3a4d2846560335212e347c4b978efd84811d6c910e93975 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/parser@npm:8.10.0" +"@typescript-eslint/parser@npm:^8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/parser@npm:8.11.0" dependencies: - "@typescript-eslint/scope-manager": 8.10.0 - "@typescript-eslint/types": 8.10.0 - "@typescript-eslint/typescript-estree": 8.10.0 - "@typescript-eslint/visitor-keys": 8.10.0 + "@typescript-eslint/scope-manager": 8.11.0 + "@typescript-eslint/types": 8.11.0 + "@typescript-eslint/typescript-estree": 8.11.0 + "@typescript-eslint/visitor-keys": 8.11.0 debug: ^4.3.4 peerDependencies: eslint: ^8.57.0 || ^9.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 2e38f34d9d044e251450116cc081a8f84ba13183e9c3e1dda919ddc00eebe634a37d4dfd785998f259b64cdd770e863ecc6c5cf7c8f422baf3d2bc2a0f9241cf + checksum: b7664933df72e150289889e16f10f042d427d8334786ce33fa2e0d2fd2fbf31a52c6e88f9b6b9a864f4e78c7b60cd52c034886eb1fa82893d69434bcd4f7e173 languageName: node linkType: hard @@ -3093,16 +3093,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/scope-manager@npm:8.10.0" - dependencies: - "@typescript-eslint/types": 8.10.0 - "@typescript-eslint/visitor-keys": 8.10.0 - checksum: 3df8df342e227b80514dcc9151774dea9a71bc649204f702d5b4a1b76a54b4814c5d5a970a6a9213462dd4df0d42342796fab35549e8663d4c0e5d84bd902bba - languageName: node - linkType: hard - "@typescript-eslint/scope-manager@npm:8.11.0": version: 8.11.0 resolution: "@typescript-eslint/scope-manager@npm:8.11.0" @@ -3113,18 +3103,18 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/type-utils@npm:8.10.0" +"@typescript-eslint/type-utils@npm:8.11.0": + version: 8.11.0 + resolution: "@typescript-eslint/type-utils@npm:8.11.0" dependencies: - "@typescript-eslint/typescript-estree": 8.10.0 - "@typescript-eslint/utils": 8.10.0 + "@typescript-eslint/typescript-estree": 8.11.0 + "@typescript-eslint/utils": 8.11.0 debug: ^4.3.4 ts-api-utils: ^1.3.0 peerDependenciesMeta: typescript: optional: true - checksum: 8b0cec8cff1926a08c2bd675b24b2ccff36e59a8d9169eed38343f70c4e3bba18796fc39f30a9307ded3f345881aded80dbd6dc1d78b9ae76cff04fbe8708788 + checksum: 74704ee811de343ea2d349a16eec53b6cc8f2b5720510bf327e10667304c48410af78b9ec7aee5d43924a3f6c268cc2cddb7a0606f20c62391b0d7045d8b6264 languageName: node linkType: hard @@ -3142,13 +3132,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/types@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/types@npm:8.10.0" - checksum: 3839fd43b0f21b432a9f6090a39d5b2254ee48c1eecf14f8f66bea0cbaba9f2f33a7fc78aea37dfe8841442332d0a8f99cc65cd2d01ca43db99550d30d6f7fe8 - languageName: node - linkType: hard - "@typescript-eslint/types@npm:8.11.0": version: 8.11.0 resolution: "@typescript-eslint/types@npm:8.11.0" @@ -3193,25 +3176,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/typescript-estree@npm:8.10.0" - dependencies: - "@typescript-eslint/types": 8.10.0 - "@typescript-eslint/visitor-keys": 8.10.0 - debug: ^4.3.4 - fast-glob: ^3.3.2 - is-glob: ^4.0.3 - minimatch: ^9.0.4 - semver: ^7.6.0 - ts-api-utils: ^1.3.0 - peerDependenciesMeta: - typescript: - optional: true - checksum: 3fc774f51d0a891a5e09bc77f5544b6aa268abec9c01cd9ec831f92dde9c9d61a5c818ca2800c124fb5d61d40ce7ac34740b347c21ba3493e756c052084afd65 - languageName: node - linkType: hard - "@typescript-eslint/typescript-estree@npm:8.11.0": version: 8.11.0 resolution: "@typescript-eslint/typescript-estree@npm:8.11.0" @@ -3231,17 +3195,17 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/utils@npm:8.10.0" +"@typescript-eslint/utils@npm:8.11.0, @typescript-eslint/utils@npm:^8.8.1": + version: 8.11.0 + resolution: "@typescript-eslint/utils@npm:8.11.0" dependencies: "@eslint-community/eslint-utils": ^4.4.0 - "@typescript-eslint/scope-manager": 8.10.0 - "@typescript-eslint/types": 8.10.0 - "@typescript-eslint/typescript-estree": 8.10.0 + "@typescript-eslint/scope-manager": 8.11.0 + "@typescript-eslint/types": 8.11.0 + "@typescript-eslint/typescript-estree": 8.11.0 peerDependencies: eslint: ^8.57.0 || ^9.0.0 - checksum: db67603baacba9cccbbc625801a44e5320bc558be846646ff9962818c64a9ab07edcfdcad98b15a3f8954d3e398e3a41f085c1ec458f7169a1ce7b3674032d59 + checksum: 0a6286fb6c6aaf497bcd5657e4f8167f29c32bb913e4feab3822c504f537ac30975d626dff442cc691e040384ad197313b5685d79296fc8a42ed6c827dcb52fc languageName: node linkType: hard @@ -3277,20 +3241,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/utils@npm:^8.8.1": - version: 8.11.0 - resolution: "@typescript-eslint/utils@npm:8.11.0" - dependencies: - "@eslint-community/eslint-utils": ^4.4.0 - "@typescript-eslint/scope-manager": 8.11.0 - "@typescript-eslint/types": 8.11.0 - "@typescript-eslint/typescript-estree": 8.11.0 - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - checksum: 0a6286fb6c6aaf497bcd5657e4f8167f29c32bb913e4feab3822c504f537ac30975d626dff442cc691e040384ad197313b5685d79296fc8a42ed6c827dcb52fc - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:5.62.0": version: 5.62.0 resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" @@ -3311,16 +3261,6 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:8.10.0": - version: 8.10.0 - resolution: "@typescript-eslint/visitor-keys@npm:8.10.0" - dependencies: - "@typescript-eslint/types": 8.10.0 - eslint-visitor-keys: ^3.4.3 - checksum: 0b3060a036dd3b6acacc32b1d81b3ada1ac5523cc2d16a369ecffd3ab5b389cd98802b248bf65ee8a266a166125a9e38acd7e917d4dd26044bdf2c805537b7e3 - languageName: node - linkType: hard - "@typescript-eslint/visitor-keys@npm:8.11.0": version: 8.11.0 resolution: "@typescript-eslint/visitor-keys@npm:8.11.0" @@ -10369,8 +10309,8 @@ __metadata: "@types/react-router-dom": ^5.3.3 "@types/react-scroll-sync": ^0.9.0 "@types/sanitize-html": ^2.13.0 - "@typescript-eslint/eslint-plugin": ^8.10.0 - "@typescript-eslint/parser": ^8.10.0 + "@typescript-eslint/eslint-plugin": ^8.11.0 + "@typescript-eslint/parser": ^8.11.0 "@uswds/uswds": 3.7.1 "@vitejs/plugin-react": ^4.3.3 "@vitest/coverage-istanbul": ^2.1.3