diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 45d6206e2..793dd5c2e 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -119,7 +119,21 @@ jobs: role-duration-seconds: 10800 - name: Test - run: yarn test-ci + run: run test --coverage + + - name: Save coverage as a workflow artifact + if: always() + uses: actions/upload-artifact@v3 + with: + name: coverage-report + path: coverage + + - name: Report coverage to Code Climate + uses: paambaati/codeclimate-action@v8.0.0 + env: + CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} + with: + coverageLocations: coverage/lcov.info:lcov e2e: timeout-minutes: 5 diff --git a/.github/workflows/pr-coverage-annotation.yml b/.github/workflows/pr-coverage-annotation.yml new file mode 100644 index 000000000..ea52b5b1b --- /dev/null +++ b/.github/workflows/pr-coverage-annotation.yml @@ -0,0 +1,21 @@ +name: PR - coverage annotation + +on: + pull_request: + branches: + - main + +jobs: + coverage-report: + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v3 + - uses: ./.github/actions/setup + - name: Test + run: run test --coverage + - name: Report Coverage + if: always() + uses: davelosert/vitest-coverage-report-action@v2 diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml deleted file mode 100644 index 8cc99a7da..000000000 --- a/.github/workflows/unit-tests.yml +++ /dev/null @@ -1,27 +0,0 @@ -name: Test Coverage - -on: - push: - branches: - - main - pull_request: - branches: - - main - -jobs: - coverage-report: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: ./.github/actions/setup - - name: install - run: run install - - run: yarn run coverage - - name: publish test coverage to code climate - if: always() && env.CC_TEST_REPORTER_ID != '' - uses: paambaati/codeclimate-action@v3.2.0 - env: - CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }} - with: - coverageLocations: | - ${{github.workspace}}/coverage/clover.xml:clover diff --git a/README.md b/README.md index a15fcaaba..e3a8c547b 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,9 @@ + + + Snyk diff --git a/package.json b/package.json index 96ea31772..19c51b9fb 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,14 @@ "test": "tests" }, "scripts": { - "test": "turbo test", - "test-ci": "turbo test", "lint": "turbo lint", "build:cli": "turbo build:cli", - "test:watch": "turbo test:watch", - "test:gui": "turbo test:gui", "e2e": "turbo e2e", "e2e:ui": "turbo e2e:ui", - "test-tsc": "tsc --skipLibCheck --noEmit" + "test-tsc": "tsc --skipLibCheck --noEmit", + "test": "vitest", + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui" }, "repository": "https://github.com/Enterprise-CMCS/macpro-mako", "workspaces": [ @@ -41,11 +40,13 @@ "@testing-library/react": "^14.0.0", "@types/uuid": "^9.0.1", "@vitest/coverage-c8": "^0.29.8", - "@vitest/ui": "^0.29.8", + "@vitest/coverage-istanbul": "^2.0.2", + "@vitest/coverage-v8": "^2.0.2", + "@vitest/ui": "^2.0.2", "aws-sdk-client-mock": "^2.0.1", "esbuild": "^0.19.3", - "prettier": "3.2.5", "msw": "^2.2.1", + "prettier": "3.2.5", "semantic-release": "^21.0.1", "serverless": "^3.38.0", "serverless-disable-functions": "^1.0.0", @@ -56,7 +57,7 @@ "serverless-scriptable-plugin": "^1.3.1", "serverless-stack-termination-protection": "^2.0.2", "turbo": "^1.9.3", - "vitest": "^0.30.1" + "vitest": "^2.0.2" }, "release": { "branches": [ diff --git a/src/cli/run.ts b/src/cli/run.ts index 7507d7c85..4a21fcb2f 100644 --- a/src/cli/run.ts +++ b/src/cli/run.ts @@ -22,7 +22,7 @@ async function install_deps(runner: LabeledProcessRunner) { `Installing Dependencies`, ["yarn"], ".", - true + true, ); } @@ -35,7 +35,7 @@ async function refreshOutputs(stage: string) { `SLS Refresh Outputs`, ["sls", "refresh-outputs", "--stage", stage], ".", - true + true, ); } @@ -55,19 +55,19 @@ yargs(process.argv.slice(2)) await runner.run_command_and_output( `config vars`, ["sls", "ui", "package", "--stage", options.stage], - "." + ".", ); await runner.run_command_and_output( `config vars`, ["sls", "ui", "useLocalhost", "--stage", options.stage], - "." + ".", ); await runner.run_command_and_output( `ui start`, ["yarn", "dev"], - `src/services/ui` + `src/services/ui`, ); - } + }, ) .command( "deploy", @@ -90,23 +90,45 @@ yargs(process.argv.slice(2)) ]; } await runner.run_command_and_output(`SLS Deploy`, deployCmd, "."); - } + }, ) .command( "test", - "run all available tests.", - { - stage: { type: "string", demandOption: true }, + "Run unit tests and watch for changes", + (yargs) => { + yargs + .option("coverage", { + type: "boolean", + describe: "Run tests and generate a coverage report.", + }) + .option("ui", { + type: "boolean", + describe: "Run tests with Vitest UI", + }) + .check((argv) => { + if (argv.coverage && argv.ui) { + throw new Error( + "You cannot use both --watch and --ui at the same time.", + ); + } + return true; + }); }, - async (options) => { + async (argv) => { await install_deps_for_services(); - await runner.run_command_and_output(`Unit Tests`, ["yarn", "test"], "."); + let testCommand = "test"; + if (argv.coverage) { + testCommand = "test:coverage"; + } + if (argv.ui) { + testCommand = "test:ui"; + } await runner.run_command_and_output( - `Load test data`, - ["sls", "database", "seed", "--stage", options.stage], - "." + "Unit Tests", + ["yarn", testCommand], + ".", ); - } + }, ) .command( "e2e", @@ -119,28 +141,20 @@ yargs(process.argv.slice(2)) await runner.run_command_and_output( `Install playwright`, ["yarn", "playwright", "install", "--with-deps"], - "." + ".", ); if (argv.ui) { await runner.run_command_and_output( `e2e:ui tests`, ["yarn", "e2e:ui"], - "." + ".", ); } else { await runner.run_command_and_output(`e2e tests`, ["yarn", "e2e"], "."); } - } + }, ) - .command("test-gui", "open unit-testing gui for vitest.", {}, async () => { - await install_deps_for_services(); - await runner.run_command_and_output( - `Unit Tests`, - ["yarn", "test-gui"], - "." - ); - }) .command( "destroy", "destroy a stage in AWS", @@ -169,7 +183,7 @@ yargs(process.argv.slice(2)) filters: filters, verify: options.verify, }); - } + }, ) .command( "connect", @@ -184,9 +198,9 @@ yargs(process.argv.slice(2)) await runner.run_command_and_output( `SLS connect`, ["sls", options.service, "connect", "--stage", options.stage], - "." + ".", ); - } + }, ) .command( "docs", @@ -199,7 +213,7 @@ yargs(process.argv.slice(2)) await runner.run_command_and_output( `Stop any existing container.`, ["docker", "rm", "-f", "jekyll"], - "docs" + "docs", ); // If we're starting... @@ -223,10 +237,10 @@ yargs(process.argv.slice(2)) "-c", "bundle install && bundle exec jekyll serve --force_polling --host 0.0.0.0", ], - "docs" + "docs", ); } - } + }, ) .command( "base-update", @@ -249,7 +263,7 @@ yargs(process.argv.slice(2)) { stderr: true, close: true, - } + }, ); const fetchBaseCommand = ["git", "fetch", "base"]; @@ -257,7 +271,7 @@ yargs(process.argv.slice(2)) await runner.run_command_and_output( "Update from Base | fetching base template", fetchBaseCommand, - "." + ".", ); const mergeCommand = ["git", "merge", "base/production", "--no-ff"]; @@ -266,13 +280,13 @@ yargs(process.argv.slice(2)) "Update from Base | merging code from base template", mergeCommand, ".", - true + true, ); console.log( - "Merge command was performed. You may have conflicts. This is normal behaivor. To complete the update process fix any conflicts, commit, push, and open a PR." + "Merge command was performed. You may have conflicts. This is normal behaivor. To complete the update process fix any conflicts, commit, push, and open a PR.", ); - } + }, ) .command( ["listRunningStages", "runningEnvs", "listRunningEnvs"], @@ -285,7 +299,7 @@ yargs(process.argv.slice(2)) await ServerlessRunningStages.getAllStagesForRegion(region!); console.log(`runningStages=${runningStages.join(",")}`); } - } + }, ) .command( ["securityHubJiraSync", "securityHubSync", "secHubSync"], @@ -301,7 +315,7 @@ yargs(process.argv.slice(2)) "* All findings of this type are resolved or suppressed, indicated by a Workflow Status of Resolved or Suppressed. (Note: this ticket will automatically close when the AC is met.)", }, }).sync(); - } + }, ) .command( ["open-kibana", "open-os"], @@ -313,10 +327,10 @@ yargs(process.argv.slice(2)) let url = await getCloudFormationOutputValue( "data", options.stage, - "OpenSearchDashboardEndpoint" + "OpenSearchDashboardEndpoint", ); open(url); - } + }, ) .command( ["open-app"], @@ -328,10 +342,10 @@ yargs(process.argv.slice(2)) let url = await getCloudFormationOutputValue( "ui-infra", options.stage, - "ApplicationEndpointUrl" + "ApplicationEndpointUrl", ); open(url); - } + }, ) .strict() // This errors and prints help if you pass an unknown command .scriptName("run") // This modifies the displayed help menu to show 'run' isntead of 'dev.js' @@ -341,7 +355,7 @@ async function getCloudFormationOutputValue( service: string, stage: string, outputKey: string, - region: string = "" + region: string = "", ): Promise { const cliRegion = region !== "" ? region : process.env.REGION_A; const client = new CloudFormationClient({ region: cliRegion }); @@ -354,7 +368,7 @@ async function getCloudFormationOutputValue( const response = await client.send(command); const stack = response.Stacks?.[0]; const outputValue = stack?.Outputs?.find( - (output) => output.OutputKey === outputKey + (output) => output.OutputKey === outputKey, )?.OutputValue; if (outputValue === undefined || outputValue.trim() === "") { throw new Error("Output not found"); @@ -363,7 +377,7 @@ async function getCloudFormationOutputValue( } catch (error) { console.error( `Failed to retrieve output [${outputKey}] from stack [${stackName}]:`, - error + error, ); throw error; // Rethrow or handle as needed } diff --git a/src/libs/package.json b/src/libs/package.json index 324e2a123..92cb14616 100644 --- a/src/libs/package.json +++ b/src/libs/package.json @@ -10,13 +10,10 @@ "aws4": "^1.12.0", "aws4-axios": "^3.2.24" }, - "devDependencies": { - "@vitest/ui": "^1.6.0", - "vitest": "^1.6.0" - }, + "devDependencies": {}, "scripts": { "test": "vitest", - "coverage": "vitest run --coverage", - "test:gui": "vitest --ui" + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui" } } diff --git a/src/libs/vitest.config.ts b/src/libs/vitest.config.ts deleted file mode 100644 index 77a73cf2e..000000000 --- a/src/libs/vitest.config.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: {}, -}); diff --git a/src/packages/shared-types/opensearch/main/index.ts b/src/packages/shared-types/opensearch/main/index.ts index 1c2811b7e..844d49094 100644 --- a/src/packages/shared-types/opensearch/main/index.ts +++ b/src/packages/shared-types/opensearch/main/index.ts @@ -11,6 +11,8 @@ import { newSubmission, legacyPackageView, withdrawPackage, + issueRai, + respondToRai, withdrawRai, toggleWithdrawEnabled, seatool, @@ -19,6 +21,8 @@ import { export type Document = z.infer & z.infer & + z.infer & + z.infer & z.infer & z.infer & z.infer & diff --git a/src/packages/shared-types/opensearch/main/transforms/index.ts b/src/packages/shared-types/opensearch/main/transforms/index.ts index e6b683576..1a97d0fda 100644 --- a/src/packages/shared-types/opensearch/main/transforms/index.ts +++ b/src/packages/shared-types/opensearch/main/transforms/index.ts @@ -2,6 +2,8 @@ export * as legacyPackageView from "./legacy-package-view"; export * as newSubmission from "./new-submission"; export * as toggleWithdrawEnabled from "./toggle-withdraw-enabled"; export * as withdrawPackage from "./withdraw-package"; +export * as issueRai from "./issue-rai"; +export * as respondToRai from "./respond-to-rai"; export * as withdrawRai from "./withdraw-rai-response"; export * as seatool from "./seatool"; export * as removeAppkChild from "./remove-appk-child"; diff --git a/src/packages/shared-types/opensearch/main/transforms/issue-rai.ts b/src/packages/shared-types/opensearch/main/transforms/issue-rai.ts new file mode 100644 index 000000000..da4e1944b --- /dev/null +++ b/src/packages/shared-types/opensearch/main/transforms/issue-rai.ts @@ -0,0 +1,12 @@ +import { raiIssueSchema } from "../../.."; + +export const transform = (id: string) => { + return raiIssueSchema.transform((data) => ({ + id, + makoChangedDate: !!data.timestamp + ? new Date(data.timestamp).toISOString() + : null, + })); +}; + +export type Schema = ReturnType; diff --git a/src/packages/shared-types/opensearch/main/transforms/respond-to-rai.ts b/src/packages/shared-types/opensearch/main/transforms/respond-to-rai.ts new file mode 100644 index 000000000..3eb4cb0e7 --- /dev/null +++ b/src/packages/shared-types/opensearch/main/transforms/respond-to-rai.ts @@ -0,0 +1,12 @@ +import { raiResponseSchema } from "../../.."; + +export const transform = (id: string) => { + return raiResponseSchema.transform((data) => ({ + id, + makoChangedDate: !!data.timestamp + ? new Date(data.timestamp).toISOString() + : null, + })); +}; + +export type Schema = ReturnType; diff --git a/src/packages/shared-types/package.json b/src/packages/shared-types/package.json index f4f2633f2..037d9a426 100644 --- a/src/packages/shared-types/package.json +++ b/src/packages/shared-types/package.json @@ -7,12 +7,12 @@ "base-64": "^1.0.0", "eslint": "^8.38.0", "eslint-config-custom-server": "*", - "vitest": "^1.6.0", "zod": "^3.22.3" }, "scripts": { "test": "vitest", - "coverage": "vitest run --coverage" + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui" }, "dependencies": { "s3-url-parser": "^1.0.3", diff --git a/src/packages/shared-utils/package-actions/rules.ts b/src/packages/shared-utils/package-actions/rules.ts index 97690b863..c2b6502a6 100644 --- a/src/packages/shared-utils/package-actions/rules.ts +++ b/src/packages/shared-utils/package-actions/rules.ts @@ -96,11 +96,15 @@ const arUpdateId: ActionRule = { }; const arCompleteIntake: ActionRule = { action: Action.COMPLETE_INTAKE, - check: (checker, user) => - false && isCmsWriteUser(user) && checker.needsIntake, + check: (checker, user) => isCmsWriteUser(user) && checker.needsIntake, }; -// TODO: Add rule for remove-appk-child +const arRemoveAppkChild: ActionRule = { + action: Action.REMOVE_APPK_CHILD, + check: (checker, user) => + isStateUser(user) && !!checker.isAppkChild +} + export default [ arIssueRai, @@ -112,4 +116,5 @@ export default [ arTempExtension, arUpdateId, arCompleteIntake, + arRemoveAppkChild, ]; diff --git a/src/packages/shared-utils/package-check.ts b/src/packages/shared-utils/package-check.ts index d058cb05d..ae2354e4d 100644 --- a/src/packages/shared-utils/package-check.ts +++ b/src/packages/shared-utils/package-check.ts @@ -37,6 +37,8 @@ export const PackageCheck = ({ appkParentId, appkParent, initialIntakeNeeded, + leadAnalystName + }: opensearch.main.Document) => { const planChecks = { isSpa: checkAuthority(authority, [Authority.MED_SPA, Authority.CHIP_SPA]), @@ -49,6 +51,7 @@ export const PackageCheck = ({ /** Keep excess methods to a minimum with `is` **/ authorityIs: (validAuthorities: Authority[]) => checkAuthority(authority, validAuthorities), + hasCpoc: !!leadAnalystName, }; const statusChecks = { /** Is in any of our pending statuses, sans Pending-RAI **/ diff --git a/src/packages/shared-utils/package.json b/src/packages/shared-utils/package.json index 7f410c0d7..1ddb260d9 100644 --- a/src/packages/shared-utils/package.json +++ b/src/packages/shared-utils/package.json @@ -5,7 +5,8 @@ "license": "MIT", "scripts": { "test": "vitest", - "coverage": "vitest run --coverage" + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui" }, "devDependencies": {}, "dependencies": { diff --git a/src/services/api/global.d.ts b/src/services/api/global.d.ts new file mode 100644 index 000000000..eb83e8dd3 --- /dev/null +++ b/src/services/api/global.d.ts @@ -0,0 +1,6 @@ +import { type PackageActionWriteService } from "./handlers/package-actions/services/package-action-write-service"; + +declare global { + // eslint-disable-next-line no-var + var packageActionWriteService: PackageActionWriteService; +} diff --git a/src/services/api/handlers/action.ts b/src/services/api/handlers/action.ts index fcb5a910e..6fb3c6415 100644 --- a/src/services/api/handlers/action.ts +++ b/src/services/api/handlers/action.ts @@ -10,16 +10,29 @@ import { getAvailableActions } from "shared-utils"; import { Action } from "shared-types"; import { issueRai, - removeAppkChild, respondToRai, toggleRaiResponseWithdraw, updateId, withdrawPackage, withdrawRai, completeIntake, -} from "./packageActions"; + removeAppkChild, +} from "./package-actions"; +import { setupWriteService } from "./package-actions/setup-write-service"; + +const checkIfActionType = ( + potentialActionType: unknown, +): potentialActionType is Action => { + if (potentialActionType) { + return true; + } + return false; +}; export const handler = async (event: APIGatewayEvent) => { + if (typeof globalThis.packageActionWriteService === "undefined") { + global.packageActionWriteService = await setupWriteService(); + } if (!event.pathParameters || !event.pathParameters.actionType) { return response({ statusCode: 400, @@ -36,8 +49,6 @@ export const handler = async (event: APIGatewayEvent) => { try { const actionType = event.pathParameters.actionType as Action; const body = JSON.parse(event.body); - console.log(actionType); - console.log(body); // Check auth const result = await getPackage(body.id); @@ -58,16 +69,10 @@ export const handler = async (event: APIGatewayEvent) => { authDetails.poolId, ); - if (actionType === Action.REMOVE_APPK_CHILD) { - await removeAppkChild(body); - return response({ - statusCode: 200, - body: { message: "success" }, - }); - } - // Check that the package action is available const actions: Action[] = getAvailableActions(userAttr, result._source); + console.log("ACTIONTYPE: " + actionType); + console.log("AVAILABLE ACTION: " + actions); if (!actions.includes(actionType)) { return response({ statusCode: 401, @@ -76,7 +81,7 @@ export const handler = async (event: APIGatewayEvent) => { }, }); } - console.log(actionType); + // Call package action switch (actionType) { case Action.WITHDRAW_PACKAGE: @@ -103,6 +108,9 @@ export const handler = async (event: APIGatewayEvent) => { case Action.COMPLETE_INTAKE: await completeIntake(body); break; + case Action.REMOVE_APPK_CHILD: + await removeAppkChild(body); + break; default: throw `No ${actionType} action available`; } diff --git a/src/services/api/handlers/package-actions/complete-intake/complete-intake.test.ts b/src/services/api/handlers/package-actions/complete-intake/complete-intake.test.ts new file mode 100644 index 000000000..eb05fb1d6 --- /dev/null +++ b/src/services/api/handlers/package-actions/complete-intake/complete-intake.test.ts @@ -0,0 +1,8 @@ +import { describe, it, expect } from "vitest"; + +// this is a placeholder. i will rewrite these shortly +describe("example test", () => { + it("should equal 1", () => { + expect(1).toEqual(1); + }); +}); \ No newline at end of file diff --git a/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts b/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts new file mode 100644 index 000000000..893e685b7 --- /dev/null +++ b/src/services/api/handlers/package-actions/complete-intake/complete-intake.ts @@ -0,0 +1,49 @@ +import { completeIntakeSchema, Action } from "shared-types"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; +import { type PackageActionWriteService } from "../services/package-action-write-service"; + +export async function completeIntake( + body: any, + packageActionWriteService: PackageActionWriteService = globalThis.packageActionWriteService, +) { + console.log("CMS performing intake for a record."); + + const result = completeIntakeSchema.safeParse(body); + if (!result.success) { + console.error( + "validation error: The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { + message: "Event validation error", + }, + }); + } + + const now = new Date().getTime(); + + await packageActionWriteService.completeIntake({ + timestamp: now, + action: Action.COMPLETE_INTAKE, + cpoc: result.data.cpoc, + description: result.data.description, + id: result.data.id, + subject: result.data.subject, + submitterName: result.data.submitterName, + subTypeIds: result.data.subTypeIds, + topicName: TOPIC_NAME, + typeIds: result.data.typeIds, + }); + + return response({ + statusCode: 200, + body: { + message: "record successfully submitted", + }, + }); +} diff --git a/src/services/api/handlers/package-actions/consts.ts b/src/services/api/handlers/package-actions/consts.ts new file mode 100644 index 000000000..5bfae5a29 --- /dev/null +++ b/src/services/api/handlers/package-actions/consts.ts @@ -0,0 +1,16 @@ +const user = process.env.dbUser; +const password = process.env.dbPassword; +const server = process.env.dbIp; +const port = parseInt(process.env.dbPort as string); + +import * as sql from "mssql"; + +export const config = { + user: user, + password: password, + server: server, + port: port, + database: "SEA", +} as sql.config; + +export const TOPIC_NAME = process.env.topicName as string; diff --git a/src/services/api/handlers/package-actions/get-id-to-update.ts b/src/services/api/handlers/package-actions/get-id-to-update.ts new file mode 100644 index 000000000..1da5d1a9f --- /dev/null +++ b/src/services/api/handlers/package-actions/get-id-to-update.ts @@ -0,0 +1,25 @@ +import { opensearch } from "shared-types"; +import { getAppkChildren } from "../../libs/package"; +import { getItem } from "libs"; + +export async function getIdsToUpdate(id: string) { + console.log(process.env.osDomain); + console.log(id); + const og = (await getItem( + process.env.osDomain!, + "main", + id, + )) as opensearch.main.ItemResult; + if (!og) { + throw "Package doesn't exist, and it should."; + } + console.log(JSON.stringify(og, null, 2)); + const idsToUpdate = [og._id]; + if (og._source.appkParent) { + const children = await getAppkChildren(og._id); + children.hits?.hits?.forEach((child) => { + idsToUpdate.push(child._id); + }); + } + return idsToUpdate; +} diff --git a/src/services/api/handlers/package-actions/index.ts b/src/services/api/handlers/package-actions/index.ts new file mode 100644 index 000000000..a780bba00 --- /dev/null +++ b/src/services/api/handlers/package-actions/index.ts @@ -0,0 +1,10 @@ +export * from "./complete-intake/complete-intake"; +export * from "./consts"; +export * from "./get-id-to-update"; +export * from "./issue-rai/issue-rai"; +export * from "./remove-appk-child/remove-appk-child"; +export * from "./respond-to-rai/respond-to-rai"; +export * from "./toggle-rai-response-withdraw/toggle-rai-response-withdraw"; +export * from "./update-id/update-id"; +export * from "./withdraw-package/withdraw-package"; +export * from "./withdraw-rai/withdraw-rai"; diff --git a/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts b/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts new file mode 100644 index 000000000..c8918cfce --- /dev/null +++ b/src/services/api/handlers/package-actions/issue-rai/issue-rai.ts @@ -0,0 +1,39 @@ +import { RaiIssue, raiIssueSchema, Action, SEATOOL_STATUS } from "shared-types"; +import { seaToolFriendlyTimestamp } from "shared-utils"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; +import { type PackageActionWriteService } from "../services/package-action-write-service"; + +export async function issueRai( + body: RaiIssue, + packageActionWriteService: PackageActionWriteService = globalThis.packageActionWriteService, +) { + console.log("CMS issuing a new RAI"); + const now = new Date().getTime(); + const today = seaToolFriendlyTimestamp(); + const result = raiIssueSchema.safeParse({ ...body, requestedDate: today }); + if (result.success === false) { + console.error( + "validation error: The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { + message: "Event validation error", + }, + }); + } + + await packageActionWriteService.issueRai({ + ...result.data, + action: Action.ISSUE_RAI, + id: result.data.id, + spwStatus: SEATOOL_STATUS.PENDING_RAI, + today: today, + timestamp: now, + topicName: TOPIC_NAME, + }); +} diff --git a/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts b/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts new file mode 100644 index 000000000..6573d41b4 --- /dev/null +++ b/src/services/api/handlers/package-actions/remove-appk-child/remove-appk-child.ts @@ -0,0 +1,34 @@ +import { + SEATOOL_STATUS, + Action, + removeAppkChildSchema, + opensearch, +} from "shared-types"; +import { seaToolFriendlyTimestamp } from "shared-utils"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; +export async function removeAppkChild(doc: opensearch.main.Document) { + const result = removeAppkChildSchema.safeParse(doc); + + if (!result.success) { + return response({ + statusCode: 400, + body: { + message: "Remove Appk Child event validation error", + }, + }); + } + + const now = new Date().getTime(); + const today = seaToolFriendlyTimestamp(); + + await packageActionWriteService.removeAppkChild({ + ...result.data, + action: Action.REMOVE_APPK_CHILD, + id: result.data.id, + spwStatus: SEATOOL_STATUS.WITHDRAWN, + today: today, + timestamp: now, + topicName: TOPIC_NAME, + }); +} diff --git a/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts new file mode 100644 index 000000000..3fc6c6da2 --- /dev/null +++ b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.test.ts @@ -0,0 +1,71 @@ +import { respondToRai } from "./respond-to-rai"; +import { vi, describe, it, expect, beforeEach } from "vitest"; +import { MockPackageActionWriteService } from "../services/package-action-write-service"; +import { Action, raiResponseSchema } from "shared-types"; +import { generateMock } from "@anatine/zod-mock"; +import { ExtendedItemResult } from "../../../libs/package"; +const mockPackageWrite = new MockPackageActionWriteService(); + +describe("respondToRai", async () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should return a server error response if given bad body", async () => { + const response = await respondToRai( + { hello: "world" }, + { + raiRequestedDate: "999", + raiReceivedDate: "999", + raiWithdrawnDate: "999", + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + }); + + it("should return a 400 when no requested date is sent", async () => { + const mockData = generateMock(raiResponseSchema); + const response = await respondToRai( + mockData, + { + raiRequestedDate: null, + raiReceivedDate: null, + raiWithdrawnDate: null, + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + }); + + it("should return a 400 when a bad requestDate is sent", async () => { + const mockData = generateMock(raiResponseSchema); + const response = await respondToRai( + mockData, + { + raiRequestedDate: "123456789", // should be an isoString + raiReceivedDate: null, + raiWithdrawnDate: null, + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + expect(JSON.parse(response.body).message).toBe("Event validation error"); + }); + + it("should return a 200 when a good payload is sent", async () => { + const packageWriteSpy = vi.spyOn(mockPackageWrite, "respondToRai"); + const mockData = generateMock(raiResponseSchema); + const response = await respondToRai( + mockData, + { + raiRequestedDate: new Date().toISOString(), + raiReceivedDate: null, + raiWithdrawnDate: null, + }, + mockPackageWrite, + ); + expect(packageWriteSpy).toHaveBeenCalledOnce(); + expect(response.statusCode).toBe(200); + }); +}); diff --git a/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts new file mode 100644 index 000000000..0898f0020 --- /dev/null +++ b/src/services/api/handlers/package-actions/respond-to-rai/respond-to-rai.ts @@ -0,0 +1,74 @@ +import { raiResponseSchema, SEATOOL_STATUS, Action } from "shared-types"; +import { seaToolFriendlyTimestamp } from "shared-utils"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; +import { ExtendedItemResult } from "../../../libs/package"; +import { PackageWriteClass } from "../services/package-action-write-service"; + +export async function respondToRai( + body: any, + document: Pick< + ExtendedItemResult["_source"], + "raiReceivedDate" | "raiRequestedDate" | "raiWithdrawnDate" + >, + packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, +) { + console.log("State responding to RAI"); + if (!document.raiRequestedDate) { + return response({ + statusCode: 400, + body: { + message: "No candidate RAI available", + }, + }); + } + const raiToRespondTo = new Date(document.raiRequestedDate).getTime(); + const now = new Date().getTime(); + const today = seaToolFriendlyTimestamp(); + const result = raiResponseSchema.safeParse({ + ...body, + responseDate: today, + requestedDate: raiToRespondTo, + }); + if (result.success === false) { + console.error( + "validation error: The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { + message: "Event validation error", + }, + }); + } + try { + await packageActionWriteService.respondToRai({ + ...result.data, + action: Action.RESPOND_TO_RAI, + id: result.data.id, + raiReceivedDate: document.raiReceivedDate!, + raiToRespondTo: raiToRespondTo, + raiWithdrawnDate: document.raiWithdrawnDate!, + responseDate: today, + spwStatus: SEATOOL_STATUS.PENDING, + today, + timestamp: now, + topicName: TOPIC_NAME, + }); + return response({ + statusCode: 200, + body: { + message: "record successfully submitted", + }, + }); + } catch (err) { + console.log(err); + + return response({ + statusCode: 500, + }); + } +} diff --git a/src/services/api/handlers/package-actions/services/mako-write-service.ts b/src/services/api/handlers/package-actions/services/mako-write-service.ts new file mode 100644 index 000000000..e04aa28b9 --- /dev/null +++ b/src/services/api/handlers/package-actions/services/mako-write-service.ts @@ -0,0 +1,196 @@ +import { type Action } from "shared-types"; +import { getNextBusinessDayTimestamp } from "shared-utils"; + +export type MessageProducer = ( + topic: string, + key: string, + value: string, +) => Promise; + +export type CompleteIntakeDto = { + topicName: string; + id: string; + action: Action; + timestamp: number; +} & Record; + +export type IssueRaiDto = { + topicName: string; + id: string; + action: Action; +} & Record; + +export type RespondToRaiDto = { + topicName: string; + id: string; + action: Action; + responseDate: number; +} & Record; + +export type ToggleRaiResponseDto = { + topicName: string; + id: string; + action: Action; +} & Record; + +export type WithdrawRaiDto = { + topicName: string; + id: string; + action: Action; +} & Record; + +export type RemoveAppkChildDto = { + topicName: string; + id: string; + action: Action; +} & Record; + +export type WithdrawPackageDto = { + topicName: string; + id: string; + action: Action; +} & Record; + +export class MakoWriteService { + #messageProducer: MessageProducer; + + constructor(messageProducer: MessageProducer) { + this.#messageProducer = messageProducer; + } + + async completeIntake({ + action, + id, + timestamp, + topicName, + ...data + }: CompleteIntakeDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + actionType: action, + timestamp, + ...data, + }), + ); + } + + async issueRai({ action, id, topicName, ...data }: IssueRaiDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + } + + async respondToRai({ + action, + id, + responseDate, + topicName, + ...data + }: RespondToRaiDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + responseDate, + actionType: action, + notificationMetadata: { + submissionDate: getNextBusinessDayTimestamp(), + }, + }), + ); + } + + async withdrawRai({ action, id, topicName, ...data }: WithdrawRaiDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + actionType: action, + notificationMetadata: { + submissionDate: getNextBusinessDayTimestamp(), + }, + }), + ); + } + + async toggleRaiResponseWithdraw({ + action, + id, + topicName, + ...data + }: ToggleRaiResponseDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + } + + async removeAppkChild({ + action, + id, + topicName, + ...data + }: RemoveAppkChildDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + } + + async withdrawPackage({ + action, + id, + topicName, + ...data + }: WithdrawPackageDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + } + + async updateId({ action, id, topicName, ...data }: UpdateIdDto) { + await this.#messageProducer( + topicName, + id, + JSON.stringify({ + ...data, + id, + actionType: action, + }), + ); + } +} + +export type UpdateIdDto = { + topicName: string; + id: string; + action: Action; +} & Record; diff --git a/src/services/api/handlers/package-actions/services/package-action-write-service.ts b/src/services/api/handlers/package-actions/services/package-action-write-service.ts new file mode 100644 index 000000000..060d795f0 --- /dev/null +++ b/src/services/api/handlers/package-actions/services/package-action-write-service.ts @@ -0,0 +1,367 @@ +import { Action } from "shared-types"; +import { + MakoWriteService, + IssueRaiDto as MakoIssueRaiDto, + CompleteIntakeDto as MakoCompleteIntake, + RespondToRaiDto as MakoRespondToRai, + WithdrawRaiDto as MakoWithdrawRai, + ToggleRaiResponseDto, + RemoveAppkChildDto as MakoRemoveAppkChild, + WithdrawPackageDto as MakoWithdrawPackage, + UpdateIdDto as MakoUpdateId, +} from "./mako-write-service"; +import { + SeatoolWriteService, + IssueRaiDto as SeaIssueRaiDto, + CompleteIntakeDto as SeaCompleteIntake, + RespondToRaiDto as SeaRespondToRai, + WithdrawRaiDto as SeaWithdrawRai, + RemoveAppkChildDto as SeaRemoveAppkChild, + WithdrawPackageDto as SeaWithdrawPackage, + UpdateIdDto as SeaUpdateId, +} from "./seatool-write-service"; + +type IdsToUpdateFunction = (lookupId: string) => Promise; + +export type CompleteIntakeDto = MakoCompleteIntake & SeaCompleteIntake; +export type IssueRaiDto = SeaIssueRaiDto & MakoIssueRaiDto; +export type RespondToRaiDto = SeaRespondToRai & MakoRespondToRai; +export type WithdrawRaiDto = SeaWithdrawRai & MakoWithdrawRai; +export type RemoveAppkChildDto = SeaRemoveAppkChild & MakoRemoveAppkChild; +export type WithdrawPackageDto = SeaWithdrawPackage & MakoWithdrawPackage; +export type UpdateIdDto = SeaUpdateId & MakoUpdateId; + +export type PackageWriteClass = { + completeIntake: (data: CompleteIntakeDto) => Promise; + issueRai: (data: IssueRaiDto) => Promise; + respondToRai: (data: RespondToRaiDto) => Promise; + withdrawRai: (data: WithdrawRaiDto) => Promise; + toggleRaiResponseWithdraw: (data: ToggleRaiResponseDto) => Promise; + removeAppkChild: (data: RemoveAppkChildDto) => Promise; + withdrawPackage: (data: WithdrawPackageDto) => Promise; + updateId: (data: UpdateIdDto) => Promise; +}; + +export class MockPackageActionWriteService implements PackageWriteClass { + async issueRai(data: IssueRaiDto) { + console.log("hello"); + } + async respondToRai(data: RespondToRaiDto) { + console.log("hello"); + } + async withdrawRai(data: WithdrawRaiDto) { + console.log("hello"); + } + async toggleRaiResponseWithdraw(data: ToggleRaiResponseDto) { + console.log("hello"); + } + async removeAppkChild(data: RemoveAppkChildDto) { + console.log("hello"); + } + async withdrawPackage(data: WithdrawPackageDto) { + console.log("hello"); + } + async updateId(data: UpdateIdDto) { + console.log("hello"); + } + async completeIntake(data: CompleteIntakeDto) { + console.log("hello"); + } +} + +export class PackageActionWriteService implements PackageWriteClass { + #seatoolWriteService: SeatoolWriteService; + #makoWriteService: MakoWriteService; + #getIdsToUpdate: IdsToUpdateFunction; + + constructor( + seatool: SeatoolWriteService, + mako: MakoWriteService, + idsToUpdateFunction: IdsToUpdateFunction, + ) { + this.#makoWriteService = mako; + this.#seatoolWriteService = seatool; + this.#getIdsToUpdate = idsToUpdateFunction; + } + + async completeIntake({ + action, + cpoc, + description, + id, + subTypeIds, + subject, + submitterName, + timestamp, + topicName, + typeIds, + ...data + }: CompleteIntakeDto) { + try { + await this.#seatoolWriteService.trx.begin(); + await this.#seatoolWriteService.completeIntake({ + typeIds, + subTypeIds, + id, + cpoc, + description, + subject, + submitterName, + }); + await this.#makoWriteService.completeIntake({ + action, + id, + timestamp, + topicName, + ...data, + }); + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + console.log("AN ERROR OCCURED: ", err); + this.#seatoolWriteService.trx.rollback(); + } + } + + async issueRai({ + action, + id, + spwStatus, + today, + timestamp, + topicName, + ...data + }: IssueRaiDto) { + try { + await this.#seatoolWriteService.trx.begin(); + const idsToUpdate = await this.#getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await this.#seatoolWriteService.issueRai({ id, spwStatus, today }); + await this.#makoWriteService.issueRai({ + action, + id, + timestamp, + topicName, + ...data, + }); + } + + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + await this.#seatoolWriteService.trx.rollback(); + + console.error(err); + } + } + + async respondToRai({ + action, + id, + raiReceivedDate, + raiToRespondTo, + raiWithdrawnDate, + responseDate, + spwStatus, + today, + timestamp, + topicName, + ...data + }: RespondToRaiDto) { + try { + await this.#seatoolWriteService.trx.begin(); + const idsToUpdate = await this.#getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await this.#seatoolWriteService.respondToRai({ + id, + spwStatus, + today, + raiReceivedDate, + raiToRespondTo, + raiWithdrawnDate, + }); + await this.#makoWriteService.respondToRai({ + action, + id, + topicName, + timestamp, + responseDate, + ...data, + }); + } + + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + await this.#seatoolWriteService.trx.rollback(); + + console.error(err); + } + } + + async withdrawRai({ + id, + spwStatus, + today, + timestamp, + raiReceivedDate, + raiToWithdraw, + raiRequestedDate, + action, + topicName, + withdrawnDate, + ...data + }: WithdrawRaiDto) { + try { + await this.#seatoolWriteService.trx.begin(); + const idsToUpdate = await this.#getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await this.#seatoolWriteService.withdrawRai({ + id, + spwStatus, + today, + raiReceivedDate, + raiToWithdraw, + raiRequestedDate, + }); + await this.#makoWriteService.withdrawRai({ + action, + id, + topicName, + timestamp, + withdrawnDate, + ...data, + }); + } + + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + await this.#seatoolWriteService.trx.rollback(); + + console.error(err); + } + } + + async toggleRaiResponseWithdraw(data: ToggleRaiResponseDto) { + try { + const idsToUpdate = await this.#getIdsToUpdate(data.id); + + for (const id of idsToUpdate) { + await this.#makoWriteService.toggleRaiResponseWithdraw({ + ...data, + id, + }); + } + } catch (err: unknown) { + console.error(err); + } + } + + async removeAppkChild({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + ...data + }: RemoveAppkChildDto) { + try { + await this.#seatoolWriteService.trx.begin(); + const idsToUpdate = [id]; + + for (const id of idsToUpdate) { + await this.#seatoolWriteService.removeAppkChild({ + id, + spwStatus, + today, + }); + await this.#makoWriteService.removeAppkChild({ + action, + id, + topicName, + timestamp, + ...data, + }); + } + + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + await this.#seatoolWriteService.trx.rollback(); + + console.error(err); + } + } + + async withdrawPackage({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + ...data + }: WithdrawPackageDto) { + try { + await this.#seatoolWriteService.trx.begin(); + const idsToUpdate = await this.#getIdsToUpdate(id); + + for (const id of idsToUpdate) { + await this.#seatoolWriteService.withdrawPackage({ + id, + spwStatus, + today, + }); + await this.#makoWriteService.withdrawPackage({ + action, + id, + topicName, + timestamp, + ...data, + }); + } + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + await this.#seatoolWriteService.trx.rollback(); + + console.error(err); + } + } + + async updateId({ + id, + timestamp, + today, + spwStatus, + action, + topicName, + newId, + ...data + }: UpdateIdDto) { + try { + await this.#seatoolWriteService.trx.begin(); + const idsToUpdate = [id]; + + for (const id of idsToUpdate) { + await this.#seatoolWriteService.updateId({ + id, + spwStatus, + today, + newId, + }); + await this.#makoWriteService.updateId({ + action, + id, + timestamp, + topicName, + ...data, + }); + } + await this.#seatoolWriteService.trx.commit(); + } catch (err: unknown) { + await this.#seatoolWriteService.trx.rollback(); + + console.error(err); + } + } +} diff --git a/src/services/api/handlers/package-actions/services/seatool-write-service.ts b/src/services/api/handlers/package-actions/services/seatool-write-service.ts new file mode 100644 index 000000000..06d23151c --- /dev/null +++ b/src/services/api/handlers/package-actions/services/seatool-write-service.ts @@ -0,0 +1,311 @@ +import { ConnectionPool, Transaction, config, connect } from "mssql"; +import { buildStatusMemoQuery } from "../../../libs/statusMemo"; +import { formatSeatoolDate } from "shared-utils"; + +export type CompleteIntakeDto = { + id: string; + typeIds: number[]; + subTypeIds: number[]; + subject: string; + description: string; + cpoc: number; + submitterName: string; +}; + +export type IssueRaiDto = { + id: string; + today: number; + spwStatus: string; +}; + +export type RespondToRaiDto = { + id: string; + raiReceivedDate: string; + raiWithdrawnDate: string; + today: number; + raiToRespondTo: number; + spwStatus: string; +}; + +export type WithdrawRaiDto = { + id: string; + today: number; + raiToWithdraw: number; + spwStatus: string; + raiRequestedDate: string; + raiReceivedDate: string; +}; + +export type RemoveAppkChildDto = { + id: string; + today: number; + spwStatus: string; +}; + +export type WithdrawPackageDto = { + id: string; + today: number; + spwStatus: string; +}; + +export type UpdateIdDto = { + id: string; + today: number; + spwStatus: string; + newId: string; +}; + +export class SeatoolWriteService { + #pool: ConnectionPool; + trx: Transaction; + + constructor(pool: ConnectionPool) { + this.#pool = pool; + this.trx = new Transaction(pool); + } + + public static async createSeatoolService(config: config) { + const pool = await connect(config); + + return new SeatoolWriteService(pool); + } + + async completeIntake({ + typeIds, + subTypeIds, + id, + cpoc, + description, + subject, + submitterName, + }: CompleteIntakeDto) { + // Generate INSERT statements for typeIds + const typeIdsValues = typeIds + .map((typeId: number) => `('${id}', '${typeId}')`) + .join(",\n"); + const typeIdsInsert = typeIdsValues + ? `INSERT INTO SEA.dbo.State_Plan_Service_Types (ID_Number, Service_Type_ID) VALUES ${typeIdsValues};` + : ""; + + // Generate INSERT statements for subTypeIds + const subTypeIdsValues = subTypeIds + .map((subTypeId: number) => `('${id}', '${subTypeId}')`) + .join(",\n"); + + const subTypeIdsInsert = subTypeIdsValues + ? `INSERT INTO SEA.dbo.State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) VALUES ${subTypeIdsValues};` + : ""; + + await this.trx.request().query(` + UPDATE SEA.dbo.State_Plan + SET + Title_Name = ${subject ? `'${subject.replace("'", "''")}'` : "NULL"}, + Summary_Memo = ${ + description ? `'${description.replace("'", "''")}'` : "NULL" + }, + Lead_Analyst_ID = ${cpoc ? cpoc : "NULL"}, + Status_Memo = ${buildStatusMemoQuery(id, `Intake Completed: Intake was completed by ${submitterName}`)} + WHERE ID_Number = '${id}' + + -- Insert all types into State_Plan_Service_Types + ${typeIdsInsert} + + -- Insert all types into State_Plan_Service_SubTypes + ${subTypeIdsInsert} + `); + } + + async issueRai({ id, spwStatus, today }: IssueRaiDto) { + // Issue RAI + const query1 = ` + Insert into SEA.dbo.RAI (ID_Number, RAI_Requested_Date) + values ('${id}' + ,dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime))) + `; + await this.trx.request().query(query1); + + // Update Status + const query2 = ` + UPDATE SEA.dbo.State_Plan + SET + SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), + Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), + Status_Memo = ${buildStatusMemoQuery(id, "RAI Issued")} + WHERE ID_Number = '${id}' + `; + await this.trx.request().query(query2); + } + + async respondToRai({ + id, + raiReceivedDate, + raiWithdrawnDate, + today, + raiToRespondTo, + spwStatus, + }: RespondToRaiDto) { + let statusMemoUpdate = ""; + if (raiReceivedDate && raiWithdrawnDate) { + statusMemoUpdate = buildStatusMemoQuery( + id, + `RAI Response Received. This overwrites the previous response received on ${formatSeatoolDate(raiReceivedDate)} and withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, + ); + } else if (raiWithdrawnDate) { + statusMemoUpdate = buildStatusMemoQuery( + id, + `RAI Response Received. This overwrites a previous response withdrawn on ${formatSeatoolDate(raiWithdrawnDate)}`, + ); + } else { + statusMemoUpdate = buildStatusMemoQuery(id, "RAI Response Received"); + } + + // Respond to RAI + const query1 = ` + UPDATE SEA.dbo.RAI + SET + RAI_RECEIVED_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)), + RAI_WITHDRAWN_DATE = NULL + WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToRespondTo}', 10)), CAST('19700101' AS DATETIME)) + `; + const result1 = await this.trx.request().query(query1); + console.log(result1); + + // Update Status + const query2 = ` + UPDATE SEA.dbo.State_Plan + SET + SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), + Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), + Status_Memo = ${statusMemoUpdate} + WHERE ID_Number = '${id}' + `; + const result2 = await this.trx.request().query(query2); + console.log(result2); + } + + async withdrawRai({ + id, + today, + raiToWithdraw, + spwStatus, + raiRequestedDate, + raiReceivedDate, + }: WithdrawRaiDto) { + await this.trx.request().query(` + UPDATE SEA.dbo.RAI + SET + RAI_WITHDRAWN_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)) + WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToWithdraw}', 10)), CAST('19700101' AS DATETIME)) + `); + // Set Status to Pending - RAI + await this.trx.request().query(` + UPDATE SEA.dbo.State_Plan + SET + SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), + Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), + Status_Memo = ${buildStatusMemoQuery( + id, + `RAI Response Withdrawn. This withdrawal is for the RAI requested on ${formatSeatoolDate(raiRequestedDate)} and received on ${formatSeatoolDate(raiReceivedDate)}`, + )} + WHERE ID_Number = '${id}' + `); + } + + async removeAppkChild({ id, today, spwStatus }: RemoveAppkChildDto) { + await this.trx.request().query(` + UPDATE SEA.dbo.State_Plan + SET + SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), + Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), + Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} + WHERE ID_Number = '${id}' + `); + } + + async withdrawPackage({ id, today, spwStatus }: WithdrawPackageDto) { + const query = ` + UPDATE SEA.dbo.State_Plan + SET + SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), + Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), + Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} + WHERE ID_Number = '${id}' + `; + await this.trx.request().query(query); + } + + async updateId({ id, today, spwStatus, newId }: UpdateIdDto) { + await this.trx.request().query( + ` + DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @newId NVARCHAR(50), @originalId NVARCHAR(50); + + SET @newId = '${newId}'; + SET @originalId = '${id}'; + + SELECT @columns = COALESCE(@columns + ', ', '') + QUOTENAME(column_name) + FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'State_Plan' AND column_name != 'ID_Number' AND column_name != 'UUID' AND column_name != 'replica_id' AND table_schema = 'dbo' + ORDER BY ordinal_position; + + SET @sql = 'INSERT INTO SEA.dbo.State_Plan (ID_Number, ' + @columns + ') SELECT ''' + @newId + ''' as ID_Number, ' + @columns + ' FROM SEA.dbo.State_Plan WHERE ID_Number = ''' + @originalId + ''''; + EXEC sp_executesql @sql; + `, + ); + + await this.trx.request().query( + ` + INSERT INTO RAI (ID_Number, RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE) + SELECT '${newId}', RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE + FROM RAI + WHERE ID_Number = '${id}'; + `, + ); + + await this.trx.request().query( + ` + INSERT INTO State_Plan_Service_Types (ID_Number, Service_Type_ID) + SELECT '${newId}', Service_Type_ID + FROM State_Plan_Service_Types + WHERE ID_Number = '${id}'; + `, + ); + + await this.trx.request().query( + ` + INSERT INTO State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) + SELECT '${newId}', Service_SubType_ID + FROM State_Plan_Service_SubTypes + WHERE ID_Number = '${id}'; + `, + ); + + await this.trx.request().query( + ` + INSERT INTO Action_Officers (ID_Number, Officer_ID) + SELECT '${newId}', Officer_ID + FROM Action_Officers + WHERE ID_Number = '${id}'; + `, + ); + + await this.trx.request().query( + ` + UPDATE SEA.dbo.State_Plan + SET + SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${spwStatus}'), + Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), + Status_Memo = ${buildStatusMemoQuery(id, `Package Terminated via ID Update: this package was copied to ${newId} and then terminated.`)} + WHERE ID_Number = '${id}' + `, + ); + + await this.trx.request().query( + ` + UPDATE SEA.dbo.State_Plan + SET + Status_Memo = ${buildStatusMemoQuery(id, `Package Created via ID Update: this package was copied from ${id}.`)} + WHERE ID_Number = '${newId}' + `, + ); + } +} diff --git a/src/services/api/handlers/package-actions/setup-write-service.ts b/src/services/api/handlers/package-actions/setup-write-service.ts new file mode 100644 index 000000000..1a5691e67 --- /dev/null +++ b/src/services/api/handlers/package-actions/setup-write-service.ts @@ -0,0 +1,13 @@ +import { produceMessage } from "../../libs/kafka"; +import { config } from "./consts"; +import { getIdsToUpdate } from "./get-id-to-update"; +import { MakoWriteService } from "./services/mako-write-service"; +import { PackageActionWriteService } from "./services/package-action-write-service"; +import { SeatoolWriteService } from "./services/seatool-write-service"; + +export const setupWriteService = async () => { + const seatool = await SeatoolWriteService.createSeatoolService(config); + const mako = new MakoWriteService(produceMessage); + + return new PackageActionWriteService(seatool, mako, getIdsToUpdate); +}; diff --git a/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts new file mode 100644 index 000000000..16dd315ad --- /dev/null +++ b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.test.ts @@ -0,0 +1,68 @@ +import { toggleRaiResponseWithdraw } from "./toggle-rai-response-withdraw"; +import { vi, describe, it, expect, beforeEach } from "vitest"; +import { MockPackageActionWriteService } from "../services/package-action-write-service"; +import { Action, toggleWithdrawRaiEnabledSchema } from "shared-types"; +import { generateMock } from "@anatine/zod-mock"; +const mockPackageWrite = new MockPackageActionWriteService(); + +describe("toggleRaiResponseWithdraw", async () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should return a server error response if given bad body", async () => { + const toggleRaiWithdraw = await toggleRaiResponseWithdraw( + { hello: "world" }, + true, + mockPackageWrite, + ); + + expect(toggleRaiWithdraw.statusCode).toBe(400); + }); + + it("package write is called when valid data is passed and 200 status code is returned", async () => { + const packageWriteSpy = vi.spyOn( + mockPackageWrite, + "toggleRaiResponseWithdraw", + ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); + const toggleRaiWithdraw = await toggleRaiResponseWithdraw( + mockData, + true, + mockPackageWrite, + ); + + expect(packageWriteSpy).toHaveBeenCalledOnce(); + expect(toggleRaiWithdraw.statusCode).toBe(200); + }); + + it("calls package write service with action set to Enable RAI when toggle set to true", async () => { + const packageWriteSpy = vi.spyOn( + mockPackageWrite, + "toggleRaiResponseWithdraw", + ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); + await toggleRaiResponseWithdraw(mockData, true, mockPackageWrite); + + expect(packageWriteSpy).toHaveBeenCalledWith( + expect.objectContaining({ + action: Action.ENABLE_RAI_WITHDRAW, + }), + ); + }); + + it("calls package write service with action set to Disable RAI when toggle set to false", async () => { + const packageWriteSpy = vi.spyOn( + mockPackageWrite, + "toggleRaiResponseWithdraw", + ); + const mockData = generateMock(toggleWithdrawRaiEnabledSchema); + await toggleRaiResponseWithdraw(mockData, false, mockPackageWrite); + + expect(packageWriteSpy).toHaveBeenCalledWith( + expect.objectContaining({ + action: Action.DISABLE_RAI_WITHDRAW, + }), + ); + }); +}); diff --git a/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts new file mode 100644 index 000000000..d2fbf64c7 --- /dev/null +++ b/src/services/api/handlers/package-actions/toggle-rai-response-withdraw/toggle-rai-response-withdraw.ts @@ -0,0 +1,52 @@ +import { toggleWithdrawRaiEnabledSchema, Action } from "shared-types"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; +import { PackageWriteClass } from "../services/package-action-write-service"; + +export async function toggleRaiResponseWithdraw( + body: any, + toggle: boolean, + packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, +) { + const now = new Date().getTime(); + const result = toggleWithdrawRaiEnabledSchema.safeParse({ + ...body, + raiWithdrawEnabled: toggle, + }); + if (result.success === false) { + console.error( + "Toggle Rai Response Withdraw Enable event validation error. The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { + message: "Toggle Rai Response Withdraw Enable event validation error", + }, + }); + } + try { + await packageActionWriteService.toggleRaiResponseWithdraw({ + ...result.data, + action: toggle ? Action.ENABLE_RAI_WITHDRAW : Action.DISABLE_RAI_WITHDRAW, + id: result.data.id, + topicName: TOPIC_NAME, + timestamp: now, + }); + + return response({ + statusCode: 200, + body: { + message: "record successfully submitted", + }, + }); + } catch (err) { + console.log(err); + + return response({ + statusCode: 500, + }); + } +} diff --git a/src/services/api/handlers/package-actions/update-id/update-id.ts b/src/services/api/handlers/package-actions/update-id/update-id.ts new file mode 100644 index 000000000..6c99d4f3b --- /dev/null +++ b/src/services/api/handlers/package-actions/update-id/update-id.ts @@ -0,0 +1,37 @@ +import { updateIdSchema, SEATOOL_STATUS, Action } from "shared-types"; +import { seaToolFriendlyTimestamp } from "shared-utils"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; + +export async function updateId(body: any) { + console.log("CMS updating the ID of a package."); + const now = new Date().getTime(); + const today = seaToolFriendlyTimestamp(); + const result = updateIdSchema.safeParse(body); + if (!result.success) { + console.error( + "validation error: The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { + message: "Event validation error", + }, + }); + } + console.log(JSON.stringify(result.data, null, 2)); + + await packageActionWriteService.updateId({ + ...result.data, + action: Action.UPDATE_ID, + id: body.id, + newId: result.data.newId, + spwStatus: SEATOOL_STATUS.TERMINATED, + timestamp: now, + today, + topicName: TOPIC_NAME, + }); +} diff --git a/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts b/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts new file mode 100644 index 000000000..e56627073 --- /dev/null +++ b/src/services/api/handlers/package-actions/withdraw-package/withdraw-package.ts @@ -0,0 +1,40 @@ +import { + WithdrawPackage, + withdrawPackageSchema, + SEATOOL_STATUS, + Action, +} from "shared-types"; +import { seaToolFriendlyTimestamp } from "shared-utils"; +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; + +export async function withdrawPackage(body: WithdrawPackage) { + console.log("State withdrawing a package."); + + const now = new Date().getTime(); + const today = seaToolFriendlyTimestamp(); + + const result = withdrawPackageSchema.safeParse(body); + if (result.success === false) { + console.error( + "Withdraw Package event validation error. The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { message: "Withdraw Package event validation error" }, + }); + } + + await packageActionWriteService.withdrawPackage({ + ...result.data, + action: Action.WITHDRAW_PACKAGE, + id: result.data.id, + spwStatus: SEATOOL_STATUS.WITHDRAWN, + timestamp: now, + today, + topicName: TOPIC_NAME, + }); +} diff --git a/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts new file mode 100644 index 000000000..397e235fd --- /dev/null +++ b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.test.ts @@ -0,0 +1,103 @@ +import { withdrawRai } from "./withdraw-rai"; +import { vi, describe, it, expect, beforeEach } from "vitest"; +import { MockPackageActionWriteService } from "../services/package-action-write-service"; +import { Action, raiWithdrawSchema } from "shared-types"; +import { generateMock } from "@anatine/zod-mock"; +import { ExtendedItemResult } from "../../../libs/package"; +const mockPackageWrite = new MockPackageActionWriteService(); + +describe("withdrawRai", async () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it("should return a 400 missing candidate when a requestedDate is missing", async () => { + const response = await withdrawRai( + { hello: "world" }, + { + raiRequestedDate: null, + raiReceivedDate: "asdf", + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + expect(JSON.parse(response.body).message).toBe( + "No candidate RAI available", + ); + }); + + it("should return a 400 missing candidate when a receivedDate is missing", async () => { + const response = await withdrawRai( + { hello: "world" }, + { + raiRequestedDate: "999", + raiReceivedDate: null, + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + expect(JSON.parse(response.body).message).toBe( + "No candidate RAI available", + ); + }); + + it("should return a server error response if given bad body", async () => { + const goodDate = new Date().toISOString(); + const response = await withdrawRai( + { hello: "world" }, + { + raiRequestedDate: goodDate, + raiReceivedDate: goodDate, + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + expect(JSON.parse(response.body).message).toBe("Event validation error"); + }); + + it("should return a 400 when a bad requestDate is sent", async () => { + const goodDate = new Date().toISOString(); + const mockData = generateMock(raiWithdrawSchema); + const response = await withdrawRai( + mockData, + { + raiRequestedDate: "123456789", + raiReceivedDate: goodDate, + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + expect(JSON.parse(response.body).message).toBe("Event validation error"); + }); + + it.skip("should return a 400 when a bad receivedDate is sent", async () => { + const goodDate = new Date().toISOString(); + const mockData = generateMock(raiWithdrawSchema); + const response = await withdrawRai( + mockData, + { + raiRequestedDate: goodDate, + raiReceivedDate: "123456789", + }, + mockPackageWrite, + ); + expect(response.statusCode).toBe(400); + expect(JSON.parse(response.body).message).toBe("Event validation error"); + }); + + it("should return a 200 when a good payload is sent", async () => { + const goodDate = new Date().toISOString(); + const packageWriteSpy = vi.spyOn(mockPackageWrite, "withdrawRai"); + const mockData = generateMock(raiWithdrawSchema); + const response = await withdrawRai( + mockData, + { + raiRequestedDate: goodDate, + raiReceivedDate: goodDate, + }, + mockPackageWrite, + ); + expect(packageWriteSpy).toHaveBeenCalledOnce(); + expect(response.statusCode).toBe(200); + }); +}); diff --git a/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts new file mode 100644 index 000000000..f843ce9a8 --- /dev/null +++ b/src/services/api/handlers/package-actions/withdraw-rai/withdraw-rai.ts @@ -0,0 +1,79 @@ +import { raiWithdrawSchema, SEATOOL_STATUS, Action } from "shared-types"; +import { seaToolFriendlyTimestamp } from "shared-utils"; + +import { response } from "../../../libs/handler"; +import { TOPIC_NAME } from "../consts"; +import { PackageWriteClass } from "../services/package-action-write-service"; +import { ExtendedItemResult } from "../../../libs/package"; + +export async function withdrawRai( + body: any, + document: Pick< + ExtendedItemResult["_source"], + "raiReceivedDate" | "raiRequestedDate" + >, + packageActionWriteService: PackageWriteClass = globalThis.packageActionWriteService, +) { + console.log("State withdrawing an RAI Response"); + + if (!document.raiRequestedDate || !document.raiReceivedDate) { + return response({ + statusCode: 400, + body: { + message: "No candidate RAI available", + }, + }); + } + + const raiToWithdraw = new Date(document.raiRequestedDate).getTime(); + + const now = new Date().getTime(); + const today = seaToolFriendlyTimestamp(); + + const result = raiWithdrawSchema.safeParse({ + ...body, + requestedDate: raiToWithdraw, + withdrawnDate: today, + }); + if (result.success === false) { + console.error( + "validation error: The following record failed to parse: ", + JSON.stringify(body), + "Because of the following Reason(s):", + result.error.message, + ); + return response({ + statusCode: 400, + body: { + message: "Event validation error", + }, + }); + } + + try { + await packageActionWriteService.withdrawRai({ + ...result.data, + action: Action.WITHDRAW_RAI, + id: result.data.id, + spwStatus: SEATOOL_STATUS.PENDING_RAI, + timestamp: now, + today, + topicName: TOPIC_NAME, + raiToWithdraw, + raiRequestedDate: document.raiRequestedDate, + raiReceivedDate: document.raiReceivedDate, + }); + return response({ + statusCode: 200, + body: { + message: "record successfully submitted", + }, + }); + } catch (err) { + console.log(err); + + return response({ + statusCode: 500, + }); + } +} diff --git a/src/services/api/handlers/packageActions.ts b/src/services/api/handlers/packageActions.ts deleted file mode 100644 index ebda184d9..000000000 --- a/src/services/api/handlers/packageActions.ts +++ /dev/null @@ -1,737 +0,0 @@ -import * as sql from "mssql"; - -const user = process.env.dbUser; -const password = process.env.dbPassword; -const server = process.env.dbIp; -const port = parseInt(process.env.dbPort as string); -const config = { - user: user, - password: password, - server: server, - port: port, - database: "SEA", -} as sql.config; - -import { - Action, - raiIssueSchema, - RaiIssue, - raiResponseSchema, - RaiResponse, - raiWithdrawSchema, - RaiWithdraw, - withdrawPackageSchema, - WithdrawPackage, - toggleWithdrawRaiEnabledSchema, - ToggleWithdrawRaiEnabled, - removeAppkChildSchema, - opensearch, - updateIdSchema, - completeIntakeSchema, -} from "shared-types"; -import { produceMessage } from "../libs/kafka"; -import { response } from "../libs/handler"; -import { SEATOOL_STATUS } from "shared-types/statusHelper"; -import { - formatSeatoolDate, - seaToolFriendlyTimestamp, - getNextBusinessDayTimestamp, -} from "shared-utils"; -import { buildStatusMemoQuery } from "../libs/statusMemo"; -import { getAppkChildren } from "../libs/package"; -import { getItem } from "libs"; - -const TOPIC_NAME = process.env.topicName as string; - -export async function issueRai(body: RaiIssue) { - console.log("CMS issuing a new RAI"); - const today = seaToolFriendlyTimestamp(); - const result = raiIssueSchema.safeParse({ ...body, requestedDate: today }); - if (result.success === false) { - console.error( - "validation error: The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { - message: "Event validation error", - }, - }); - } - - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - try { - await transaction.begin(); - - const idsToUpdate = await getIdsToUpdate(result.data.id); - console.log(idsToUpdate); - console.log("ASDFASDFASDF"); - for (const id of idsToUpdate) { - // Issue RAI - const query1 = ` - Insert into SEA.dbo.RAI (ID_Number, RAI_Requested_Date) - values ('${id}' - ,dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime))) - `; - const result1 = await transaction.request().query(query1); - console.log(result1); - - // Update Status - const query2 = ` - UPDATE SEA.dbo.State_Plan - SET - SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${ - SEATOOL_STATUS.PENDING_RAI - }'), - Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), - Status_Memo = ${buildStatusMemoQuery(id, "RAI Issued")} - WHERE ID_Number = '${id}' - `; - const result2 = await transaction.request().query(query2); - console.log(result2); - - // write to kafka here - await produceMessage( - TOPIC_NAME, - id, - JSON.stringify({ - ...result.data, - id, - actionType: Action.ISSUE_RAI, - }), - ); - } - // Commit transaction - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error(err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } -} - -export async function withdrawRai(body: RaiWithdraw, document: any) { - console.log("State withdrawing an RAI Response"); - if (!document.raiRequestedDate) { - return response({ - statusCode: 400, - body: { - message: "No candidate RAI available", - }, - }); - } - const raiToWithdraw = new Date(document.raiRequestedDate).getTime(); - const today = seaToolFriendlyTimestamp(); - const result = raiWithdrawSchema.safeParse({ - ...body, - requestedDate: raiToWithdraw, - withdrawnDate: today, - }); - if (result.success === false) { - console.error( - "validation error: The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { - message: "Event validation error", - }, - }); - } - console.log("LATEST RAI KEY: " + raiToWithdraw); - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - try { - await transaction.begin(); - - const idsToUpdate = await getIdsToUpdate(result.data.id); - for (const id of idsToUpdate) { - // Set Received Date - await transaction.request().query(` - UPDATE SEA.dbo.RAI - SET - RAI_WITHDRAWN_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)) - WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToWithdraw}', 10)), CAST('19700101' AS DATETIME)) - `); - // Set Status to Pending - RAI - await transaction.request().query(` - UPDATE SEA.dbo.State_Plan - SET - SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${SEATOOL_STATUS.PENDING_RAI}'), - Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), - Status_Memo = ${buildStatusMemoQuery( - id, - `RAI Response Withdrawn. This withdrawal is for the RAI requested on ${formatSeatoolDate(document.raiRequestedDate)} and received on ${formatSeatoolDate(document.raiReceivedDate)}`, - )} - WHERE ID_Number = '${id}' - `); - - await produceMessage( - TOPIC_NAME, - id, - JSON.stringify({ - ...result.data, - id, - actionType: Action.WITHDRAW_RAI, - notificationMetadata: { - submissionDate: getNextBusinessDayTimestamp(), - }, - }), - ); - } - - // Commit transaction - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error(err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } -} - -export async function respondToRai(body: RaiResponse, document: any) { - console.log("State responding to RAI"); - if (!document.raiRequestedDate) { - return response({ - statusCode: 400, - body: { - message: "No candidate RAI available", - }, - }); - } - const raiToRespondTo = new Date(document.raiRequestedDate).getTime(); - const today = seaToolFriendlyTimestamp(); - const result = raiResponseSchema.safeParse({ - ...body, - responseDate: today, - requestedDate: raiToRespondTo, - }); - if (result.success === false) { - console.error( - "validation error: The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { - message: "Event validation error", - }, - }); - } - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - let statusMemoUpdate: string; - - // Potentially overwriting data... will be as verbose as possible. - if (document.raiReceivedDate && document.raiWithdrawnDate) { - statusMemoUpdate = buildStatusMemoQuery( - result.data.id, - `RAI Response Received. This overwrites the previous response received on ${formatSeatoolDate(document.raiReceivedDate)} and withdrawn on ${formatSeatoolDate(document.raiWithdrawnDate)}`, - ); - } else if (document.raiWithdrawnDate) { - statusMemoUpdate = buildStatusMemoQuery( - result.data.id, - `RAI Response Received. This overwrites a previous response withdrawn on ${formatSeatoolDate(document.raiWithdrawnDate)}`, - ); - } else { - statusMemoUpdate = buildStatusMemoQuery(body.id, "RAI Response Received"); - } - try { - await transaction.begin(); - - const idsToUpdate = await getIdsToUpdate(result.data.id); - for (const id of idsToUpdate) { - // Issue RAI - const query1 = ` - UPDATE SEA.dbo.RAI - SET - RAI_RECEIVED_DATE = DATEADD(s, CONVERT(int, LEFT('${today}', 10)), CAST('19700101' AS DATETIME)), - RAI_WITHDRAWN_DATE = NULL - WHERE ID_Number = '${id}' AND RAI_REQUESTED_DATE = DATEADD(s, CONVERT(int, LEFT('${raiToRespondTo}', 10)), CAST('19700101' AS DATETIME)) - `; - const result1 = await transaction.request().query(query1); - console.log(result1); - - // Update Status - const query2 = ` - UPDATE SEA.dbo.State_Plan - SET - SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${SEATOOL_STATUS.PENDING}'), - Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), - Status_Memo = ${statusMemoUpdate} - WHERE ID_Number = '${id}' - `; - const result2 = await transaction.request().query(query2); - console.log(result2); - - // Write to kafka here - console.log(JSON.stringify(result, null, 2)); - await produceMessage( - TOPIC_NAME, - id, - JSON.stringify({ - ...result.data, - id, - responseDate: today, - actionType: Action.RESPOND_TO_RAI, - notificationMetadata: { - submissionDate: getNextBusinessDayTimestamp(), - }, - }), - ); - } - - // Commit transaction - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error(err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } -} - -export async function withdrawPackage(body: WithdrawPackage) { - console.log("State withdrawing a package."); - // Check incoming data - const result = withdrawPackageSchema.safeParse(body); - if (result.success === false) { - console.error( - "Withdraw Package event validation error. The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { message: "Withdraw Package event validation error" }, - }); - } - // Begin query (data is confirmed) - const today = seaToolFriendlyTimestamp(); - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - - try { - await transaction.begin(); - const idsToUpdate = await getIdsToUpdate(result.data.id); - for (const id of idsToUpdate) { - const query = ` - UPDATE SEA.dbo.State_Plan - SET - SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${ - SEATOOL_STATUS.WITHDRAWN - }'), - Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), - Status_Memo = ${buildStatusMemoQuery(id, "Package Withdrawn")} - WHERE ID_Number = '${id}' - `; - const txnResult = await transaction.request().query(query); - console.log(txnResult); - - await produceMessage( - TOPIC_NAME, - id, - JSON.stringify({ - ...result.data, - id, - actionType: Action.WITHDRAW_PACKAGE, - }), - ); - } - // Commit transaction - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error("Error executing query:", err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } -} - -export async function toggleRaiResponseWithdraw( - body: ToggleWithdrawRaiEnabled, - toggle: boolean, -) { - const result = toggleWithdrawRaiEnabledSchema.safeParse({ - ...body, - raiWithdrawEnabled: toggle, - }); - if (result.success === false) { - console.error( - "Toggle Rai Response Withdraw Enable event validation error. The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { - message: "Toggle Rai Response Withdraw Enable event validation error", - }, - }); - } - try { - const idsToUpdate = await getIdsToUpdate(result.data.id); - for (const id of idsToUpdate) { - await produceMessage( - TOPIC_NAME, - id, - JSON.stringify({ - actionType: toggle - ? Action.ENABLE_RAI_WITHDRAW - : Action.DISABLE_RAI_WITHDRAW, - ...result.data, - id, - }), - ); - } - - return response({ - statusCode: 200, - body: { - message: "record successfully submitted", - }, - }); - } catch (err) { - console.log(err); - - return response({ - statusCode: 500, - }); - } -} - -export async function removeAppkChild(doc: opensearch.main.Document) { - const result = removeAppkChildSchema.safeParse(doc); - - if (!result.success) { - return response({ - statusCode: 400, - body: { - message: "Remove Appk Child event validation error", - }, - }); - } - - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - const today = seaToolFriendlyTimestamp(); - - try { - await transaction.begin(); - - await transaction.request().query(` - UPDATE SEA.dbo.State_Plan - SET - SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${SEATOOL_STATUS.WITHDRAWN}'), - Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), - Status_Memo = ${buildStatusMemoQuery( - result.data.id, - "Package Withdrawn", - )} - WHERE ID_Number = '${doc.id}' - `); - await produceMessage( - TOPIC_NAME, - doc.id, - JSON.stringify({ - actionType: Action.REMOVE_APPK_CHILD, - ...result.data, - }), - ); - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error("Error executing query:", err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } -} - -async function getIdsToUpdate(id: string) { - console.log(process.env.osDomain); - console.log(id); - const og = (await getItem( - process.env.osDomain!, - "main", - id, - )) as opensearch.main.ItemResult; - if (!og) { - throw "Package doesn't exist, and it should."; - } - console.log(JSON.stringify(og, null, 2)); - const idsToUpdate = [og._id]; - if (og._source.appkParent) { - const children = await getAppkChildren(og._id); - children.hits?.hits?.forEach((child) => { - idsToUpdate.push(child._id); - }); - } - return idsToUpdate; -} - -export async function updateId(body: any) { - console.log("CMS updating the ID of a package."); - - const result = updateIdSchema.safeParse(body); - if (!result.success) { - console.error( - "validation error: The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { - message: "Event validation error", - }, - }); - } - console.log(JSON.stringify(result.data, null, 2)); - - const now = new Date().getTime(); - const today = seaToolFriendlyTimestamp(); - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - try { - await transaction.begin(); - - // Copy State_Plan row, dropping UUID and replica_id - await transaction.request().query(` - DECLARE @columns NVARCHAR(MAX), @sql NVARCHAR(MAX), @newId NVARCHAR(50), @originalId NVARCHAR(50); - - SET @newId = '${result.data.newId}'; - SET @originalId = '${body.id}'; - - SELECT @columns = COALESCE(@columns + ', ', '') + QUOTENAME(column_name) - FROM INFORMATION_SCHEMA.COLUMNS - WHERE table_name = 'State_Plan' AND column_name != 'ID_Number' AND column_name != 'UUID' AND column_name != 'replica_id' AND table_schema = 'dbo' - ORDER BY ordinal_position; - - SET @sql = 'INSERT INTO SEA.dbo.State_Plan (ID_Number, ' + @columns + ') SELECT ''' + @newId + ''' as ID_Number, ' + @columns + ' FROM SEA.dbo.State_Plan WHERE ID_Number = ''' + @originalId + ''''; - EXEC sp_executesql @sql; - `); - - // Copy RAI rows - await transaction.request().query(` - INSERT INTO RAI (ID_Number, RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE) - SELECT '${result.data.newId}', RAI_REQUESTED_DATE, RAI_RECEIVED_DATE, RAI_WITHDRAWN_DATE - FROM RAI - WHERE ID_Number = '${body.id}'; - `); - - // Copy Types rows - await transaction.request().query(` - INSERT INTO State_Plan_Service_Types (ID_Number, Service_Type_ID) - SELECT '${result.data.newId}', Service_Type_ID - FROM State_Plan_Service_Types - WHERE ID_Number = '${body.id}'; - `); - - //Copy SubTypes rows - await transaction.request().query(` - INSERT INTO State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) - SELECT '${result.data.newId}', Service_SubType_ID - FROM State_Plan_Service_SubTypes - WHERE ID_Number = '${body.id}'; - `); - - //Copy Action_Officers rows - await transaction.request().query(` - INSERT INTO Action_Officers (ID_Number, Officer_ID) - SELECT '${result.data.newId}', Officer_ID - FROM Action_Officers - WHERE ID_Number = '${body.id}'; - `); - - // Put Status Memo notes in the old package - await transaction.request().query(` - UPDATE SEA.dbo.State_Plan - SET - SPW_Status_ID = (SELECT SPW_Status_ID FROM SEA.dbo.SPW_Status WHERE SPW_Status_DESC = '${ - SEATOOL_STATUS.TERMINATED - }'), - Status_Date = dateadd(s, convert(int, left(${today}, 10)), cast('19700101' as datetime)), - Status_Memo = ${buildStatusMemoQuery(body.id, `Package Terminated via ID Update: this package was copied to ${result.data.newId} and then terminated.`)} - WHERE ID_Number = '${body.id}' - `); - - // Put Status Memo notes in the new package; this could be combined into the insert above, for speed. - await transaction.request().query(` - UPDATE SEA.dbo.State_Plan - SET - Status_Memo = ${buildStatusMemoQuery(body.id, `Package Created via ID Update: this package was copied from ${body.id}.`)} - WHERE ID_Number = '${result.data.newId}' - `); - - await produceMessage( - TOPIC_NAME, - body.id, - JSON.stringify({ - actionType: Action.UPDATE_ID, - timestamp: now, - ...result.data, - }), - ); - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error("Error executing query:", err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } - - return response({ - statusCode: 200, - body: { - message: "record successfully submitted", - }, - }); -} - -export async function completeIntake(body: any) { - console.log("CMS performing intake for a record."); - - const result = completeIntakeSchema.safeParse(body); - if (!result.success) { - console.error( - "validation error: The following record failed to parse: ", - JSON.stringify(body), - "Because of the following Reason(s):", - result.error.message, - ); - return response({ - statusCode: 400, - body: { - message: "Event validation error", - }, - }); - } - - const now = new Date().getTime(); - const pool = await sql.connect(config); - const transaction = new sql.Transaction(pool); - try { - await transaction.begin(); - - // Generate INSERT statements for typeIds - const typeIdsValues = result.data.typeIds - .map((typeId: number) => `('${result.data.id}', '${typeId}')`) - .join(",\n"); - - const typeIdsInsert = typeIdsValues - ? `INSERT INTO SEA.dbo.State_Plan_Service_Types (ID_Number, Service_Type_ID) VALUES ${typeIdsValues};` - : ""; - - // Generate INSERT statements for subTypeIds - const subTypeIdsValues = result.data.subTypeIds - .map((subTypeId: number) => `('${result.data.id}', '${subTypeId}')`) - .join(",\n"); - - const subTypeIdsInsert = subTypeIdsValues - ? `INSERT INTO SEA.dbo.State_Plan_Service_SubTypes (ID_Number, Service_SubType_ID) VALUES ${subTypeIdsValues};` - : ""; - - await transaction.request().query(` - UPDATE SEA.dbo.State_Plan - SET - Title_Name = ${ - result.data.subject - ? `'${result.data.subject.replace("'", "''")}'` - : "NULL" - }, - Summary_Memo = ${ - result.data.description - ? `'${result.data.description.replace("'", "''")}'` - : "NULL" - }, - Lead_Analyst_ID = ${result.data.cpoc ? result.data.cpoc : "NULL"}, - Status_Memo = ${buildStatusMemoQuery(result.data.id, `Intake Completed: Intake was completed by ${result.data.submitterName}`)} - WHERE ID_Number = '${result.data.id}' - - -- Insert all types into State_Plan_Service_Types - ${typeIdsInsert} - - -- Insert all types into State_Plan_Service_SubTypes - ${subTypeIdsInsert} - `); - - await produceMessage( - TOPIC_NAME, - result.data.id, - JSON.stringify({ - actionType: Action.COMPLETE_INTAKE, - timestamp: now, - ...result.data, - }), - ); - await transaction.commit(); - } catch (err) { - // Rollback and log - await transaction.rollback(); - console.error("Error executing query:", err); - return response({ - statusCode: 500, - body: err instanceof Error ? { message: err.message } : err, - }); - } finally { - // Close pool - await pool.close(); - } - - return response({ - statusCode: 200, - body: { - message: "record successfully submitted", - }, - }); -} diff --git a/src/services/api/libs/package/getPackage.ts b/src/services/api/libs/package/getPackage.ts index 5a9957e59..9017ebf38 100644 --- a/src/services/api/libs/package/getPackage.ts +++ b/src/services/api/libs/package/getPackage.ts @@ -2,7 +2,7 @@ import * as os from "../../../../libs/opensearch-lib"; import { opensearch } from "shared-types"; import { getAppkChildren } from "./appk"; -interface ExtendedItemResult extends opensearch.main.ItemResult { +export interface ExtendedItemResult extends opensearch.main.ItemResult { appkChildren?: any[]; // Add appkChildren field } export const getPackage = async (id: string) => { diff --git a/src/services/api/package.json b/src/services/api/package.json index 16490104a..a33124e7a 100644 --- a/src/services/api/package.json +++ b/src/services/api/package.json @@ -2,6 +2,7 @@ "name": "api", "private": true, "devDependencies": { + "@anatine/zod-mock": "^3.13.4", "@types/aws-lambda": "^8.10.111", "@types/mssql": "^8.1.2", "@typescript-eslint/eslint-plugin": "^5.59.0", @@ -31,6 +32,7 @@ "build": "tsc", "lint": "eslint '**/*.{ts,js}'", "test": "vitest", - "coverage": "vitest run --coverage" + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui" } } diff --git a/src/services/api/tsconfig.json b/src/services/api/tsconfig.json index 6f70a5de2..b783eef14 100644 --- a/src/services/api/tsconfig.json +++ b/src/services/api/tsconfig.json @@ -1,11 +1,12 @@ { "compilerOptions": { - "target": "ES2016", + "target": "ES2017", "moduleResolution": "node", "module": "commonjs", "skipLibCheck": true, "strict": true, - "noEmit": true + "noEmit": true, + "typeRoots": ["./global.d.ts"] }, "include": ["./**/*.ts"], "exclude": ["node_modules"] diff --git a/src/services/data/handlers/sinkMain.ts b/src/services/data/handlers/sinkMain.ts index 8fe91dba5..1d08fdd16 100644 --- a/src/services/data/handlers/sinkMain.ts +++ b/src/services/data/handlers/sinkMain.ts @@ -135,6 +135,14 @@ const onemac = async (kafkaRecords: KafkaRecord[], topicPartition: string) => { return opensearch.main.toggleWithdrawEnabled .transform(id) .safeParse(record); + case Action.ISSUE_RAI: + return opensearch.main.issueRai + .transform(id) + .safeParse(record); + case Action.RESPOND_TO_RAI: + return opensearch.main.respondToRai + .transform(id) + .safeParse(record); case Action.WITHDRAW_RAI: return opensearch.main.withdrawRai .transform(id) diff --git a/src/services/ui/package.json b/src/services/ui/package.json index 4c6dded4a..b33c7b45c 100644 --- a/src/services/ui/package.json +++ b/src/services/ui/package.json @@ -9,10 +9,9 @@ "lint": "eslint 'src/**/*.{ts,tsx}'", "build": "tsc && vite build", "preview": "vite preview", - "test": "vitest run", - "test:watch": "vitest", - "test:gui": "vitest --ui", - "coverage": "vitest run --coverage", + "test": "vitest", + "test:coverage": "vitest run --coverage", + "test:ui": "vitest --ui", "e2e:ui": "playwright test --ui" }, "dependencies": { @@ -90,8 +89,6 @@ "@typescript-eslint/eslint-plugin": "^5.59.0", "@typescript-eslint/parser": "^5.59.0", "@vitejs/plugin-react-swc": "^3.0.0", - "@vitest/coverage-istanbul": "^1.6.0", - "@vitest/ui": "^1.6.0", "autoprefixer": "^10.4.14", "eslint": "^8.38.0", "eslint-config-custom": "*", @@ -103,7 +100,6 @@ "tailwindcss": "^3.3.1", "typescript": "^5.2.0", "vite": "^4.2.0", - "vite-plugin-radar": "^0.9.2", - "vitest": "^1.6.0" + "vite-plugin-radar": "^0.9.2" } } diff --git a/src/services/ui/src/features/package-actions/lib/modules/complete-intake/index.tsx b/src/services/ui/src/features/package-actions/lib/modules/complete-intake/index.tsx index 3594923c4..dead50262 100644 --- a/src/services/ui/src/features/package-actions/lib/modules/complete-intake/index.tsx +++ b/src/services/ui/src/features/package-actions/lib/modules/complete-intake/index.tsx @@ -47,4 +47,6 @@ export const defaultCompleteIntakeContent: FormContentHydrator = ( }, }); -export const intakeCompleted: CheckDocumentFunction = (_checks) => true; +export const intakeCompleted: CheckDocumentFunction = (checks) => { + return checks.hasCpoc; +}; diff --git a/src/services/ui/src/features/package-actions/lib/modules/respond-to-rai/index.tsx b/src/services/ui/src/features/package-actions/lib/modules/respond-to-rai/index.tsx index f0225bb50..8336566bc 100644 --- a/src/services/ui/src/features/package-actions/lib/modules/respond-to-rai/index.tsx +++ b/src/services/ui/src/features/package-actions/lib/modules/respond-to-rai/index.tsx @@ -16,15 +16,20 @@ export const spaRaiContent: FormContentHydrator = (document) => ({ export * from "./waiver/b-waiver-rai"; // TODO: C waiver rai?? -export const waiverRaiContent: FormContentHydrator = (document) => ({ - title: `${document.authority} Waiver Formal RAI Response Details`, - preSubmitNotice: - "Once you submit this form, a confirmation email is sent to you and to CMS. CMS will use this content to review your package, and you will not be able to edit this form. If CMS needs any additional information, they will follow up by email.", - successBanner: { - header: "RAI response submitted", - body: `The RAI response for ${document.id} has been submitted.`, - }, -}); +export const waiverRaiContent: FormContentHydrator = (document) => { + const title = document.appkParent + ? `${document.authority} Appendix K Formal RAI Response Details` + : `${document.authority} Waiver Formal RAI Response Details`; + return { + title, + preSubmitNotice: + "Once you submit this form, a confirmation email is sent to you and to CMS. CMS will use this content to review your package, and you will not be able to edit this form. If CMS needs any additional information, they will follow up by email.", + successBanner: { + header: "RAI response submitted", + body: `The RAI response for ${document.id} has been submitted.`, + }, + }; +}; export const raiRespondedTo: CheckDocumentFunction = (checks) => checks.hasStatus(SEATOOL_STATUS.PENDING) && checks.hasRaiResponse; diff --git a/src/services/ui/src/features/package-actions/lib/modules/withdraw-rai/index.tsx b/src/services/ui/src/features/package-actions/lib/modules/withdraw-rai/index.tsx index e2ab7d40c..083366f70 100644 --- a/src/services/ui/src/features/package-actions/lib/modules/withdraw-rai/index.tsx +++ b/src/services/ui/src/features/package-actions/lib/modules/withdraw-rai/index.tsx @@ -37,21 +37,25 @@ export const defaultWithdrawRaiFields: ReactElement[] = [ instruction={"Explain your need for withdrawal."} />, ]; -export const defaultWithdrawRaiContent: FormContentHydrator = (document) => ({ - title: `${document.authority} Withdraw Formal RAI Response Details`, - preSubmitNotice: - "Once complete, you and CMS will receive an email confirmation.", - confirmationModal: { - header: "Withdraw RAI response?", - body: `The RAI response for ${document.id} will be withdrawn, and CMS will be notified.`, - acceptButtonText: "Yes, withdraw response", - cancelButtonText: "Cancel", - }, - successBanner: { - header: "RAI response withdrawn", - body: `The RAI response for ${document.id} has been withdrawn. CMS may follow up if additional information is needed.`, - }, -}); +export const defaultWithdrawRaiContent: FormContentHydrator = (document) => { + const title = document.appkParent + ? `${document.authority} Appendix K Withdraw Formal RAI Response Details` + : `${document.authority} Withdraw Formal RAI Response Details`; + return { + title, + preSubmitNotice: "Once complete, you and CMS will receive an email confirmation.", + confirmationModal: { + header: "Withdraw RAI response?", + body: `The RAI response for ${document.id} will be withdrawn, and CMS will be notified.`, + acceptButtonText: "Yes, withdraw response", + cancelButtonText: "Cancel", + }, + successBanner: { + header: "RAI response withdrawn", + body: `The RAI response for ${document.id} has been withdrawn. CMS may follow up if additional information is needed.`, + }, + }; +}; export const raiWithdrawn: CheckDocumentFunction = (checks) => checks.hasStatus(SEATOOL_STATUS.PENDING_RAI) && checks.hasRaiWithdrawal; diff --git a/turbo.json b/turbo.json index 4c4150859..3188fff98 100644 --- a/turbo.json +++ b/turbo.json @@ -1,19 +1,12 @@ { "$schema": "https://turbo.build/schema.json", "pipeline": { - "test": { - "outputs": ["dist/**"], - "cache": false - }, - "coverage": {}, "lint": { "cache": false }, "build:cli": { "cache": false }, - "test:watch": {}, - "test:gui": {}, "e2e": {}, "e2e:ui": {} } diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 000000000..0fa06c4e8 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,26 @@ +import { defineConfig, configDefaults } from "vitest/config"; +import { join } from "path"; + +export default defineConfig({ + test: { + coverage: { + provider: "v8", + reportsDirectory: join(__dirname, "coverage"), + reporter: ["html", "text", "json-summary", "json", "lcov"], + reportOnFailure: true, + exclude: [ + ...configDefaults.exclude, + "build_run", + "docs", + "src/services/api/webforms", + "src/packages/eslint-config-custom", + "src/packages/eslint-config-custom-server", + "src/cli", + "vitest.workspace.ts", + "**/*/.eslintrc.{ts,js,cjs}", + "**/*.config.{ts,js,cjs}", + "src/services/ui/e2e", + ], + }, + }, +}); diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 000000000..c0e71a159 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1,10 @@ +import { defineWorkspace } from 'vitest/config' + +// defineWorkspace provides a nice type hinting DX +export default defineWorkspace([ + 'src/services/ui', + 'src/services/api', + 'src/packages/shared-types', + 'src/packages/shared-utils', + 'src/libs' +]) \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 68c107620..661690105 100644 --- a/yarn.lock +++ b/yarn.lock @@ -32,7 +32,7 @@ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30" integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== -"@ampproject/remapping@^2.2.0": +"@ampproject/remapping@^2.2.0", "@ampproject/remapping@^2.3.0": version "2.3.0" resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== @@ -40,7 +40,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@anatine/zod-mock@^3.12.0": +"@anatine/zod-mock@^3.12.0", "@anatine/zod-mock@^3.13.4": version "3.13.4" resolved "https://registry.yarnpkg.com/@anatine/zod-mock/-/zod-mock-3.13.4.tgz#ec464bcf2b5f3c1fece8d5e637d1f339e19a0449" integrity sha512-yO/KeuyYsEDCTcQ+7CiRuY3dnafMHIZUMok6Ci7aERRCTQ+/XmsiPk/RnMx5wlLmWBTmX9kw+PavbMsjM+sAJA== @@ -6479,18 +6479,6 @@ resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.5.tgz#db9468cb1b1b5a925b8f34822f1669df0c5472f5" integrity sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg== -"@types/chai-subset@^1.3.3": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.5.tgz#3fc044451f26985f45625230a7f22284808b0a9a" - integrity sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A== - dependencies: - "@types/chai" "*" - -"@types/chai@*", "@types/chai@^4.3.4": - version "4.3.14" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.14.tgz#ae3055ea2be43c91c9fd700a36d67820026d96e6" - integrity sha512-Wj71sXE4Q4AkGdG9Tvq1u/fquNz9EdG4LIJMwVVII7ashjD/8cf8fyIfJAjRr6YcsXnSE8cOGQPq1gqeR8z+3w== - "@types/cookie@^0.3.3": version "0.3.3" resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" @@ -6967,132 +6955,104 @@ picocolors "^1.0.0" std-env "^3.3.1" -"@vitest/coverage-istanbul@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/coverage-istanbul/-/coverage-istanbul-1.6.0.tgz#4df9310b085416f064f7e057373c546dcf14e41c" - integrity sha512-h/BwpXehkkS0qsNCS00QxiupAqVkNi0WT19BR0dQvlge5oHghoSVLx63fABYFoKxVb7Ue7+k6V2KokmQ1zdMpg== +"@vitest/coverage-istanbul@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/coverage-istanbul/-/coverage-istanbul-2.0.2.tgz#b145417b4f84dec89ad2997292875585b40c392a" + integrity sha512-9TZC/4CT9j7GZYwh1fYtxNtRoSi7T4evF5M/rxOOAvgejJFxM/ysXSvdyV/HXWkEbH/Be8uKnd+v/TyYyrglGA== dependencies: - debug "^4.3.4" + "@istanbuljs/schema" "^0.1.3" + debug "^4.3.5" istanbul-lib-coverage "^3.2.2" - istanbul-lib-instrument "^6.0.1" + istanbul-lib-instrument "^6.0.3" istanbul-lib-report "^3.0.1" - istanbul-lib-source-maps "^5.0.4" - istanbul-reports "^3.1.6" - magicast "^0.3.3" - picocolors "^1.0.0" - test-exclude "^6.0.0" - -"@vitest/expect@0.30.1": - version "0.30.1" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-0.30.1.tgz#3c92a3fc23a198315ce8cd16689dc2d5aeac40b8" - integrity sha512-c3kbEtN8XXJSeN81iDGq29bUzSjQhjES2WR3aColsS4lPGbivwLtas4DNUe0jD9gg/FYGIteqOenfU95EFituw== - dependencies: - "@vitest/spy" "0.30.1" - "@vitest/utils" "0.30.1" - chai "^4.3.7" + istanbul-lib-source-maps "^5.0.6" + istanbul-reports "^3.1.7" + magicast "^0.3.4" + test-exclude "^7.0.1" + tinyrainbow "^1.2.0" -"@vitest/expect@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.0.tgz#0b3ba0914f738508464983f4d811bc122b51fb30" - integrity sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ== - dependencies: - "@vitest/spy" "1.6.0" - "@vitest/utils" "1.6.0" - chai "^4.3.10" - -"@vitest/runner@0.30.1": - version "0.30.1" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-0.30.1.tgz#534db590091e5d40682f47b9478f64b776073c50" - integrity sha512-W62kT/8i0TF1UBCNMRtRMOBWJKRnNyv9RrjIgdUryEe0wNpGZvvwPDLuzYdxvgSckzjp54DSpv1xUbv4BQ0qVA== - dependencies: - "@vitest/utils" "0.30.1" - concordance "^5.0.4" - p-limit "^4.0.0" - pathe "^1.1.0" - -"@vitest/runner@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.0.tgz#a6de49a96cb33b0e3ba0d9064a3e8d6ce2f08825" - integrity sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg== +"@vitest/coverage-v8@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-2.0.2.tgz#dcaf34b4927e272e8babaa557a677e1e6a16196e" + integrity sha512-iA8eb4PMid3bMc++gfQSTvYE1QL//fC8pz+rKsTUDBFjdDiy/gH45hvpqyDu5K7FHhvgG0GNNCJzTMMSFKhoxg== dependencies: - "@vitest/utils" "1.6.0" - p-limit "^5.0.0" - pathe "^1.1.1" - -"@vitest/snapshot@0.30.1": - version "0.30.1" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-0.30.1.tgz#25e912557b357ecb89d5ee35e8d7c4c7a5ecfe32" - integrity sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw== + "@ampproject/remapping" "^2.3.0" + "@bcoe/v8-coverage" "^0.2.3" + debug "^4.3.5" + istanbul-lib-coverage "^3.2.2" + istanbul-lib-report "^3.0.1" + istanbul-lib-source-maps "^5.0.6" + istanbul-reports "^3.1.7" + magic-string "^0.30.10" + magicast "^0.3.4" + std-env "^3.7.0" + strip-literal "^2.1.0" + test-exclude "^7.0.1" + tinyrainbow "^1.2.0" + +"@vitest/expect@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-2.0.2.tgz#2eff61dde5fb2574a0a7a32517419b5de7d78124" + integrity sha512-nKAvxBYqcDugYZ4nJvnm5OR8eDJdgWjk4XM9owQKUjzW70q0icGV2HVnQOyYsp906xJaBDUXw0+9EHw2T8e0mQ== dependencies: - magic-string "^0.30.0" - pathe "^1.1.0" - pretty-format "^27.5.1" + "@vitest/spy" "2.0.2" + "@vitest/utils" "2.0.2" + chai "^5.1.1" + tinyrainbow "^1.2.0" -"@vitest/snapshot@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.0.tgz#deb7e4498a5299c1198136f56e6e0f692e6af470" - integrity sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ== +"@vitest/pretty-format@2.0.2", "@vitest/pretty-format@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-2.0.2.tgz#c2674fef447ad8469144fdc483e859f9b1664133" + integrity sha512-SBCyOXfGVvddRd9r2PwoVR0fonQjh9BMIcBMlSzbcNwFfGr6ZhOhvBzurjvi2F4ryut2HcqiFhNeDVGwru8tLg== dependencies: - magic-string "^0.30.5" - pathe "^1.1.1" - pretty-format "^29.7.0" + tinyrainbow "^1.2.0" -"@vitest/spy@0.30.1": - version "0.30.1" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-0.30.1.tgz#e3344d4513407afd922963737fb9733a7787a2bf" - integrity sha512-YfJeIf37GvTZe04ZKxzJfnNNuNSmTEGnla2OdL60C8od16f3zOfv9q9K0nNii0NfjDJRt/CVN/POuY5/zTS+BA== +"@vitest/runner@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-2.0.2.tgz#5716c25f762308e4c87485668e4654cd4b832a73" + integrity sha512-OCh437Vi8Wdbif1e0OvQcbfM3sW4s2lpmOjAE7qfLrpzJX2M7J1IQlNvEcb/fu6kaIB9n9n35wS0G2Q3en5kHg== dependencies: - tinyspy "^2.1.0" + "@vitest/utils" "2.0.2" + pathe "^1.1.2" -"@vitest/spy@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.0.tgz#362cbd42ccdb03f1613798fde99799649516906d" - integrity sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw== +"@vitest/snapshot@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-2.0.2.tgz#91a8b847d82d92d06b9bf70b72bb9f21a4a416a1" + integrity sha512-Yc2ewhhZhx+0f9cSUdfzPRcsM6PhIb+S43wxE7OG0kTxqgqzo8tHkXFuFlndXeDMp09G3sY/X5OAo/RfYydf1g== dependencies: - tinyspy "^2.2.0" + "@vitest/pretty-format" "2.0.2" + magic-string "^0.30.10" + pathe "^1.1.2" -"@vitest/ui@^0.29.8": - version "0.29.8" - resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-0.29.8.tgz#0897b8632760047729a07083bc463072545e8b0f" - integrity sha512-+vbLd+c1R/XUWfzJsWeyjeiw13fwJ95I5tguxaqXRg61y9iYUKesVljg7Pttp2uo7VK+kAjvY91J41NZ1Vx3vg== +"@vitest/spy@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-2.0.2.tgz#505b70978ae5f9db7a923bf8d62e4bfa6d89725f" + integrity sha512-MgwJ4AZtCgqyp2d7WcQVE8aNG5vQ9zu9qMPYQHjsld/QVsrvg78beNrXdO4HYkP0lDahCO3P4F27aagIag+SGQ== dependencies: - fast-glob "^3.2.12" - flatted "^3.2.7" - pathe "^1.1.0" - picocolors "^1.0.0" - sirv "^2.0.2" + tinyspy "^3.0.0" -"@vitest/ui@^1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-1.6.0.tgz#ffcc97ebcceca7fec840c29ab68632d0cd01db93" - integrity sha512-k3Lyo+ONLOgylctiGovRKy7V4+dIN2yxstX3eY5cWFXH6WP+ooVX79YSyi0GagdTQzLmT43BF27T0s6dOIPBXA== +"@vitest/ui@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/ui/-/ui-2.0.2.tgz#325deb23db34a067bda19a93c1ad732df6c48edd" + integrity sha512-VwxFTOC2GcNPexQlR9PFb8drWCLA+nLWTWlAS4oba1xbTJYJ8H5vY8OUFOTMb7YQXF0Vsc5IfmLpYkb2dcVgOA== dependencies: - "@vitest/utils" "1.6.0" + "@vitest/utils" "2.0.2" fast-glob "^3.3.2" - fflate "^0.8.1" - flatted "^3.2.9" - pathe "^1.1.1" - picocolors "^1.0.0" + fflate "^0.8.2" + flatted "^3.3.1" + pathe "^1.1.2" sirv "^2.0.4" + tinyrainbow "^1.2.0" -"@vitest/utils@0.30.1": - version "0.30.1" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-0.30.1.tgz#0e5bf8c1b81a6dfa2b70120c2aa092a651440cda" - integrity sha512-/c8Xv2zUVc+rnNt84QF0Y0zkfxnaGhp87K2dYJMLtLOIckPzuxLVzAtFCicGFdB4NeBHNzTRr1tNn7rCtQcWFA== - dependencies: - concordance "^5.0.4" - loupe "^2.3.6" - pretty-format "^27.5.1" - -"@vitest/utils@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.0.tgz#5c5675ca7d6f546a7b4337de9ae882e6c57896a1" - integrity sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw== +"@vitest/utils@2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-2.0.2.tgz#a2e829b126b08987e93e1d105323c7f7b99e271d" + integrity sha512-pxCY1v7kmOCWYWjzc0zfjGTA3Wmn8PKnlPvSrsA643P1NHl1fOyXj2Q9SaNlrlFE+ivCsxM80Ov3AR82RmHCWQ== dependencies: - diff-sequences "^29.6.3" + "@vitest/pretty-format" "2.0.2" estree-walker "^3.0.3" - loupe "^2.3.7" - pretty-format "^29.7.0" + loupe "^3.1.1" + tinyrainbow "^1.2.0" JSONStream@^1.3.5: version "1.3.5" @@ -7142,23 +7102,11 @@ acorn-walk@^8.0.2, acorn-walk@^8.2.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -acorn-walk@^8.3.2: - version "8.3.3" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e" - integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw== - dependencies: - acorn "^8.11.0" - -acorn@^8.1.0, acorn@^8.10.0, acorn@^8.11.3, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0: +acorn@^8.1.0, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0: version "8.11.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== -acorn@^8.11.0: - version "8.12.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" - integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== - adm-zip@^0.5.5: version "0.5.12" resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.12.tgz#87786328e91d54b37358d8a50f954c4cd73ba60b" @@ -7563,10 +7511,10 @@ assert-plus@1.0.0, assert-plus@^1.0.0: resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== async@^3.2.0, async@^3.2.4: version "3.2.5" @@ -7797,11 +7745,6 @@ bluebird@^2.6.2: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" integrity sha512-UfFSr22dmHPQqPP9XWHRhq+gWnHCYguQGkXQlbyPtW5qTnhFWA8/iXg765tH0cAjy7l/zPJ1aBTO0g5XgA7kvQ== -blueimp-md5@^2.10.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/blueimp-md5/-/blueimp-md5-2.19.0.tgz#b53feea5498dcb53dc6ec4b823adb84b729c4af0" - integrity sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w== - bottleneck@^2.15.3: version "2.19.5" resolved "https://registry.yarnpkg.com/bottleneck/-/bottleneck-2.19.5.tgz#5df0b90f59fd47656ebe63c78a98419205cadd91" @@ -8084,18 +8027,16 @@ cfn-response-async@^1.0.0: resolved "https://registry.yarnpkg.com/cfn-response-async/-/cfn-response-async-1.0.0.tgz#92cfe1756413a0cce9b50e86e1f5519951d18989" integrity sha512-/uSeKzALcu0SDieUwu9LwqxTYX4IpX3JAyNAfQ6menx7Y2FfERAUw884Qk4/o+KYZNsaPXjFaEwGHsyrQP/FJA== -chai@^4.3.10, chai@^4.3.7: - version "4.4.1" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" - integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.0.8" +chai@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.1.tgz#f035d9792a22b481ead1c65908d14bb62ec1c82c" + integrity sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" @@ -8132,12 +8073,10 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== - dependencies: - get-func-name "^2.0.2" +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== child-process-ext@^2.1.1: version "2.1.1" @@ -8459,25 +8398,6 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== -concordance@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/concordance/-/concordance-5.0.4.tgz#9896073261adced72f88d60e4d56f8efc4bbbbd2" - integrity sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw== - dependencies: - date-time "^3.1.0" - esutils "^2.0.3" - fast-diff "^1.2.0" - js-string-escape "^1.0.1" - lodash "^4.17.15" - md5-hex "^3.0.1" - semver "^7.3.2" - well-known-symbols "^2.0.0" - -confbox@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579" - integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA== - config-chain@^1.1.11: version "1.1.13" resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" @@ -8751,13 +8671,6 @@ date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" -date-time@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/date-time/-/date-time-3.1.0.tgz#0d1e934d170579f481ed8df1e2b8ff70ee845e1e" - integrity sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg== - dependencies: - time-zone "^1.0.0" - dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" @@ -8775,6 +8688,13 @@ debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, d dependencies: ms "2.1.2" +debug@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + decamelize-keys@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.1.tgz#04a2d523b2f18d80d0158a43b895d56dff8d19d8" @@ -8853,12 +8773,10 @@ decompress@^4.2.1: pify "^2.3.0" strip-dirs "^2.0.0" -deep-eql@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" - integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== - dependencies: - type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== deep-equal@^2.0.5: version "2.2.3" @@ -9658,7 +9576,7 @@ estree-walker@^3.0.3: dependencies: "@types/estree" "^1.0.0" -esutils@^2.0.2, esutils@^2.0.3: +esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== @@ -9824,12 +9742,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - -fast-glob@^3.0.3, fast-glob@^3.2.12, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2: +fast-glob@^3.0.3, fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.0, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -9910,7 +9823,7 @@ fflate@0.8.1: resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.1.tgz#1ed92270674d2ad3c73f077cd0acf26486dae6c9" integrity sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ== -fflate@^0.8.1: +fflate@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== @@ -10095,7 +10008,7 @@ flat@^6.0.1: resolved "https://registry.yarnpkg.com/flat/-/flat-6.0.1.tgz#09070cf918293b401577f20843edeadf4d3e8755" integrity sha512-/3FfIa8mbrg3xE7+wAhWeV+bd7L2Mof+xtZb5dRDKZ+wDvYJK4WDYeIOuOhre5Yv5aQObZrlbRmk3RTSiuQBtw== -flatted@^3.2.7, flatted@^3.2.9: +flatted@^3.2.9, flatted@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== @@ -10339,7 +10252,7 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.1, get-func-name@^2.0.2: +get-func-name@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== @@ -10453,6 +10366,18 @@ glob@^10.2.2, glob@^10.3.10: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" +glob@^10.4.1: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.0.5, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.2.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -11377,7 +11302,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0, istanbul-lib-coverag resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-instrument@^6.0.1: +istanbul-lib-instrument@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== @@ -11397,7 +11322,7 @@ istanbul-lib-report@^3.0.0, istanbul-lib-report@^3.0.1: make-dir "^4.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^5.0.4: +istanbul-lib-source-maps@^5.0.6: version "5.0.6" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz#acaef948df7747c8eb5fbf1265cb980f6353a441" integrity sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A== @@ -11406,7 +11331,7 @@ istanbul-lib-source-maps@^5.0.4: debug "^4.1.1" istanbul-lib-coverage "^3.0.0" -istanbul-reports@^3.1.4, istanbul-reports@^3.1.6: +istanbul-reports@^3.1.4, istanbul-reports@^3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== @@ -11434,6 +11359,15 @@ jackspeak@^2.3.5: optionalDependencies: "@pkgjs/parseargs" "^0.11.0" +jackspeak@^3.1.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.2.tgz#c3d1e00071d52dba8b0dac17cd2a12d0187d2989" + integrity sha512-qH3nOSj8q/8+Eg8LUPOq3C+6HWkpUioIjDsq1+D4zY91oZvpPttw8GwtF1nReRYKXl+1AORyFqtm2f5Q1SB6/Q== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + java-properties@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211" @@ -11530,11 +11464,6 @@ js-md4@^0.3.2: resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== -js-string-escape@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - integrity sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -11694,11 +11623,6 @@ json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" - integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== - jsonfile@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" @@ -12113,19 +12037,6 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -local-pkg@^0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" - integrity sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g== - -local-pkg@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c" - integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg== - dependencies: - mlly "^1.4.2" - pkg-types "^1.0.3" - locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -12302,10 +12213,10 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loupe@^2.3.6, loupe@^2.3.7: - version "2.3.7" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== +loupe@^3.1.0, loupe@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.1.tgz#71d038d59007d890e3247c5db97c1ec5a92edc54" + integrity sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw== dependencies: get-func-name "^2.0.1" @@ -12360,21 +12271,14 @@ lz-string@^1.5.0: resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== -magic-string@^0.30.0: - version "0.30.8" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" - integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - -magic-string@^0.30.5: +magic-string@^0.30.10: version "0.30.10" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e" integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ== dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" -magicast@^0.3.3: +magicast@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.4.tgz#bbda1791d03190a24b00ff3dd18151e7fd381d19" integrity sha512-TyDF/Pn36bBji9rWKHlZe+PZb6Mx5V8IHCSxk7X4aljM4e/vyDvZZYwHewdVaqiA0nb3ghfHU/6AUpDxWoER2Q== @@ -12467,13 +12371,6 @@ marked@^5.0.0: resolved "https://registry.yarnpkg.com/marked/-/marked-5.1.2.tgz#62b5ccfc75adf72ca3b64b2879b551d89e77677f" integrity sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg== -md5-hex@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-3.0.1.tgz#be3741b510591434b2784d79e556eefc2c9a8e5c" - integrity sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw== - dependencies: - blueimp-md5 "^2.10.0" - memoize-one@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" @@ -12606,6 +12503,13 @@ minimatch@^5.0.1, minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -12695,6 +12599,11 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -12715,26 +12624,6 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mlly@^1.2.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.6.1.tgz#0983067dc3366d6314fc5e12712884e6978d028f" - integrity sha512-vLgaHvaeunuOXHSmEbZ9izxPx3USsk8KCQ8iC+aTlp5sKRSoZvwhHh5L9VbKSaVC6sJDqbyohIS76E2VmHIPAA== - dependencies: - acorn "^8.11.3" - pathe "^1.1.2" - pkg-types "^1.0.3" - ufo "^1.3.2" - -mlly@^1.4.2, mlly@^1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.1.tgz#e0336429bb0731b6a8e887b438cbdae522c8f32f" - integrity sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA== - dependencies: - acorn "^8.11.3" - pathe "^1.1.2" - pkg-types "^1.1.1" - ufo "^1.5.3" - modify-values@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" @@ -13455,13 +13344,6 @@ p-limit@^4.0.0: dependencies: yocto-queue "^1.0.0" -p-limit@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985" - integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ== - dependencies: - yocto-queue "^1.0.0" - p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -13529,6 +13411,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +package-json-from-dist@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00" + integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw== + pacote@^15.0.0, pacote@^15.0.8, pacote@^15.2.0: version "15.2.0" resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3" @@ -13671,6 +13558,14 @@ path-scurry@^1.10.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@^6.2.0, path-to-regexp@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" @@ -13691,15 +13586,15 @@ path2@^0.1.0: resolved "https://registry.yarnpkg.com/path2/-/path2-0.1.0.tgz#639828942cdbda44a41a45b074ae8873483b4efa" integrity sha512-TX+cz8Jk+ta7IvRy2FAej8rdlbrP0+uBIkP/5DTODez/AuL/vSb30KuAdDxGVREXzn8QfAiu5mJYJ1XjbOhEPA== -pathe@^1.1.0, pathe@^1.1.1, pathe@^1.1.2: +pathe@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec" integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ== -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== peek-readable@^4.1.0: version "4.1.0" @@ -13801,24 +13696,6 @@ pkg-conf@^2.1.0: find-up "^2.0.0" load-json-file "^4.0.0" -pkg-types@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.0.3.tgz#988b42ab19254c01614d13f4f65a2cfc7880f868" - integrity sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A== - dependencies: - jsonc-parser "^3.2.0" - mlly "^1.2.0" - pathe "^1.1.0" - -pkg-types@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.3.tgz#161bb1242b21daf7795036803f28e30222e476e3" - integrity sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA== - dependencies: - confbox "^0.1.7" - mlly "^1.7.1" - pathe "^1.1.2" - playwright-core@1.42.1: version "1.42.1" resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.42.1.tgz#13c150b93c940a3280ab1d3fbc945bc855c9459e" @@ -13960,7 +13837,7 @@ prettier@3.2.5: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== -pretty-format@^27.0.2, pretty-format@^27.5.1: +pretty-format@^27.0.2: version "27.5.1" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== @@ -15103,7 +14980,7 @@ sinon@^14.0.2: nise "^5.1.2" supports-color "^7.2.0" -sirv@^2.0.2, sirv@^2.0.4: +sirv@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== @@ -15300,7 +15177,7 @@ statuses@^2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -std-env@^3.3.1, std-env@^3.3.2, std-env@^3.5.0: +std-env@^3.3.1, std-env@^3.7.0: version "3.7.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2" integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg== @@ -15487,14 +15364,7 @@ strip-json-comments@~2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -strip-literal@^1.0.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-1.3.0.tgz#db3942c2ec1699e6836ad230090b84bb458e3a07" - integrity sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg== - dependencies: - acorn "^8.10.0" - -strip-literal@^2.0.0: +strip-literal@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.0.tgz#6d82ade5e2e74f5c7e8739b6c84692bd65f0bd2a" integrity sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw== @@ -15762,6 +15632,15 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +test-exclude@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-7.0.1.tgz#20b3ba4906ac20994e275bbcafd68d510264c2a2" + integrity sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^10.4.1" + minimatch "^9.0.4" + text-extensions@^2.0.0: version "2.4.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34" @@ -15811,11 +15690,6 @@ through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -time-zone@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" - integrity sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA== - timers-ext@^0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" @@ -15834,30 +15708,25 @@ tiny-warning@^1.0.2: resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== -tinybench@^2.4.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.6.0.tgz#1423284ee22de07c91b3752c048d2764714b341b" - integrity sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA== - -tinybench@^2.5.1: +tinybench@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.8.0.tgz#30e19ae3a27508ee18273ffed9ac7018949acd7b" integrity sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw== -tinypool@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.4.0.tgz#3cf3ebd066717f9f837e8d7d31af3c127fdb5446" - integrity sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA== +tinypool@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.0.tgz#a68965218e04f4ad9de037d2a1cd63cda9afb238" + integrity sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ== -tinypool@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8" - integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ== +tinyrainbow@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-1.2.0.tgz#5c57d2fc0fb3d1afd78465c33ca885d04f02abb5" + integrity sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ== -tinyspy@^2.1.0, tinyspy@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.1.tgz#117b2342f1f38a0dbdcc73a50a454883adf861d1" - integrity sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A== +tinyspy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.0.tgz#cb61644f2713cd84dee184863f4642e06ddf0585" + integrity sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA== tmp@^0.0.33: version "0.0.33" @@ -16069,7 +15938,7 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: +type-detect@4.0.8, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -16173,11 +16042,6 @@ typescript@^5.0.4, typescript@^5.2.0: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== -ufo@^1.3.2, ufo@^1.5.3: - version "1.5.3" - resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344" - integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw== - uglify-js@^3.1.4: version "3.17.4" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.4.tgz#61678cf5fa3f5b7eb789bb345df29afb8257c22c" @@ -16449,27 +16313,15 @@ verror@1.10.0: core-util-is "1.0.2" extsprintf "^1.2.0" -vite-node@0.30.1: - version "0.30.1" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-0.30.1.tgz#ab0ed1553019c7d81ac95529c57ab8ac9e82347d" - integrity sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg== - dependencies: - cac "^6.7.14" - debug "^4.3.4" - mlly "^1.2.0" - pathe "^1.1.0" - picocolors "^1.0.0" - vite "^3.0.0 || ^4.0.0" - -vite-node@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f" - integrity sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw== +vite-node@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-2.0.2.tgz#6e1958b2db655ddef8c95e6fb461bcd954b7fbbf" + integrity sha512-w4vkSz1Wo+NIQg8pjlEn0jQbcM/0D+xVaYjhw3cvarTanLLBh54oNiRbsT8PNK5GfuST0IlVXjsNRoNlqvY/fw== dependencies: cac "^6.7.14" - debug "^4.3.4" - pathe "^1.1.1" - picocolors "^1.0.0" + debug "^4.3.5" + pathe "^1.1.2" + tinyrainbow "^1.2.0" vite "^5.0.0" vite-plugin-radar@^0.9.2: @@ -16477,7 +16329,7 @@ vite-plugin-radar@^0.9.2: resolved "https://registry.yarnpkg.com/vite-plugin-radar/-/vite-plugin-radar-0.9.3.tgz#c184897aa8c057fa845f1033a2f977011a8b7c70" integrity sha512-o/7F0gHQW9yUxpExXYwQLxFYOSxiWIPs3Uh24sg+wl5ikghzLKMQ2Xldak/rsT0o06rzdrAqP9+XSOwfCbwz2Q== -"vite@^3.0.0 || ^4.0.0", vite@^4.2.0: +vite@^4.2.0: version "4.5.3" resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.3.tgz#d88a4529ea58bae97294c7e2e6f0eab39a50fb1a" integrity sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg== @@ -16499,62 +16351,29 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vitest@^0.30.1: - version "0.30.1" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-0.30.1.tgz#351d4a2f27aa8cc0245e3583e3ed45e30efc71d6" - integrity sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA== - dependencies: - "@types/chai" "^4.3.4" - "@types/chai-subset" "^1.3.3" - "@types/node" "*" - "@vitest/expect" "0.30.1" - "@vitest/runner" "0.30.1" - "@vitest/snapshot" "0.30.1" - "@vitest/spy" "0.30.1" - "@vitest/utils" "0.30.1" - acorn "^8.8.2" - acorn-walk "^8.2.0" - cac "^6.7.14" - chai "^4.3.7" - concordance "^5.0.4" - debug "^4.3.4" - local-pkg "^0.4.3" - magic-string "^0.30.0" - pathe "^1.1.0" - picocolors "^1.0.0" - source-map "^0.6.1" - std-env "^3.3.2" - strip-literal "^1.0.1" - tinybench "^2.4.0" - tinypool "^0.4.0" - vite "^3.0.0 || ^4.0.0" - vite-node "0.30.1" - why-is-node-running "^2.2.2" - -vitest@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.0.tgz#9d5ad4752a3c451be919e412c597126cffb9892f" - integrity sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA== - dependencies: - "@vitest/expect" "1.6.0" - "@vitest/runner" "1.6.0" - "@vitest/snapshot" "1.6.0" - "@vitest/spy" "1.6.0" - "@vitest/utils" "1.6.0" - acorn-walk "^8.3.2" - chai "^4.3.10" - debug "^4.3.4" +vitest@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-2.0.2.tgz#39a4bde8af124c848b4e9098ca339914ebe10ef9" + integrity sha512-WlpZ9neRIjNBIOQwBYfBSr0+of5ZCbxT2TVGKW4Lv0c8+srCFIiRdsP7U009t8mMn821HQ4XKgkx5dVWpyoyLw== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@vitest/expect" "2.0.2" + "@vitest/pretty-format" "^2.0.2" + "@vitest/runner" "2.0.2" + "@vitest/snapshot" "2.0.2" + "@vitest/spy" "2.0.2" + "@vitest/utils" "2.0.2" + chai "^5.1.1" + debug "^4.3.5" execa "^8.0.1" - local-pkg "^0.5.0" - magic-string "^0.30.5" - pathe "^1.1.1" - picocolors "^1.0.0" - std-env "^3.5.0" - strip-literal "^2.0.0" - tinybench "^2.5.1" - tinypool "^0.8.3" + magic-string "^0.30.10" + pathe "^1.1.2" + std-env "^3.7.0" + tinybench "^2.8.0" + tinypool "^1.0.0" + tinyrainbow "^1.2.0" vite "^5.0.0" - vite-node "1.6.0" + vite-node "2.0.2" why-is-node-running "^2.2.2" w3c-xmlserializer@^4.0.0: @@ -16599,11 +16418,6 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== -well-known-symbols@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/well-known-symbols/-/well-known-symbols-2.0.0.tgz#e9c7c07dbd132b7b84212c8174391ec1f9871ba5" - integrity sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q== - whatwg-encoding@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53"