From 2cdd0dede07399cf6f8d6f52aa2f5efbcf2759f3 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 09:19:06 +0100 Subject: [PATCH 01/56] feat(DTFS2-7052): new API modules and endpoint /api/v1/geospatial/addresses/postcode?postcode=W1A1AA --- .cspell.json | 14 +- .env.sample | 6 + src/config/index.ts | 3 +- src/config/ordnance-survey.config.test.ts | 39 ++++++ src/config/ordnance-survey.config.ts | 21 +++ .../dto/get-addresses-response.dto.ts | 90 ++++++++++++ .../dto/get-search-postcode-query.dto.ts | 3 + ...-search-places-v1-postcode-no-results.json | 15 ++ ...esponse-for-search-places-v1-postcode.json | 53 ++++++++ .../ordnance-survey.exception.test.ts | 28 ++++ .../exception/ordnance-survey.exception.ts | 9 ++ .../ordnance-survey/known-errors.ts | 13 ++ .../ordnance-survey/ordnance-survey.module.ts | 26 ++++ .../ordnance-survey.service.test.ts | 128 ++++++++++++++++++ .../ordnance-survey.service.ts | 35 +++++ ...rap-ordnance-survey-http-error-callback.ts | 32 +++++ 16 files changed, 513 insertions(+), 2 deletions(-) create mode 100644 src/config/ordnance-survey.config.test.ts create mode 100644 src/config/ordnance-survey.config.ts create mode 100644 src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts create mode 100644 src/helper_modules/ordnance-survey/dto/get-search-postcode-query.dto.ts create mode 100644 src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json create mode 100644 src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json create mode 100644 src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.test.ts create mode 100644 src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.ts create mode 100644 src/helper_modules/ordnance-survey/known-errors.ts create mode 100644 src/helper_modules/ordnance-survey/ordnance-survey.module.ts create mode 100644 src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts create mode 100644 src/helper_modules/ordnance-survey/ordnance-survey.service.ts create mode 100644 src/helper_modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts diff --git a/.cspell.json b/.cspell.json index c2e875a8..0a7de18b 100644 --- a/.cspell.json +++ b/.cspell.json @@ -51,7 +51,19 @@ "ukef", "venv", "VNET", - "CICD" + "CICD", + "DPA", + "UPRN", + "UDPRN", + "BLPU", + "TOID", + "EPSG", + "WOGAN", + "osgb", + "HJLNP", + "Zabd", + "hjlnp", + "BLPUs" ], "dictionaries": [ "en-gb", diff --git a/.env.sample b/.env.sample index 673bc1e0..68141bee 100644 --- a/.env.sample +++ b/.env.sample @@ -39,3 +39,9 @@ APIM_INFORMATICA_USERNAME= APIM_INFORMATICA_PASSWORD= APIM_INFORMATICA_MAX_REDIRECTS= APIM_INFORMATICA_TIMEOUT= + +# ORDANANCE SURVEY +ORDNANCE_SURVEY_URL= +ORDNANCE_SURVEY_KEY= +ORDNANCE_SURVEY_MAX_REDIRECTS= +ORDNANCE_SURVEY_TIMEOUT= diff --git a/src/config/index.ts b/src/config/index.ts index 4e89f16d..29fe1c91 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -2,5 +2,6 @@ import AppConfig from './app.config'; import DatabaseConfig from './database.config'; import DocConfig from './doc.config'; import InformaticaConfig from './informatica.config'; +import OrdnanceSurveyConfig from './ordnance-survey.config'; -export default [AppConfig, DocConfig, DatabaseConfig, InformaticaConfig]; +export default [AppConfig, DocConfig, DatabaseConfig, InformaticaConfig, OrdnanceSurveyConfig]; diff --git a/src/config/ordnance-survey.config.test.ts b/src/config/ordnance-survey.config.test.ts new file mode 100644 index 00000000..5b22020e --- /dev/null +++ b/src/config/ordnance-survey.config.test.ts @@ -0,0 +1,39 @@ +import { withEnvironmentVariableParsingUnitTests } from '@ukef-test/common-tests/environment-variable-parsing-unit-tests'; + +import ordnanceSurveyConfig, { OrdnanceSurveyConfig } from './ordnance-survey.config'; + +describe('ordnanceSurveyConfig', () => { + const configDirectlyFromEnvironmentVariables: { configPropertyName: keyof OrdnanceSurveyConfig; environmentVariableName: string }[] = [ + { + configPropertyName: 'baseUrl', + environmentVariableName: 'ORDNANCE_SURVEY_URL', + }, + { + configPropertyName: 'key', + environmentVariableName: 'ORDNANCE_SURVEY_KEY', + }, + ]; + + const configParsedAsIntFromEnvironmentVariablesWithDefault: { + configPropertyName: keyof OrdnanceSurveyConfig; + environmentVariableName: string; + defaultConfigValue: number; + }[] = [ + { + configPropertyName: 'maxRedirects', + environmentVariableName: 'ORDNANCE_SURVEY_MAX_REDIRECTS', + defaultConfigValue: 5, + }, + { + configPropertyName: 'timeout', + environmentVariableName: 'ORDNANCE_SURVEY_TIMEOUT', + defaultConfigValue: 30000, + }, + ]; + + withEnvironmentVariableParsingUnitTests({ + configDirectlyFromEnvironmentVariables, + configParsedAsIntFromEnvironmentVariablesWithDefault, + getConfig: () => ordnanceSurveyConfig(), + }); +}); diff --git a/src/config/ordnance-survey.config.ts b/src/config/ordnance-survey.config.ts new file mode 100644 index 00000000..e30acf8b --- /dev/null +++ b/src/config/ordnance-survey.config.ts @@ -0,0 +1,21 @@ +import { registerAs } from '@nestjs/config'; +import { getIntConfig } from '@ukef/helpers/get-int-config'; + +export const KEY = 'ordnanceSurvey'; + +export interface OrdnanceSurveyConfig { + baseUrl: string; + key: string; + maxRedirects: number; + timeout: number; +} + +export default registerAs( + KEY, + (): OrdnanceSurveyConfig => ({ + baseUrl: process.env.ORDNANCE_SURVEY_URL, + key: process.env.ORDNANCE_SURVEY_KEY, + maxRedirects: getIntConfig(process.env.ORDNANCE_SURVEY_MAX_REDIRECTS, 5), + timeout: getIntConfig(process.env.ORDNANCE_SURVEY_TIMEOUT, 30000), + }), +); diff --git a/src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts b/src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts new file mode 100644 index 00000000..5a9f6201 --- /dev/null +++ b/src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts @@ -0,0 +1,90 @@ +export type GetAddressResponse = { + header: { + uri: string, + query: string, + offset: number, + totalresults: number, + format: string, + dataset: string, + lr: string, + maxresults: number, + epoch: string, + lastupdate: string, + output_srs: string + }, + results?: GetAddressResponseItem[], +}; + +interface GetAddressResponseItem { + DPA: { + UPRN: string, + UDPRN: string, + ADDRESS: string, + BUILDING_NAME?: string, + BUILDING_NUMBER?: string, + ORGANISATION_NAME?: string; + DEPENDENT_LOCALITY?: string; + THOROUGHFARE_NAME: string, + POST_TOWN: string, + POSTCODE: string, + RPC: string, + X_COORDINATE: number, + Y_COORDINATE: number, + STATUS: string, + LOGICAL_STATUS_CODE: string, + CLASSIFICATION_CODE: string, + CLASSIFICATION_CODE_DESCRIPTION: string, + LOCAL_CUSTODIAN_CODE: number, + LOCAL_CUSTODIAN_CODE_DESCRIPTION: string, + COUNTRY_CODE: string, + COUNTRY_CODE_DESCRIPTION: string, + POSTAL_ADDRESS_CODE: string, + POSTAL_ADDRESS_CODE_DESCRIPTION: string, + BLPU_STATE_CODE: string, + BLPU_STATE_CODE_DESCRIPTION: string, + TOPOGRAPHY_LAYER_TOID: string, + LAST_UPDATE_DATE: string, + ENTRY_DATE: string, + BLPU_STATE_DATE: string, + LANGUAGE: string, + MATCH: number, + MATCH_DESCRIPTION: string, + DELIVERY_POINT_SUFFIX: string + } +} + +// interface GetAddressResponseAddress { +// UPRN: string, +// UDPRN: string, +// ADDRESS: string, +// BUILDING_NAME?: string, +// BUILDING_NUMBER?: string, +// ORGANISATION_NAME?: string; +// DEPENDENT_LOCALITY?: string; +// THOROUGHFARE_NAME: string, +// POST_TOWN: string, +// POSTCODE: string, +// RPC: string, +// X_COORDINATE: number, +// Y_COORDINATE: number, +// STATUS: string, +// LOGICAL_STATUS_CODE: string, +// CLASSIFICATION_CODE: string, +// CLASSIFICATION_CODE_DESCRIPTION: string, +// LOCAL_CUSTODIAN_CODE: number, +// LOCAL_CUSTODIAN_CODE_DESCRIPTION: string, +// COUNTRY_CODE: string, +// COUNTRY_CODE_DESCRIPTION: string, +// POSTAL_ADDRESS_CODE: string, +// POSTAL_ADDRESS_CODE_DESCRIPTION: string, +// BLPU_STATE_CODE: string, +// BLPU_STATE_CODE_DESCRIPTION: string, +// TOPOGRAPHY_LAYER_TOID: string, +// LAST_UPDATE_DATE: string, +// ENTRY_DATE: string, +// BLPU_STATE_DATE: string, +// LANGUAGE: string, +// MATCH: number, +// MATCH_DESCRIPTION: string, +// DELIVERY_POINT_SUFFIX: string +// } diff --git a/src/helper_modules/ordnance-survey/dto/get-search-postcode-query.dto.ts b/src/helper_modules/ordnance-survey/dto/get-search-postcode-query.dto.ts new file mode 100644 index 00000000..8f8ea0f2 --- /dev/null +++ b/src/helper_modules/ordnance-survey/dto/get-search-postcode-query.dto.ts @@ -0,0 +1,3 @@ +export class GetSearchPostcodeOrdnanceSurveyQueryDto { + public postcode: string; +} diff --git a/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json b/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json new file mode 100644 index 00000000..2223c9e4 --- /dev/null +++ b/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json @@ -0,0 +1,15 @@ +{ + "header": { + "uri": "https://api.os.uk/search/places/v1/postcode?postcode=CV1%2011M", + "query": "postcode=CV1 11M", + "offset": 0, + "totalresults": 0, + "format": "JSON", + "dataset": "DPA", + "lr": "EN,CY", + "maxresults": 100, + "epoch": "109", + "lastupdate": "2024-04-05", + "output_srs": "EPSG:27700" + } +} \ No newline at end of file diff --git a/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json b/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json new file mode 100644 index 00000000..335f7c1e --- /dev/null +++ b/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json @@ -0,0 +1,53 @@ +{ + "header": { + "uri": "https://api.os.uk/search/places/v1/postcode?postcode=W1A%201AA", + "query": "postcode=W1A 1AA", + "offset": 0, + "totalresults": 1, + "format": "JSON", + "dataset": "DPA", + "lr": "EN,CY", + "maxresults": 100, + "epoch": "109", + "lastupdate": "2024-04-09", + "output_srs": "EPSG:27700" + }, + "results": [ + { + "DPA": { + "UPRN": "10092008000", + "UDPRN": "25733000", + "ADDRESS": "BRITISH BROADCASTING CORPORATION, WOGAN HOUSE, PORTLAND PLACE, LONDON, W1A 1AA", + "ORGANISATION_NAME": "BRITISH BROADCASTING CORPORATION", + "BUILDING_NAME": "WOGAN HOUSE", + "THOROUGHFARE_NAME": "PORTLAND PLACE", + "POST_TOWN": "LONDON", + "POSTCODE": "W1A 1AA", + "RPC": "2", + "X_COORDINATE": 528960.0, + "Y_COORDINATE": 181680.0, + "STATUS": "APPROVED", + "LOGICAL_STATUS_CODE": "1", + "CLASSIFICATION_CODE": "OR00", + "CLASSIFICATION_CODE_DESCRIPTION": "Additional Mail / Packet Addressee", + "LOCAL_CUSTODIAN_CODE": 7600, + "LOCAL_CUSTODIAN_CODE_DESCRIPTION": "ORDNANCE SURVEY", + "COUNTRY_CODE": "E", + "COUNTRY_CODE_DESCRIPTION": "This record is within England", + "POSTAL_ADDRESS_CODE": "D", + "POSTAL_ADDRESS_CODE_DESCRIPTION": "A record which is linked to PAF", + "BLPU_STATE_CODE": "2", + "BLPU_STATE_CODE_DESCRIPTION": "In use", + "TOPOGRAPHY_LAYER_TOID": "osgb1000005200000", + "PARENT_UPRN": "100023600000", + "LAST_UPDATE_DATE": "29/01/2023", + "ENTRY_DATE": "19/01/2012", + "BLPU_STATE_DATE": "01/01/2020", + "LANGUAGE": "EN", + "MATCH": 1.0, + "MATCH_DESCRIPTION": "EXACT", + "DELIVERY_POINT_SUFFIX": "1A" + } + } + ] +} diff --git a/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.test.ts b/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.test.ts new file mode 100644 index 00000000..aa7c8d96 --- /dev/null +++ b/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.test.ts @@ -0,0 +1,28 @@ +import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; + +import { OrdnanceSurveyException } from './ordnance-survey.exception'; + +describe('OrdnanceSurveyException', () => { + const valueGenerator = new RandomValueGenerator(); + const message = valueGenerator.string(); + + it('exposes the message it was created with', () => { + const exception = new OrdnanceSurveyException(message); + + expect(exception.message).toBe(message); + }); + + it('exposes the name of the exception', () => { + const exception = new OrdnanceSurveyException(message); + + expect(exception.name).toBe('OrdnanceSurveyException'); + }); + + it('exposes the inner error it was created with', () => { + const innerError = new Error(); + + const exception = new OrdnanceSurveyException(message, innerError); + + expect(exception.innerError).toBe(innerError); + }); +}); diff --git a/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.ts b/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.ts new file mode 100644 index 00000000..64ff9ebe --- /dev/null +++ b/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.ts @@ -0,0 +1,9 @@ +export class OrdnanceSurveyException extends Error { + constructor( + message: string, + public readonly innerError?: Error, + ) { + super(message); + this.name = this.constructor.name; + } +} diff --git a/src/helper_modules/ordnance-survey/known-errors.ts b/src/helper_modules/ordnance-survey/known-errors.ts new file mode 100644 index 00000000..5684be7d --- /dev/null +++ b/src/helper_modules/ordnance-survey/known-errors.ts @@ -0,0 +1,13 @@ +import { NotFoundException } from '@nestjs/common'; +import { AxiosError } from 'axios'; + +export type KnownErrors = KnownError[]; + +type KnownError = { caseInsensitiveSubstringToFind: string; throwError: (error: AxiosError) => never }; + +export const getCustomersNotFoundKnownOrdnanceSurveyError = (): KnownError => ({ + caseInsensitiveSubstringToFind: 'Company registration not found', + throwError: (error) => { + throw new NotFoundException('Customer not found.', error); + }, +}); diff --git a/src/helper_modules/ordnance-survey/ordnance-survey.module.ts b/src/helper_modules/ordnance-survey/ordnance-survey.module.ts new file mode 100644 index 00000000..553f756b --- /dev/null +++ b/src/helper_modules/ordnance-survey/ordnance-survey.module.ts @@ -0,0 +1,26 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule, ConfigService } from '@nestjs/config'; +import { OrdnanceSurveyConfig, KEY as ORDNANCE_SURVEY_CONFIG_KEY } from '@ukef/config/ordnance-survey.config'; +import { HttpModule } from '@ukef/modules/http/http.module'; + +import { OrdnanceSurveyService } from './ordnance-survey.service'; + +@Module({ + imports: [ + HttpModule.registerAsync({ + imports: [ConfigModule], + inject: [ConfigService], + useFactory: (configService: ConfigService) => { + const { baseUrl, maxRedirects, timeout } = configService.get(ORDNANCE_SURVEY_CONFIG_KEY); + return { + baseURL: baseUrl, + maxRedirects, + timeout, + }; + }, + }), + ], + providers: [OrdnanceSurveyService], + exports: [OrdnanceSurveyService], +}) +export class OrdnanceSurveyModule {} diff --git a/src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts new file mode 100644 index 00000000..e895730a --- /dev/null +++ b/src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts @@ -0,0 +1,128 @@ +import { HttpService } from '@nestjs/axios'; +import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; +import { AxiosError } from 'axios'; +import { when } from 'jest-when'; +import { of, throwError } from 'rxjs'; + +import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; +import { OrdnanceSurveyService } from './ordnance-survey.service'; +import { ConfigService } from '@nestjs/config'; + +const expectedResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); +const noResultsResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); + +describe('OrdnanceSurveyService', () => { + const valueGenerator = new RandomValueGenerator(); + + let httpServiceGet: jest.Mock; + let configServiceGet: jest.Mock; + let service: OrdnanceSurveyService; + + const testPostcode = 'W1A 1AA'; + const testKey = valueGenerator.string({length: 10}); + const basePath = '/search/places/v1/postcode'; + + beforeEach(() => { + const httpService = new HttpService(); + const configService = new ConfigService(); + httpServiceGet = jest.fn(); + httpService.get = httpServiceGet; + + configServiceGet = jest.fn().mockReturnValue({key: testKey}); + configService.get = configServiceGet; + + service = new OrdnanceSurveyService(httpService, configService); + }); + + + + describe('getAddressesByPostcode', () => { + const expectedPath = `${basePath}?postcode=${testPostcode}&key=${testKey}`; + + const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; + + it('sends a GET to the Ordnance Survey API /search endpoint with the specified request', async () => { + when(httpServiceGet) + .calledWith(...expectedHttpServiceGetArgs) + .mockReturnValueOnce( + of({ + data: expectedResponse, + status: 200, + statusText: 'OK', + config: undefined, + headers: undefined, + }), + ); + + await service.getAddressesByPostcode(testPostcode); + + expect(httpServiceGet).toHaveBeenCalledTimes(1); + expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); + }); + + it.each([ + { + postcode: 'W1A 1AA', + expectedUrlQueryPart: `?postcode=W1A%201AA`, + }, + { + postcode: 'W1A1AA', + expectedUrlQueryPart: '?postcode=W1A1AA', + }, + ])('call Ordnance Survey API with correct and safe query parameters "$expectedUrlQueryPart"', async ({ postcode, expectedUrlQueryPart }) => { + // const expectedPath = `${basePath}${expectedUrlQueryPart}&key=${testKey}`; + + // const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; + + when(httpServiceGet) + .calledWith(...expectedHttpServiceGetArgs) + .mockReturnValueOnce( + of({ + data: expectedResponse, + status: 200, + statusText: 'OK', + config: undefined, + headers: undefined, + }), + ); + + await service.getAddressesByPostcode(testPostcode); + + expect(httpServiceGet).toHaveBeenCalledTimes(1); + expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); + }); + + it("no results - returns 200 without results", async () => { + when(httpServiceGet) + .calledWith(...expectedHttpServiceGetArgs) + .mockReturnValueOnce( + of({ + data: noResultsResponse, + status: 200, + statusText: 'OK', + config: undefined, + headers: undefined, + }), + ); + + const results = await service.getAddressesByPostcode(testPostcode); + + expect(httpServiceGet).toHaveBeenCalledTimes(1); + expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); + expect(results).toBe(noResultsResponse); + }); + + it('throws an OrdnanceSurveyException if the request to Ordnance Survey fails', async () => { + const axiosRequestError = new AxiosError(); + when(httpServiceGet) + .calledWith(...expectedHttpServiceGetArgs) + .mockReturnValueOnce(throwError(() => axiosRequestError)); + + const getCustomersPromise = service.getAddressesByPostcode(testPostcode); + + await expect(getCustomersPromise).rejects.toBeInstanceOf(OrdnanceSurveyException); + await expect(getCustomersPromise).rejects.toThrow('Failed to get response from Ordnance Survey API.'); + await expect(getCustomersPromise).rejects.toHaveProperty('innerError', axiosRequestError); + }); + }); +}); diff --git a/src/helper_modules/ordnance-survey/ordnance-survey.service.ts b/src/helper_modules/ordnance-survey/ordnance-survey.service.ts new file mode 100644 index 00000000..7443a9a5 --- /dev/null +++ b/src/helper_modules/ordnance-survey/ordnance-survey.service.ts @@ -0,0 +1,35 @@ +import { HttpService } from '@nestjs/axios'; +import { Injectable } from '@nestjs/common'; +import { HttpClient } from '@ukef/modules/http/http.client'; + +import { GetAddressResponse } from './dto/get-addresses-response.dto'; +// import { getCustomersNotFoundKnownOrdnanceSurveyError } from './known-errors'; +import { createWrapOrdnanceSurveyHttpGetErrorCallback } from './wrap-ordnance-survey-http-error-callback'; +import { ConfigService } from '@nestjs/config'; +import { OrdnanceSurveyConfig, KEY as ORDNANCE_SURVEY_CONFIG_KEY } from '@ukef/config/ordnance-survey.config'; + +@Injectable() +export class OrdnanceSurveyService { + private readonly httpClient: HttpClient; + private readonly key: string; + + constructor(httpService: HttpService, configService: ConfigService) { + this.httpClient = new HttpClient(httpService); + const { key } = configService.get(ORDNANCE_SURVEY_CONFIG_KEY); + this.key = key; + } + + async getAddressesByPostcode(postcode): Promise { + const path = '/search/places/v1/postcode?postcode=' + postcode + '&key=' + this.key; + const { data } = await this.httpClient.get({ + path, + headers: { 'Content-Type': 'application/json' }, + onError: createWrapOrdnanceSurveyHttpGetErrorCallback({ + messageForUnknownError: `Failed to get response from Ordnance Survey API.`, + knownErrors: [], + // knownErrors: [getCustomersNotFoundKnownOrdnanceSurveyError()], // TODO: should we change 200 no results to 404? + }), + }); + return data; + } +} diff --git a/src/helper_modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts b/src/helper_modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts new file mode 100644 index 00000000..cf1e4c1a --- /dev/null +++ b/src/helper_modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts @@ -0,0 +1,32 @@ +import { AxiosError } from 'axios'; +import { ObservableInput, throwError } from 'rxjs'; + +import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; +import { KnownErrors } from './known-errors'; + +type AcbsHttpErrorCallback = (error: Error) => ObservableInput; + +export const createWrapOrdnanceSurveyHttpGetErrorCallback = + ({ messageForUnknownError, knownErrors }: { messageForUnknownError: string; knownErrors: KnownErrors }): AcbsHttpErrorCallback => + (error: Error) => { + let errorString; + if (error instanceof AxiosError && error.response) { + if (typeof error.response.data === 'object') { + errorString = JSON.stringify(error.response.data); + } + if (typeof error.response.data === 'string') { + errorString = error.response.data; + } + if (errorString) { + const errorStringInLowerCase = errorString.toLowerCase(); + + knownErrors.forEach(({ caseInsensitiveSubstringToFind, throwError }) => { + if (errorStringInLowerCase.includes(caseInsensitiveSubstringToFind.toLowerCase())) { + return throwError(error); + } + }); + } + } + + return throwError(() => new OrdnanceSurveyException(messageForUnknownError, error)); + }; From 14a6a08485888f854935909f4039cd8eb9d261ae Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 09:50:43 +0100 Subject: [PATCH 02/56] feat(DTFS2-7052): new module geospatial --- .../dto/get-address-by-postcode-query.dto.ts | 16 +++++++ .../dto/get-search-addresses-response.dto.ts | 47 +++++++++++++++++++ .../geospatial/geospatial.controller.ts | 29 ++++++++++++ src/modules/geospatial/geospatial.module.ts | 12 +++++ src/modules/geospatial/geospatial.service.ts | 33 +++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts create mode 100644 src/modules/geospatial/dto/get-search-addresses-response.dto.ts create mode 100644 src/modules/geospatial/geospatial.controller.ts create mode 100644 src/modules/geospatial/geospatial.module.ts create mode 100644 src/modules/geospatial/geospatial.service.ts diff --git a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts new file mode 100644 index 00000000..d01a159f --- /dev/null +++ b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts @@ -0,0 +1,16 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { Matches, MaxLength, MinLength } from 'class-validator'; + +const UK_POSTCODE = /^[A-Za-z]{1,2}[0-9Rr][0-9A-Za-z]?\s?[0-9][ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; + +export class GetAddressByPostcodeQueryDto { + @ApiProperty({ + example: 'SW1A 2AQ', + description: 'Postcode to search for', + }) + @MinLength(5) + @MaxLength(8) + @Matches(UK_POSTCODE) + public postcode: string; +} + diff --git a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts b/src/modules/geospatial/dto/get-search-addresses-response.dto.ts new file mode 100644 index 00000000..d4b84090 --- /dev/null +++ b/src/modules/geospatial/dto/get-search-addresses-response.dto.ts @@ -0,0 +1,47 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export type GetSearchAddressesResponse = GetSearchAddressesResponseItem[]; + +export class GetSearchAddressesResponseItem { + @ApiProperty({ + description: 'Organisation name if available', + example: 'CHURCHILL MUSEUM & CABINET WAR ROOMS', + }) + readonly organisationName: string | null; + + @ApiProperty({ + description: 'Address line 1', + example: 'CLIVE STEPS KING CHARLES STREET', + }) + readonly addressLine1: string; + + @ApiProperty({ + description: 'Address line 2', + example: null, + }) + readonly addressLine2: string | null; + + @ApiProperty({ + description: 'Address line 3', + example: null, + }) + readonly addressLine3: string | null; + + @ApiProperty({ + description: 'Locality, Town', + example: 'LONDON', + }) + readonly locality: string | null; + + @ApiProperty({ + description: 'Postcode', + example: 'SW1A 2AQ', + }) + readonly postalCode: string | null; + + @ApiProperty({ + description: 'Country of address record', + example: null, + }) + readonly country: string | null; +} diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts new file mode 100644 index 00000000..74d4e8ff --- /dev/null +++ b/src/modules/geospatial/geospatial.controller.ts @@ -0,0 +1,29 @@ +import { BadRequestException, Controller, Get, Query } from '@nestjs/common'; +import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; + +import { GetSearchPostcodeOrdnanceSurveyQueryDto } from '@ukef/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto'; +import { GeospatialService } from './geospatial.service'; +import { GetAddressByPostcodeQueryDto } from './dto/get-address-by-postcode-query.dto'; +import { GetSearchAddressesResponse, GetSearchAddressesResponseItem } from './dto/get-search-addresses-response.dto'; + +@ApiTags('geospatial') +@Controller('geospatial') +export class GeospatialController { + constructor(private readonly geospatialService: GeospatialService) {} + + @Get('addresses/postcode') + @ApiOperation({ + summary: "A search based on a property's postcode. Will accept a full postcode consisting of the area, district, sector and unit e.g. SO16 0AS.", + }) + @ApiResponse({ + status: 200, + description: 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).', + type: [GetSearchAddressesResponseItem], + }) + @ApiNotFoundResponse({ + description: 'Customer not found.', + }) + getGeospatial(@Query() query: GetAddressByPostcodeQueryDto): Promise { + return this.geospatialService.getAddressesByPostcode(query.postcode); + } +} diff --git a/src/modules/geospatial/geospatial.module.ts b/src/modules/geospatial/geospatial.module.ts new file mode 100644 index 00000000..8d4ae4aa --- /dev/null +++ b/src/modules/geospatial/geospatial.module.ts @@ -0,0 +1,12 @@ +import { Module } from '@nestjs/common'; +import { OrdnanceSurveyModule } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.module'; + +import { GeospatialController } from './geospatial.controller'; +import { GeospatialService } from './geospatial.service'; + +@Module({ + imports: [OrdnanceSurveyModule], + controllers: [GeospatialController], + providers: [GeospatialService], +}) +export class GeospatialModule {} diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts new file mode 100644 index 00000000..e48de375 --- /dev/null +++ b/src/modules/geospatial/geospatial.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; + +import { GetSearchAddressesResponse } from './dto/get-search-addresses-response.dto'; + +@Injectable() +export class GeospatialService { + constructor(private readonly ordnanceSurveyService: OrdnanceSurveyService) {} + + async getAddressesByPostcode(postcode: string): Promise { + let addresses = []; + const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); + + response.results.forEach((item) => { + // if (item.DPA.LANGUAGE === (req.query.language ? req.query.language : 'EN')) { + if (item.DPA.LANGUAGE === 'EN') { + // Ordnance survey sends duplicated results with the welsh version too via 'CY' + + addresses.push({ + organisationName: item.DPA.ORGANISATION_NAME || null, + addressLine1: `${item.DPA.BUILDING_NAME || ''} ${item.DPA.BUILDING_NUMBER || ''} ${item.DPA.THOROUGHFARE_NAME || ''}`.trim(), + addressLine2: item.DPA.DEPENDENT_LOCALITY || null, + addressLine3: null, // keys to match registered Address as requested, but not available in OS Places + locality: item.DPA.POST_TOWN || null, + postalCode: item.DPA.POSTCODE || null, + country: null, // keys to match registered Address as requested, but not available in OS Places + }); + } + }); + + return addresses; + } +} From 17fea546a3cf1e0945e85e653c7829544de41bfc Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 12:07:42 +0100 Subject: [PATCH 03/56] feat(DTFS2-7052): fixed lint errors --- .eslintrc.json | 9 +- jest.config.ts | 1 + .../dto/get-addresses-response.dto.ts | 56 ++++++++++++ .../dto/get-search-postcode-query.dto.ts | 0 ...-search-places-v1-postcode-no-results.json | 0 ...esponse-for-search-places-v1-postcode.json | 0 .../ordnance-survey.exception.test.ts | 0 .../exception/ordnance-survey.exception.ts | 0 .../ordnance-survey/known-errors.ts | 0 .../ordnance-survey/ordnance-survey.module.ts | 2 +- .../ordnance-survey.service.test.ts | 24 +++-- .../ordnance-survey.service.ts | 7 +- ...rap-ordnance-survey-http-error-callback.ts | 0 .../dto/get-addresses-response.dto.ts | 90 ------------------- .../dto/get-address-by-postcode-query.dto.ts | 3 +- .../geospatial/geospatial.controller.ts | 8 +- src/modules/geospatial/geospatial.service.ts | 5 +- src/modules/mdm.module.ts | 6 ++ tsconfig.json | 3 +- 19 files changed, 93 insertions(+), 121 deletions(-) create mode 100644 src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts rename src/{helper_modules => helper-modules}/ordnance-survey/dto/get-search-postcode-query.dto.ts (100%) rename src/{helper_modules => helper-modules}/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json (100%) rename src/{helper_modules => helper-modules}/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json (100%) rename src/{helper_modules => helper-modules}/ordnance-survey/exception/ordnance-survey.exception.test.ts (100%) rename src/{helper_modules => helper-modules}/ordnance-survey/exception/ordnance-survey.exception.ts (100%) rename src/{helper_modules => helper-modules}/ordnance-survey/known-errors.ts (100%) rename src/{helper_modules => helper-modules}/ordnance-survey/ordnance-survey.module.ts (92%) rename src/{helper_modules => helper-modules}/ordnance-survey/ordnance-survey.service.test.ts (83%) rename src/{helper_modules => helper-modules}/ordnance-survey/ordnance-survey.service.ts (88%) rename src/{helper_modules => helper-modules}/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts (100%) delete mode 100644 src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts diff --git a/.eslintrc.json b/.eslintrc.json index 7688571f..1b37c0d3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -15,14 +15,14 @@ "plugin:eslint-comments/recommended", "plugin:optimize-regex/recommended", "plugin:switch-case/recommended", - "plugin:security/recommended", + "plugin:security/recommended-legacy", "plugin:import/recommended", "plugin:import/typescript", "prettier" ], "parserOptions": { "project": "tsconfig.json", - "ecmaVersion": 2020, + "ecmaVersion": "latest", "sourceType": "module" }, "env": { @@ -110,7 +110,10 @@ "consistent-return": "off", "no-unused-vars": "off", "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": "error", + "unused-imports/no-unused-vars": [ + "error", + { "vars": "all", "varsIgnorePattern": "^_", "args": "after-used", "argsIgnorePattern": "^_" } + ], "@typescript-eslint/no-unused-vars": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-explicit-any": "off", diff --git a/jest.config.ts b/jest.config.ts index a4dfdb06..48c400f1 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -12,6 +12,7 @@ const defaultSettings = { '@ukef/config/(.*)': '/../src/config/$1', '@ukef/database/(.*)': '/../src/modules/database/$1', '@ukef/helpers/(.*)': '/../src/helpers/$1', + '@ukef/helper-modules/(.*)': '/../src/helper-modules/$1', '@ukef/modules/(.*)': '/../src/modules/$1', '@ukef/auth/(.*)': '/../src/modules/auth/$1', '@ukef/(.*)': '/../src/$1', diff --git a/src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts b/src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts new file mode 100644 index 00000000..755ef606 --- /dev/null +++ b/src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts @@ -0,0 +1,56 @@ +export type GetAddressResponse = { + header: { + uri: string; + query: string; + offset: number; + totalresults: number; + format: string; + dataset: string; + lr: string; + maxresults: number; + epoch: string; + lastupdate: string; + output_srs: string; + }; + results?: GetAddressResponseItem[]; +}; + +interface GetAddressResponseItem { + DPA: GetAddressResponseAddress; +} + +interface GetAddressResponseAddress { + UPRN: string; + UDPRN: string; + ADDRESS: string; + BUILDING_NAME?: string; + BUILDING_NUMBER?: string; + ORGANISATION_NAME?: string; + DEPENDENT_LOCALITY?: string; + THOROUGHFARE_NAME: string; + POST_TOWN: string; + POSTCODE: string; + RPC: string; + X_COORDINATE: number; + Y_COORDINATE: number; + STATUS: string; + LOGICAL_STATUS_CODE: string; + CLASSIFICATION_CODE: string; + CLASSIFICATION_CODE_DESCRIPTION: string; + LOCAL_CUSTODIAN_CODE: number; + LOCAL_CUSTODIAN_CODE_DESCRIPTION: string; + COUNTRY_CODE: string; + COUNTRY_CODE_DESCRIPTION: string; + POSTAL_ADDRESS_CODE: string; + POSTAL_ADDRESS_CODE_DESCRIPTION: string; + BLPU_STATE_CODE: string; + BLPU_STATE_CODE_DESCRIPTION: string; + TOPOGRAPHY_LAYER_TOID: string; + LAST_UPDATE_DATE: string; + ENTRY_DATE: string; + BLPU_STATE_DATE: string; + LANGUAGE: string; + MATCH: number; + MATCH_DESCRIPTION: string; + DELIVERY_POINT_SUFFIX: string; +} diff --git a/src/helper_modules/ordnance-survey/dto/get-search-postcode-query.dto.ts b/src/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto.ts similarity index 100% rename from src/helper_modules/ordnance-survey/dto/get-search-postcode-query.dto.ts rename to src/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto.ts diff --git a/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json b/src/helper-modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json similarity index 100% rename from src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json rename to src/helper-modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode-no-results.json diff --git a/src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json b/src/helper-modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json similarity index 100% rename from src/helper_modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json rename to src/helper-modules/ordnance-survey/examples/example-response-for-search-places-v1-postcode.json diff --git a/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.test.ts b/src/helper-modules/ordnance-survey/exception/ordnance-survey.exception.test.ts similarity index 100% rename from src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.test.ts rename to src/helper-modules/ordnance-survey/exception/ordnance-survey.exception.test.ts diff --git a/src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.ts b/src/helper-modules/ordnance-survey/exception/ordnance-survey.exception.ts similarity index 100% rename from src/helper_modules/ordnance-survey/exception/ordnance-survey.exception.ts rename to src/helper-modules/ordnance-survey/exception/ordnance-survey.exception.ts diff --git a/src/helper_modules/ordnance-survey/known-errors.ts b/src/helper-modules/ordnance-survey/known-errors.ts similarity index 100% rename from src/helper_modules/ordnance-survey/known-errors.ts rename to src/helper-modules/ordnance-survey/known-errors.ts diff --git a/src/helper_modules/ordnance-survey/ordnance-survey.module.ts b/src/helper-modules/ordnance-survey/ordnance-survey.module.ts similarity index 92% rename from src/helper_modules/ordnance-survey/ordnance-survey.module.ts rename to src/helper-modules/ordnance-survey/ordnance-survey.module.ts index 553f756b..2afb21df 100644 --- a/src/helper_modules/ordnance-survey/ordnance-survey.module.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.module.ts @@ -1,6 +1,6 @@ import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; -import { OrdnanceSurveyConfig, KEY as ORDNANCE_SURVEY_CONFIG_KEY } from '@ukef/config/ordnance-survey.config'; +import { KEY as ORDNANCE_SURVEY_CONFIG_KEY, OrdnanceSurveyConfig } from '@ukef/config/ordnance-survey.config'; import { HttpModule } from '@ukef/modules/http/http.module'; import { OrdnanceSurveyService } from './ordnance-survey.service'; diff --git a/src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts similarity index 83% rename from src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts rename to src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index e895730a..6ed18f36 100644 --- a/src/helper_modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -1,15 +1,14 @@ import { HttpService } from '@nestjs/axios'; +import { ConfigService } from '@nestjs/config'; import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; import { AxiosError } from 'axios'; import { when } from 'jest-when'; import { of, throwError } from 'rxjs'; +import expectedResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); +import noResultsResponse = require('./examples/example-response-for-search-places-v1-postcode-no-results.json'); import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; import { OrdnanceSurveyService } from './ordnance-survey.service'; -import { ConfigService } from '@nestjs/config'; - -const expectedResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); -const noResultsResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); describe('OrdnanceSurveyService', () => { const valueGenerator = new RandomValueGenerator(); @@ -19,7 +18,7 @@ describe('OrdnanceSurveyService', () => { let service: OrdnanceSurveyService; const testPostcode = 'W1A 1AA'; - const testKey = valueGenerator.string({length: 10}); + const testKey = valueGenerator.string({ length: 10 }); const basePath = '/search/places/v1/postcode'; beforeEach(() => { @@ -28,16 +27,14 @@ describe('OrdnanceSurveyService', () => { httpServiceGet = jest.fn(); httpService.get = httpServiceGet; - configServiceGet = jest.fn().mockReturnValue({key: testKey}); + configServiceGet = jest.fn().mockReturnValue({ key: testKey }); configService.get = configServiceGet; service = new OrdnanceSurveyService(httpService, configService); }); - - describe('getAddressesByPostcode', () => { - const expectedPath = `${basePath}?postcode=${testPostcode}&key=${testKey}`; + const expectedPath = `${basePath}?postcode=${encodeURIComponent(testPostcode)}&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; @@ -70,9 +67,8 @@ describe('OrdnanceSurveyService', () => { expectedUrlQueryPart: '?postcode=W1A1AA', }, ])('call Ordnance Survey API with correct and safe query parameters "$expectedUrlQueryPart"', async ({ postcode, expectedUrlQueryPart }) => { - // const expectedPath = `${basePath}${expectedUrlQueryPart}&key=${testKey}`; - - // const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; + const expectedPath = `${basePath}${expectedUrlQueryPart}&key=${encodeURIComponent(testKey)}`; + const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; when(httpServiceGet) .calledWith(...expectedHttpServiceGetArgs) @@ -86,13 +82,13 @@ describe('OrdnanceSurveyService', () => { }), ); - await service.getAddressesByPostcode(testPostcode); + await service.getAddressesByPostcode(postcode); expect(httpServiceGet).toHaveBeenCalledTimes(1); expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); }); - it("no results - returns 200 without results", async () => { + it('no results - returns 200 without results', async () => { when(httpServiceGet) .calledWith(...expectedHttpServiceGetArgs) .mockReturnValueOnce( diff --git a/src/helper_modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts similarity index 88% rename from src/helper_modules/ordnance-survey/ordnance-survey.service.ts rename to src/helper-modules/ordnance-survey/ordnance-survey.service.ts index 7443a9a5..5464166e 100644 --- a/src/helper_modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -1,12 +1,12 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { KEY as ORDNANCE_SURVEY_CONFIG_KEY, OrdnanceSurveyConfig } from '@ukef/config/ordnance-survey.config'; import { HttpClient } from '@ukef/modules/http/http.client'; import { GetAddressResponse } from './dto/get-addresses-response.dto'; // import { getCustomersNotFoundKnownOrdnanceSurveyError } from './known-errors'; import { createWrapOrdnanceSurveyHttpGetErrorCallback } from './wrap-ordnance-survey-http-error-callback'; -import { ConfigService } from '@nestjs/config'; -import { OrdnanceSurveyConfig, KEY as ORDNANCE_SURVEY_CONFIG_KEY } from '@ukef/config/ordnance-survey.config'; @Injectable() export class OrdnanceSurveyService { @@ -20,7 +20,8 @@ export class OrdnanceSurveyService { } async getAddressesByPostcode(postcode): Promise { - const path = '/search/places/v1/postcode?postcode=' + postcode + '&key=' + this.key; + const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&key=${encodeURIComponent(this.key)}`; + const { data } = await this.httpClient.get({ path, headers: { 'Content-Type': 'application/json' }, diff --git a/src/helper_modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts b/src/helper-modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts similarity index 100% rename from src/helper_modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts rename to src/helper-modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts diff --git a/src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts b/src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts deleted file mode 100644 index 5a9f6201..00000000 --- a/src/helper_modules/ordnance-survey/dto/get-addresses-response.dto.ts +++ /dev/null @@ -1,90 +0,0 @@ -export type GetAddressResponse = { - header: { - uri: string, - query: string, - offset: number, - totalresults: number, - format: string, - dataset: string, - lr: string, - maxresults: number, - epoch: string, - lastupdate: string, - output_srs: string - }, - results?: GetAddressResponseItem[], -}; - -interface GetAddressResponseItem { - DPA: { - UPRN: string, - UDPRN: string, - ADDRESS: string, - BUILDING_NAME?: string, - BUILDING_NUMBER?: string, - ORGANISATION_NAME?: string; - DEPENDENT_LOCALITY?: string; - THOROUGHFARE_NAME: string, - POST_TOWN: string, - POSTCODE: string, - RPC: string, - X_COORDINATE: number, - Y_COORDINATE: number, - STATUS: string, - LOGICAL_STATUS_CODE: string, - CLASSIFICATION_CODE: string, - CLASSIFICATION_CODE_DESCRIPTION: string, - LOCAL_CUSTODIAN_CODE: number, - LOCAL_CUSTODIAN_CODE_DESCRIPTION: string, - COUNTRY_CODE: string, - COUNTRY_CODE_DESCRIPTION: string, - POSTAL_ADDRESS_CODE: string, - POSTAL_ADDRESS_CODE_DESCRIPTION: string, - BLPU_STATE_CODE: string, - BLPU_STATE_CODE_DESCRIPTION: string, - TOPOGRAPHY_LAYER_TOID: string, - LAST_UPDATE_DATE: string, - ENTRY_DATE: string, - BLPU_STATE_DATE: string, - LANGUAGE: string, - MATCH: number, - MATCH_DESCRIPTION: string, - DELIVERY_POINT_SUFFIX: string - } -} - -// interface GetAddressResponseAddress { -// UPRN: string, -// UDPRN: string, -// ADDRESS: string, -// BUILDING_NAME?: string, -// BUILDING_NUMBER?: string, -// ORGANISATION_NAME?: string; -// DEPENDENT_LOCALITY?: string; -// THOROUGHFARE_NAME: string, -// POST_TOWN: string, -// POSTCODE: string, -// RPC: string, -// X_COORDINATE: number, -// Y_COORDINATE: number, -// STATUS: string, -// LOGICAL_STATUS_CODE: string, -// CLASSIFICATION_CODE: string, -// CLASSIFICATION_CODE_DESCRIPTION: string, -// LOCAL_CUSTODIAN_CODE: number, -// LOCAL_CUSTODIAN_CODE_DESCRIPTION: string, -// COUNTRY_CODE: string, -// COUNTRY_CODE_DESCRIPTION: string, -// POSTAL_ADDRESS_CODE: string, -// POSTAL_ADDRESS_CODE_DESCRIPTION: string, -// BLPU_STATE_CODE: string, -// BLPU_STATE_CODE_DESCRIPTION: string, -// TOPOGRAPHY_LAYER_TOID: string, -// LAST_UPDATE_DATE: string, -// ENTRY_DATE: string, -// BLPU_STATE_DATE: string, -// LANGUAGE: string, -// MATCH: number, -// MATCH_DESCRIPTION: string, -// DELIVERY_POINT_SUFFIX: string -// } diff --git a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts index d01a159f..698dbe25 100644 --- a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts +++ b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts @@ -1,7 +1,7 @@ import { ApiProperty } from '@nestjs/swagger'; import { Matches, MaxLength, MinLength } from 'class-validator'; -const UK_POSTCODE = /^[A-Za-z]{1,2}[0-9Rr][0-9A-Za-z]?\s?[0-9][ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; +const UK_POSTCODE = /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; export class GetAddressByPostcodeQueryDto { @ApiProperty({ @@ -13,4 +13,3 @@ export class GetAddressByPostcodeQueryDto { @Matches(UK_POSTCODE) public postcode: string; } - diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 74d4e8ff..4c25561a 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -1,10 +1,9 @@ -import { BadRequestException, Controller, Get, Query } from '@nestjs/common'; +import { Controller, Get, Query } from '@nestjs/common'; import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; -import { GetSearchPostcodeOrdnanceSurveyQueryDto } from '@ukef/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto'; -import { GeospatialService } from './geospatial.service'; import { GetAddressByPostcodeQueryDto } from './dto/get-address-by-postcode-query.dto'; import { GetSearchAddressesResponse, GetSearchAddressesResponseItem } from './dto/get-search-addresses-response.dto'; +import { GeospatialService } from './geospatial.service'; @ApiTags('geospatial') @Controller('geospatial') @@ -17,7 +16,8 @@ export class GeospatialController { }) @ApiResponse({ status: 200, - description: 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).', + description: + 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).', type: [GetSearchAddressesResponseItem], }) @ApiNotFoundResponse({ diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index e48de375..af45adab 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -8,14 +8,13 @@ export class GeospatialService { constructor(private readonly ordnanceSurveyService: OrdnanceSurveyService) {} async getAddressesByPostcode(postcode: string): Promise { - let addresses = []; + const addresses = []; const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); response.results.forEach((item) => { // if (item.DPA.LANGUAGE === (req.query.language ? req.query.language : 'EN')) { + // Ordnance survey sends duplicated results with the welsh version too via 'CY' if (item.DPA.LANGUAGE === 'EN') { - // Ordnance survey sends duplicated results with the welsh version too via 'CY' - addresses.push({ organisationName: item.DPA.ORGANISATION_NAME || null, addressLine1: `${item.DPA.BUILDING_NAME || ''} ${item.DPA.BUILDING_NUMBER || ''} ${item.DPA.THOROUGHFARE_NAME || ''}`.trim(), diff --git a/src/modules/mdm.module.ts b/src/modules/mdm.module.ts index 2c16ce9b..9d3b7bfb 100644 --- a/src/modules/mdm.module.ts +++ b/src/modules/mdm.module.ts @@ -1,9 +1,11 @@ import { Module } from '@nestjs/common'; import { AuthModule } from '@ukef/auth/auth.module'; import { DatabaseModule } from '@ukef/database/database.module'; +import { OrdnanceSurveyModule } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.module'; import { CurrenciesModule } from '@ukef/modules/currencies/currencies.module'; import { CustomersModule } from '@ukef/modules/customers/customers.module'; import { ExposurePeriodModule } from '@ukef/modules/exposure-period/exposure-period.module'; +import { GeospatialModule } from '@ukef/modules/geospatial/geospatial.module'; import { HealthcheckModule } from '@ukef/modules/healthcheck/healthcheck.module'; import { InterestRatesModule } from '@ukef/modules/interest-rates/interest-rates.module'; import { MarketsModule } from '@ukef/modules/markets/markets.module'; @@ -26,6 +28,8 @@ import { YieldRatesModule } from '@ukef/modules/yield-rates/yield-rates.module'; PremiumSchedulesModule, SectorIndustriesModule, YieldRatesModule, + OrdnanceSurveyModule, + GeospatialModule, ], exports: [ AuthModule, @@ -40,6 +44,8 @@ import { YieldRatesModule } from '@ukef/modules/yield-rates/yield-rates.module'; PremiumSchedulesModule, SectorIndustriesModule, YieldRatesModule, + OrdnanceSurveyModule, + GeospatialModule, ], }) export class MdmModule {} diff --git a/tsconfig.json b/tsconfig.json index 0a1bd4bf..98d8c83e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,6 +32,7 @@ "@ukef/config/*": ["src/config/*"], "@ukef/database/*": ["src/modules/database/*"], "@ukef/helpers/*": ["src/helpers/*"], + "@ukef/helper-modules/*": ["src/helper-modules/*"], "@ukef/modules/*": ["src/modules/*"], "@ukef/auth/*": ["src/modules/auth/*"], "@ukef/swagger/*": ["src/swagger"], @@ -41,7 +42,7 @@ "include": [ "src", "test", - "jest.config.ts" + "jest.config.ts", ], "exclude": [ "node_modules", From a3d54338610f50f4824d6c6eeffa50ebdb6e91a2 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 12:52:00 +0100 Subject: [PATCH 04/56] feat(DTFS2-7052): adding constants and examples --- src/constants/enums.ts | 2 ++ src/constants/enums/geospatial.ts | 6 +++++ src/constants/geospatial.constant.ts | 9 ++++++++ src/constants/index.ts | 2 ++ .../ordnance-survey/known-errors.ts | 6 ++--- .../ordnance-survey.service.test.ts | 8 ++++--- .../ordnance-survey.service.ts | 3 ++- .../dto/get-address-by-postcode-query.dto.ts | 3 ++- .../dto/get-search-addresses-response.dto.ts | 6 +++-- .../geospatial/geospatial.controller.ts | 3 +-- src/modules/geospatial/geospatial.service.ts | 23 +++++++++---------- 11 files changed, 47 insertions(+), 24 deletions(-) create mode 100644 src/constants/enums/geospatial.ts create mode 100644 src/constants/geospatial.constant.ts diff --git a/src/constants/enums.ts b/src/constants/enums.ts index 848cb76b..dc997052 100644 --- a/src/constants/enums.ts +++ b/src/constants/enums.ts @@ -1,7 +1,9 @@ import * as FALLBACK_TO_LEGACY_DATA from './enums/fallbackToLegacyData'; +import * as GEOSPATIAL from './enums/geospatial'; import * as PRODUCTS from './enums/products'; export const ENUMS = { PRODUCTS: PRODUCTS.QueryParamProductsEnum, FALLBACK_TO_LEGACY_DATA: FALLBACK_TO_LEGACY_DATA.FallbackToLegacyDataEnum, + GEOSPATIAL_COUNTRIES: GEOSPATIAL.GeospatialCountriesEnum, }; diff --git a/src/constants/enums/geospatial.ts b/src/constants/enums/geospatial.ts new file mode 100644 index 00000000..f181289d --- /dev/null +++ b/src/constants/enums/geospatial.ts @@ -0,0 +1,6 @@ +export enum GeospatialCountriesEnum { + E = 'England', + S = 'Scotland', + W = 'Wales', + N = 'Northern Ireland', +} diff --git a/src/constants/geospatial.constant.ts b/src/constants/geospatial.constant.ts new file mode 100644 index 00000000..08bd74c2 --- /dev/null +++ b/src/constants/geospatial.constant.ts @@ -0,0 +1,9 @@ +export const GEOSPATIAL = { + DEFAULT: { + RESULT_LANGUAGE: 'EN', + DATASET: 'DPA', + }, + EXAMPLES: { + POSTCODE: 'SW1A 2AQ', + }, +}; diff --git a/src/constants/index.ts b/src/constants/index.ts index 7bd70773..dd7a98e7 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -9,6 +9,7 @@ * 5. Customers * 6. Strings to redact * 7. Strings locations to redact + * 8. Module geospatial */ export * from './auth.constant'; @@ -16,6 +17,7 @@ export * from './customers.constant'; export * from './database-name.constant'; export * from './date.constant'; export * from './enums'; +export * from './geospatial.constant'; export * from './products.constant'; export * from './redact-strings.constant'; export * from './redact-strings-paths.constant'; diff --git a/src/helper-modules/ordnance-survey/known-errors.ts b/src/helper-modules/ordnance-survey/known-errors.ts index 5684be7d..48c9d029 100644 --- a/src/helper-modules/ordnance-survey/known-errors.ts +++ b/src/helper-modules/ordnance-survey/known-errors.ts @@ -5,9 +5,9 @@ export type KnownErrors = KnownError[]; type KnownError = { caseInsensitiveSubstringToFind: string; throwError: (error: AxiosError) => never }; -export const getCustomersNotFoundKnownOrdnanceSurveyError = (): KnownError => ({ - caseInsensitiveSubstringToFind: 'Company registration not found', +export const getAddressNotFoundKnownOrdnanceSurveyError = (): KnownError => ({ + caseInsensitiveSubstringToFind: 'Address not found', throwError: (error) => { - throw new NotFoundException('Customer not found.', error); + throw new NotFoundException('Address not found.', error); }, }); diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index 6ed18f36..e3cfceca 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -7,6 +7,8 @@ import { of, throwError } from 'rxjs'; import expectedResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); import noResultsResponse = require('./examples/example-response-for-search-places-v1-postcode-no-results.json'); +import { GEOSPATIAL } from '@ukef/constants'; + import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; import { OrdnanceSurveyService } from './ordnance-survey.service'; @@ -17,7 +19,7 @@ describe('OrdnanceSurveyService', () => { let configServiceGet: jest.Mock; let service: OrdnanceSurveyService; - const testPostcode = 'W1A 1AA'; + const testPostcode = GEOSPATIAL.EXAMPLES.POSTCODE; const testKey = valueGenerator.string({ length: 10 }); const basePath = '/search/places/v1/postcode'; @@ -34,7 +36,7 @@ describe('OrdnanceSurveyService', () => { }); describe('getAddressesByPostcode', () => { - const expectedPath = `${basePath}?postcode=${encodeURIComponent(testPostcode)}&key=${encodeURIComponent(testKey)}`; + const expectedPath = `${basePath}?postcode=${encodeURIComponent(testPostcode)}&lr=EN&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; @@ -67,7 +69,7 @@ describe('OrdnanceSurveyService', () => { expectedUrlQueryPart: '?postcode=W1A1AA', }, ])('call Ordnance Survey API with correct and safe query parameters "$expectedUrlQueryPart"', async ({ postcode, expectedUrlQueryPart }) => { - const expectedPath = `${basePath}${expectedUrlQueryPart}&key=${encodeURIComponent(testKey)}`; + const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; when(httpServiceGet) diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts index 5464166e..dfa35330 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -2,6 +2,7 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { KEY as ORDNANCE_SURVEY_CONFIG_KEY, OrdnanceSurveyConfig } from '@ukef/config/ordnance-survey.config'; +import { GEOSPATIAL } from '@ukef/constants'; import { HttpClient } from '@ukef/modules/http/http.client'; import { GetAddressResponse } from './dto/get-addresses-response.dto'; @@ -20,7 +21,7 @@ export class OrdnanceSurveyService { } async getAddressesByPostcode(postcode): Promise { - const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&key=${encodeURIComponent(this.key)}`; + const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(this.key)}`; const { data } = await this.httpClient.get({ path, diff --git a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts index 698dbe25..6202fdd1 100644 --- a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts +++ b/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts @@ -1,11 +1,12 @@ import { ApiProperty } from '@nestjs/swagger'; +import { GEOSPATIAL } from '@ukef/constants'; import { Matches, MaxLength, MinLength } from 'class-validator'; const UK_POSTCODE = /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; export class GetAddressByPostcodeQueryDto { @ApiProperty({ - example: 'SW1A 2AQ', + example: GEOSPATIAL.EXAMPLES.POSTCODE, description: 'Postcode to search for', }) @MinLength(5) diff --git a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts b/src/modules/geospatial/dto/get-search-addresses-response.dto.ts index d4b84090..5ba8a8c7 100644 --- a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-search-addresses-response.dto.ts @@ -1,4 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; +import { ENUMS, GEOSPATIAL } from '@ukef/constants'; export type GetSearchAddressesResponse = GetSearchAddressesResponseItem[]; @@ -35,13 +36,14 @@ export class GetSearchAddressesResponseItem { @ApiProperty({ description: 'Postcode', - example: 'SW1A 2AQ', + example: GEOSPATIAL.EXAMPLES.POSTCODE, }) readonly postalCode: string | null; @ApiProperty({ description: 'Country of address record', - example: null, + example: ENUMS.GEOSPATIAL_COUNTRIES.E, + enum: ENUMS.GEOSPATIAL_COUNTRIES, }) readonly country: string | null; } diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 4c25561a..5c210dc5 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -16,8 +16,7 @@ export class GeospatialController { }) @ApiResponse({ status: 200, - description: - 'AddressBase® Premium Basic Land and Property Units (BLPUs) can reference two types of address and with the OS Places API it is possible to search for one at a time, or both. These are the Delivery Point Address (DPA) and the Land and Property Identifier (LPI).', + description: 'Returns addresses from Ordanance survey Delivery Point Address (DPA) system.', type: [GetSearchAddressesResponseItem], }) @ApiNotFoundResponse({ diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index af45adab..ca4f4a69 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@nestjs/common'; +import { ENUMS } from '@ukef/constants'; import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; import { GetSearchAddressesResponse } from './dto/get-search-addresses-response.dto'; @@ -12,19 +13,17 @@ export class GeospatialService { const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); response.results.forEach((item) => { - // if (item.DPA.LANGUAGE === (req.query.language ? req.query.language : 'EN')) { // Ordnance survey sends duplicated results with the welsh version too via 'CY' - if (item.DPA.LANGUAGE === 'EN') { - addresses.push({ - organisationName: item.DPA.ORGANISATION_NAME || null, - addressLine1: `${item.DPA.BUILDING_NAME || ''} ${item.DPA.BUILDING_NUMBER || ''} ${item.DPA.THOROUGHFARE_NAME || ''}`.trim(), - addressLine2: item.DPA.DEPENDENT_LOCALITY || null, - addressLine3: null, // keys to match registered Address as requested, but not available in OS Places - locality: item.DPA.POST_TOWN || null, - postalCode: item.DPA.POSTCODE || null, - country: null, // keys to match registered Address as requested, but not available in OS Places - }); - } + const item_data = item[Object.keys(item)[0]]; + addresses.push({ + organisationName: item_data.ORGANISATION_NAME || null, + addressLine1: `${item_data.BUILDING_NAME || ''} ${item_data.BUILDING_NUMBER || ''} ${item_data.THOROUGHFARE_NAME || ''}`.trim(), + addressLine2: item_data.DEPENDENT_LOCALITY || null, + addressLine3: null, + locality: item_data.POST_TOWN || null, + postalCode: item_data.POSTCODE || null, + country: ENUMS.GEOSPATIAL_COUNTRIES[item_data.COUNTRY_CODE], + }); }); return addresses; From 0b79772256a36fc8e5c9b38e3f67a0433984f2ab Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 12:54:02 +0100 Subject: [PATCH 05/56] feat(DTFS2-7052): adding typescript include for json files, to satify lint. I added big examples to json files --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index 98d8c83e..8b8ce17a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -43,6 +43,7 @@ "src", "test", "jest.config.ts", + "src/**/*.json", ], "exclude": [ "node_modules", From 1b6cf30cb4e960e64a2efb2b699aed75b61cd4d2 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 12:58:59 +0100 Subject: [PATCH 06/56] feat(DTFS2-7052): trying to automate husky run on commit --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 916ad6eb..506f1cec 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,8 @@ "start:debug": "nest start --debug --watch", "start:dev": "nest start --tsc --watch", "start:prod": "node dist/src/main", - "unit-test": "jest --selectProjects=Unit" + "unit-test": "jest --selectProjects=Unit", + "prepare": "husky" }, "lint-staged": { "**/package.json": "sort-package-json", From 5fbf3d78f38c1ce7847b482112ce2815ba2e4c7b Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 12:59:15 +0100 Subject: [PATCH 07/56] feat(DTFS2-7052): trying to automate husky run on commit --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 506f1cec..d5ef544c 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,13 @@ "housekeeping": "npm update --save --legacy-peer-deps && npm i --legacy-peer-deps && npm audit --fix && npm run spellcheck", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", + "prepare": "husky", "spellcheck": "cspell lint --gitignore --no-must-find-files --unique --no-progress --show-suggestions --color '**/*'", "start": "nest start", "start:debug": "nest start --debug --watch", "start:dev": "nest start --tsc --watch", "start:prod": "node dist/src/main", - "unit-test": "jest --selectProjects=Unit", - "prepare": "husky" + "unit-test": "jest --selectProjects=Unit" }, "lint-staged": { "**/package.json": "sort-package-json", From 889fe1b0c12152a2964afbf75cdede3ef1e6b48b Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Wed, 10 Apr 2024 14:16:20 +0100 Subject: [PATCH 08/56] feat(DTFS2-7052): change husky install to same way as in DTFS project --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d5ef544c..731bb763 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,9 @@ "api-test": "jest --selectProjects=API", "build": "nest build -p tsconfig.build.json", "housekeeping": "npm update --save --legacy-peer-deps && npm i --legacy-peer-deps && npm audit --fix && npm run spellcheck", + "postinstall": "husky install", "lint": "eslint . --ext .ts", "lint:fix": "eslint . --ext .ts --fix", - "prepare": "husky", "spellcheck": "cspell lint --gitignore --no-must-find-files --unique --no-progress --show-suggestions --color '**/*'", "start": "nest start", "start:debug": "nest start --debug --watch", From 21f800652587e12cf8cdcd457353b8a163221311 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 11 Apr 2024 09:14:36 +0100 Subject: [PATCH 09/56] feat(DTFS2-7052): work in progress of geospatial-get-address api tests --- ...addresses-ordnance-survey-response.dto.ts} | 10 +- ...rch-postcode-ordnance-survey-query.dto.ts} | 0 .../ordnance-survey.service.ts | 6 +- ...e.dto.ts => get-addresses-response.dto.ts} | 4 +- .../geospatial/geospatial.controller.ts | 6 +- src/modules/geospatial/geospatial.service.ts | 7 +- .../get-address-by-postcode.api-test.ts | 213 ++++++++++++++++++ .../get-geospatial-addresses-generator.ts | 148 ++++++++++++ .../generator/random-value-generator.ts | 12 + 9 files changed, 390 insertions(+), 16 deletions(-) rename src/helper-modules/ordnance-survey/dto/{get-addresses-response.dto.ts => get-addresses-ordnance-survey-response.dto.ts} (82%) rename src/helper-modules/ordnance-survey/dto/{get-search-postcode-query.dto.ts => get-search-postcode-ordnance-survey-query.dto.ts} (100%) rename src/modules/geospatial/dto/{get-search-addresses-response.dto.ts => get-addresses-response.dto.ts} (89%) create mode 100644 test/geospatial/get-address-by-postcode.api-test.ts create mode 100644 test/support/generator/get-geospatial-addresses-generator.ts diff --git a/src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts b/src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts similarity index 82% rename from src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts rename to src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts index 755ef606..f1c5b1f5 100644 --- a/src/helper-modules/ordnance-survey/dto/get-addresses-response.dto.ts +++ b/src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts @@ -1,4 +1,4 @@ -export type GetAddressResponse = { +export type GetAddressOrdnanceSurveyResponse = { header: { uri: string; query: string; @@ -12,14 +12,14 @@ export type GetAddressResponse = { lastupdate: string; output_srs: string; }; - results?: GetAddressResponseItem[]; + results?: GetAddressOrdnanceSurveyResponseItem[]; }; -interface GetAddressResponseItem { - DPA: GetAddressResponseAddress; +interface GetAddressOrdnanceSurveyResponseItem { + DPA: GetAddressOrdnanceSurveyResponseAddress; } -interface GetAddressResponseAddress { +interface GetAddressOrdnanceSurveyResponseAddress { UPRN: string; UDPRN: string; ADDRESS: string; diff --git a/src/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto.ts b/src/helper-modules/ordnance-survey/dto/get-search-postcode-ordnance-survey-query.dto.ts similarity index 100% rename from src/helper-modules/ordnance-survey/dto/get-search-postcode-query.dto.ts rename to src/helper-modules/ordnance-survey/dto/get-search-postcode-ordnance-survey-query.dto.ts diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts index dfa35330..4dbd137c 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -5,7 +5,7 @@ import { KEY as ORDNANCE_SURVEY_CONFIG_KEY, OrdnanceSurveyConfig } from '@ukef/c import { GEOSPATIAL } from '@ukef/constants'; import { HttpClient } from '@ukef/modules/http/http.client'; -import { GetAddressResponse } from './dto/get-addresses-response.dto'; +import { GetAddressOrdnanceSurveyResponse } from './dto/get-addresses-ordnance-survey-response.dto'; // import { getCustomersNotFoundKnownOrdnanceSurveyError } from './known-errors'; import { createWrapOrdnanceSurveyHttpGetErrorCallback } from './wrap-ordnance-survey-http-error-callback'; @@ -20,10 +20,10 @@ export class OrdnanceSurveyService { this.key = key; } - async getAddressesByPostcode(postcode): Promise { + async getAddressesByPostcode(postcode): Promise { const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(this.key)}`; - const { data } = await this.httpClient.get({ + const { data } = await this.httpClient.get({ path, headers: { 'Content-Type': 'application/json' }, onError: createWrapOrdnanceSurveyHttpGetErrorCallback({ diff --git a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts similarity index 89% rename from src/modules/geospatial/dto/get-search-addresses-response.dto.ts rename to src/modules/geospatial/dto/get-addresses-response.dto.ts index 5ba8a8c7..b458bf19 100644 --- a/src/modules/geospatial/dto/get-search-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -1,9 +1,9 @@ import { ApiProperty } from '@nestjs/swagger'; import { ENUMS, GEOSPATIAL } from '@ukef/constants'; -export type GetSearchAddressesResponse = GetSearchAddressesResponseItem[]; +export type GetAddressesResponse = GetAddressesResponseItem[]; -export class GetSearchAddressesResponseItem { +export class GetAddressesResponseItem { @ApiProperty({ description: 'Organisation name if available', example: 'CHURCHILL MUSEUM & CABINET WAR ROOMS', diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 5c210dc5..4d1580b7 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -2,7 +2,7 @@ import { Controller, Get, Query } from '@nestjs/common'; import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { GetAddressByPostcodeQueryDto } from './dto/get-address-by-postcode-query.dto'; -import { GetSearchAddressesResponse, GetSearchAddressesResponseItem } from './dto/get-search-addresses-response.dto'; +import { GetAddressesResponse, GetAddressesResponseItem } from './dto/get-addresses-response.dto'; import { GeospatialService } from './geospatial.service'; @ApiTags('geospatial') @@ -17,12 +17,12 @@ export class GeospatialController { @ApiResponse({ status: 200, description: 'Returns addresses from Ordanance survey Delivery Point Address (DPA) system.', - type: [GetSearchAddressesResponseItem], + type: [GetAddressesResponseItem], }) @ApiNotFoundResponse({ description: 'Customer not found.', }) - getGeospatial(@Query() query: GetAddressByPostcodeQueryDto): Promise { + getGeospatial(@Query() query: GetAddressByPostcodeQueryDto): Promise { return this.geospatialService.getAddressesByPostcode(query.postcode); } } diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index ca4f4a69..0c1b999e 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -1,16 +1,17 @@ import { Injectable } from '@nestjs/common'; import { ENUMS } from '@ukef/constants'; +import { GetAddressOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; -import { GetSearchAddressesResponse } from './dto/get-search-addresses-response.dto'; +import { GetAddressesResponse } from './dto/get-addresses-response.dto'; @Injectable() export class GeospatialService { constructor(private readonly ordnanceSurveyService: OrdnanceSurveyService) {} - async getAddressesByPostcode(postcode: string): Promise { + async getAddressesByPostcode(postcode: string): Promise { const addresses = []; - const response = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); + const response: GetAddressOrdnanceSurveyResponse = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); response.results.forEach((item) => { // Ordnance survey sends duplicated results with the welsh version too via 'CY' diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts new file mode 100644 index 00000000..a1522d29 --- /dev/null +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -0,0 +1,213 @@ +// import { CUSTOMERS, ENUMS } from '@ukef/constants'; +// import { IncorrectAuthArg, withClientAuthenticationTests } from '@ukef-test/common-tests/client-authentication-api-tests'; +import { Api } from '@ukef-test/support/api'; +// import { ENVIRONMENT_VARIABLES, TIME_EXCEEDING_INFORMATICA_TIMEOUT } from '@ukef-test/support/environment-variables'; +import { ENVIRONMENT_VARIABLES } from '@ukef-test/support/environment-variables'; +import { GetGeospatialAddressesGenerator } from '@ukef-test/support/generator/get-geospatial-addresses-generator'; +import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; +import nock from 'nock'; + +describe('GET /geospatial/addresses/postcode?postcode=', () => { + const valueGenerator = new RandomValueGenerator(); + + let api: Api; + + const { ordnanceSurveyPath, mdmPath, getAddressesByPostcodeResponse, getAddressOrdnanceSurveyResponse } = new GetGeospatialAddressesGenerator( + valueGenerator, + ).generate({ + numberToGenerate: 2, + }); + + // const getMdmUrl = (postcode: string) => `/api/v1/geospatial/addresses/postcode?postcode=${encodeURIComponent(postcode)}`; + + beforeAll(async () => { + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); + }); + + afterEach(() => { + nock.abortPendingRequests(); + nock.cleanAll(); + }); + + // withClientAuthenticationTests({ + // givenTheRequestWouldOtherwiseSucceed: () => { + // requestToGetCustomers(mdmPath[0]).reply(200, getAddressesByPostcodeResponse[0]); + // }, + // makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPath[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), + // }); + + it.only('returns a 200 response with the customers if they are returned by Informatica', async () => { + requestToGetCustomers(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + + const { status, body } = await api.get(mdmPath[0]); + + expect(status).toBe(200); + expect(body).toStrictEqual(getAddressesByPostcodeResponse[0]); + }); + + // it.each([ + // { + // query: { name: CUSTOMERS.EXAMPLES.NAME, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.YES }, + // }, + // { + // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.YES }, + // }, + // { + // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.YES }, + // }, + // { + // query: { name: CUSTOMERS.EXAMPLES.NAME, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.NO }, + // }, + // { + // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.NO }, + // }, + // { + // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.NO }, + // }, + // { + // query: { name: CUSTOMERS.EXAMPLES.NAME, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.LEGACY_ONLY }, + // }, + // { + // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.LEGACY_ONLY }, + // }, + // { + // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.LEGACY_ONLY }, + // }, + // { + // query: { name: CUSTOMERS.EXAMPLES.NAME }, + // }, + // { + // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG }, + // }, + // { + // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN }, + // }, + // ])('returns a 200 response with the customers if query is "$query"', async ({ query }) => { + // const { mdmPath, informaticaPath, getCustomersResponse } = new GetCustomersGenerator(valueGenerator).generate({ + // numberToGenerate: 1, + // query, + // }); + // requestToGetCustomers(informaticaPath).reply(200, getCustomersResponse[0]); + + // const { status, body } = await api.get(mdmPath); + + // expect(status).toBe(200); + // expect(body).toStrictEqual(getCustomersResponse[0]); + // }); + + // it('returns a 404 response if Informatica returns a 404 response with the string "null"', async () => { + // requestToGetCustomers(informaticaPath).reply(404, [ + // { + // errorCode: '404', + // errorDateTime: '2023-06-30T13:41:33Z', + // errorMessage: 'Company registration not found', + // errorDescription: 'Party details request for the requested company registration not found.', + // }, + // ]); + + // const { status, body } = await api.get(mdmPath); + + // expect(status).toBe(404); + // expect(body).toStrictEqual({ + // statusCode: 404, + // message: 'Customer not found.', + // }); + // }); + + // it('returns a 500 response if Informatica returns a status code that is NOT 200', async () => { + // requestToGetCustomers(informaticaPath).reply(401); + + // const { status, body } = await api.get(mdmPath); + + // expect(status).toBe(500); + // expect(body).toStrictEqual({ + // statusCode: 500, + // message: 'Internal server error', + // }); + // }); + + // it('returns a 500 response if getting the facility investors from ACBS times out', async () => { + // requestToGetCustomers(informaticaPath).delay(TIME_EXCEEDING_INFORMATICA_TIMEOUT).reply(200, getCustomersResponse[0]); + + // const { status, body } = await api.get(mdmPath); + + // expect(status).toBe(500); + // expect(body).toStrictEqual({ + // statusCode: 500, + // message: 'Internal server error', + // }); + // }); + + // it.each([ + // { + // query: { name: valueGenerator.string({ length: 1 }) }, + // expectedError: 'name must be longer than or equal to 2 characters', + // }, + // { + // query: { name: valueGenerator.string({ length: 256 }) }, + // expectedError: 'name must be shorter than or equal to 255 characters', + // }, + // { + // query: { name: valueGenerator.word(), extraParameter: valueGenerator.word() }, + // expectedError: 'property extraParameter should not exist', + // }, + // { + // query: { companyReg: valueGenerator.string({ length: 7 }) }, + // expectedError: 'companyReg must be longer than or equal to 8 characters', + // }, + // { + // query: { companyReg: valueGenerator.string({ length: 11 }) }, + // expectedError: 'companyReg must be shorter than or equal to 10 characters', + // }, + // { + // query: { partyUrn: valueGenerator.stringOfNumericCharacters({ length: 7 }) }, + // expectedError: 'partyUrn must match /^\\d{8}$/ regular expression', + // }, + // { + // query: { partyUrn: valueGenerator.stringOfNumericCharacters({ length: 9 }) }, + // expectedError: 'partyUrn must match /^\\d{8}$/ regular expression', + // }, + // { + // query: { partyUrn: valueGenerator.word() }, + // expectedError: 'partyUrn must match /^\\d{8}$/ regular expression', + // }, + // ])('returns a 400 response with error array if query is "$query"', async ({ query, expectedError }) => { + // const { status, body } = await api.get(getMdmUrl(query)); + + // expect(status).toBe(400); + // expect(body).toMatchObject({ + // error: 'Bad Request', + // message: expect.arrayContaining([expectedError]), + // statusCode: 400, + // }); + // }); + + // it.each([ + // { + // query: {}, + // expectedError: 'One and just one search parameter is required', + // }, + // { + // query: { name: valueGenerator.word(), companyReg: valueGenerator.string({ length: 8 }) }, + // expectedError: 'One and just one search parameter is required', + // }, + // ])('returns a 400 response with error string if query is "$query"', async ({ query, expectedError }) => { + // const { status, body } = await api.get(getMdmUrl(query)); + + // expect(status).toBe(400); + // expect(body).toMatchObject({ + // error: 'Bad Request', + // message: expectedError, + // statusCode: 400, + // }); + // }); + + const basicAuth = Buffer.from(`${ENVIRONMENT_VARIABLES.APIM_INFORMATICA_USERNAME}:${ENVIRONMENT_VARIABLES.APIM_INFORMATICA_PASSWORD}`).toString('base64'); + + const requestToGetCustomers = (informaticaPath: string): nock.Interceptor => + nock(ENVIRONMENT_VARIABLES.APIM_INFORMATICA_URL).get(informaticaPath).matchHeader('authorization', `Basic ${basicAuth}`); +}); diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts new file mode 100644 index 00000000..e24fab8a --- /dev/null +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -0,0 +1,148 @@ +import { ENUMS, GEOSPATIAL } from '@ukef/constants'; +import { GetAddressOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; +import { GetAddressByPostcodeQueryDto } from '@ukef/modules/geospatial/dto/get-address-by-postcode-query.dto'; +import { GetAddressesResponse } from '@ukef/modules/geospatial/dto/get-addresses-response.dto'; + +import { AbstractGenerator } from './abstract-generator'; +import { RandomValueGenerator } from './random-value-generator'; + +export class GetGeospatialAddressesGenerator extends AbstractGenerator { + constructor(protected readonly valueGenerator: RandomValueGenerator) { + super(valueGenerator); + } + + protected generateValues(): AddressValues { + return { + ORGANISATION_NAME: this.valueGenerator.word({ length: 5 }), + BUILDING_NAME: this.valueGenerator.word(), + BUILDING_NUMBER: this.valueGenerator.nonnegativeInteger().toString(), + THOROUGHFARE_NAME: this.valueGenerator.word({ length: 7 }), + DEPENDENT_LOCALITY: this.valueGenerator.word(), + POST_TOWN: this.valueGenerator.word(), + POSTCODE: this.valueGenerator.postcode(), + COUNTRY_CODE: this.valueGenerator.enumValue(ENUMS.GEOSPATIAL_COUNTRIES), + }; + } + + protected transformRawValuesToGeneratedValues(values: AddressValues[], { postcode, key }: GenerateOptions): GenerateResult { + const useKey = key || 'test'; + // let request: GetAddressByPostcodeQueryDto = ; + // let ordnanceSurveyRequest: GetCustomersInformaticaQueryDto[]; + // let ordnanceSurveyPath: 'test', + // let mdmPath: 'test', + // let getAddressesByPostcodeResponse: GetAddressesResponse[]; + + const request: GetAddressByPostcodeQueryDto[] = values.map((v) => ({ postcode: postcode || v.POSTCODE }) as GetAddressByPostcodeQueryDto); + + const ordnanceSurveyPath: string[] = values.map((v) => { + const usePostcode = postcode || v.POSTCODE; + return `/search/places/v1/postcode?postcode=${encodeURIComponent(usePostcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(useKey)}`; + }); + + const mdmPath: string[] = values.map((v) => { + const usePostcode = postcode || v.POSTCODE; + return `/api/v1/geospatial/addresses/postcode?postcode=${usePostcode}`; + }); + + const getAddressesByPostcodeResponse: GetAddressesResponse[] = values.map((v) => [ + { + organisationName: v.ORGANISATION_NAME, + addressLine1: `${v.BUILDING_NAME} ${v.BUILDING_NUMBER} ${v.THOROUGHFARE_NAME}`, + addressLine2: v.DEPENDENT_LOCALITY, + addressLine3: null, + locality: v.POST_TOWN || null, + postalCode: v.POSTCODE || null, + country: ENUMS.GEOSPATIAL_COUNTRIES[v.COUNTRY_CODE], + }, + ]); + + const getAddressOrdnanceSurveyResponse: GetAddressOrdnanceSurveyResponse[] = values.map((v) => ({ + header: { + uri: 'test', + query: 'test', + offset: 0, + totalresults: 1, + format: 'test', + dataset: 'test', + lr: 'test', + maxresults: 100, + epoch: 'test', + lastupdate: 'test', + output_srs: 'test', + }, + results: [ + { + DPA: { + UPRN: 'test', + UDPRN: 'test', + ADDRESS: 'test', + BUILDING_NAME: v.BUILDING_NAME, + BUILDING_NUMBER: v.BUILDING_NUMBER, + ORGANISATION_NAME: v.ORGANISATION_NAME, + DEPENDENT_LOCALITY: v.DEPENDENT_LOCALITY, + THOROUGHFARE_NAME: v.THOROUGHFARE_NAME, + POST_TOWN: v.POST_TOWN, + POSTCODE: v.POSTCODE, + RPC: 'test', + X_COORDINATE: 12345, + Y_COORDINATE: 12345, + STATUS: 'test', + LOGICAL_STATUS_CODE: 'test', + CLASSIFICATION_CODE: 'test', + CLASSIFICATION_CODE_DESCRIPTION: 'test', + LOCAL_CUSTODIAN_CODE: 12345, + LOCAL_CUSTODIAN_CODE_DESCRIPTION: 'test', + COUNTRY_CODE: v.COUNTRY_CODE, + COUNTRY_CODE_DESCRIPTION: 'test', + POSTAL_ADDRESS_CODE: 'test', + POSTAL_ADDRESS_CODE_DESCRIPTION: 'test', + BLPU_STATE_CODE: 'test', + BLPU_STATE_CODE_DESCRIPTION: 'test', + TOPOGRAPHY_LAYER_TOID: 'test', + LAST_UPDATE_DATE: 'test', + ENTRY_DATE: 'test', + BLPU_STATE_DATE: 'test', + LANGUAGE: 'test', + MATCH: 12345, + MATCH_DESCRIPTION: 'test', + DELIVERY_POINT_SUFFIX: 'test', + }, + }, + ], + })); + + return { + request, + // ordnanceSurveyRequest, + ordnanceSurveyPath, + mdmPath, + getAddressesByPostcodeResponse, + getAddressOrdnanceSurveyResponse, + }; + } +} + +interface AddressValues { + ORGANISATION_NAME: string; + BUILDING_NAME: string; + BUILDING_NUMBER: string; + THOROUGHFARE_NAME: string; + DEPENDENT_LOCALITY: string; + POST_TOWN: string; + POSTCODE: string; + COUNTRY_CODE: string; +} + +interface GenerateOptions { + postcode?: string; + key?: string; +} + +interface GenerateResult { + request: GetAddressByPostcodeQueryDto[]; + //ordnanceSurveyRequest: GetCustomersInformaticaQueryDto[]; + ordnanceSurveyPath: string[]; + mdmPath: string[]; + getAddressesByPostcodeResponse: GetAddressesResponse[]; + getAddressOrdnanceSurveyResponse: GetAddressOrdnanceSurveyResponse[]; +} diff --git a/test/support/generator/random-value-generator.ts b/test/support/generator/random-value-generator.ts index ff1c1983..612f9d59 100644 --- a/test/support/generator/random-value-generator.ts +++ b/test/support/generator/random-value-generator.ts @@ -1,5 +1,8 @@ import { Chance } from 'chance'; +interface Enum { + [key: number | string]: string | number; +} export class RandomValueGenerator { private static readonly seed = 0; private readonly chance: Chance.Chance; @@ -63,4 +66,13 @@ export class RandomValueGenerator { nonnegativeInteger({ max }: { max?: number } = {}): number { return this.integer({ min: 0, max }); } + + postcode(): string { + return this.chance.postcode(); + } + + enumValue(theEnum: Enum): T { + const possibleValues = Object.values(theEnum); + return possibleValues[this.integer({ min: 0, max: possibleValues.length - 1 })] as T; + } } From 32593478c1939697f5d75cea3917716d64711d9d Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 11 Apr 2024 13:37:15 +0100 Subject: [PATCH 10/56] feat(DTFS2-7052): package update --- package-lock.json | 3054 ++++++++++++++++++++++++--------------------- package.json | 68 +- 2 files changed, 1657 insertions(+), 1465 deletions(-) diff --git a/package-lock.json b/package-lock.json index b8a3a398..ad4b8d2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,22 +7,23 @@ "": { "name": "mdm-api", "version": "1.17.0", + "hasInstallScript": true, "license": "MIT", "dependencies": { - "@nestjs/axios": "^3.0.1", - "@nestjs/common": "^10.3.1", - "@nestjs/config": "^3.1.1", - "@nestjs/core": "^10.3.1", + "@nestjs/axios": "^3.0.2", + "@nestjs/common": "^10.3.7", + "@nestjs/config": "^3.2.2", + "@nestjs/core": "^10.3.7", "@nestjs/passport": "^10.0.3", - "@nestjs/platform-express": "^10.3.1", - "@nestjs/swagger": "^7.2.0", - "@nestjs/terminus": "^10.2.1", - "@nestjs/typeorm": "^10.0.1", - "axios": "^1.6.7", + "@nestjs/platform-express": "^10.3.7", + "@nestjs/swagger": "^7.3.1", + "@nestjs/terminus": "^10.2.3", + "@nestjs/typeorm": "^10.0.2", + "axios": "^1.6.8", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "compression": "^1.7.4", - "date-fns": "^3.3.1", + "date-fns": "^3.6.0", "dotenv": "^16.4.1", "express-basic-auth": "^1.2.1", "lodash": "^4.17.21", @@ -32,33 +33,33 @@ "passport-headerapikey": "^1.2.2", "pino-http": "^9.0.0", "pino-pretty": "^10.3.1", - "reflect-metadata": "^0.2.1", + "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "tsconfig-paths": "^4.2.0", "tslib": "^2.6.2", "typeorm": "^0.3.20", - "typeorm-extension": "^3.4.0", - "typescript": "^5.3.3" + "typeorm-extension": "^3.5.1", + "typescript": "^5.4.5" }, "devDependencies": { - "@commitlint/cli": "^18.6.0", - "@commitlint/config-conventional": "^18.6.0", - "@nestjs/cli": "^10.3.0", - "@nestjs/schematics": "^10.1.0", - "@nestjs/testing": "^10.3.1", - "@tsconfig/node21": "^21.0.1", + "@commitlint/cli": "^18.6.1", + "@commitlint/config-conventional": "^18.6.3", + "@nestjs/cli": "^10.3.2", + "@nestjs/schematics": "^10.1.1", + "@nestjs/testing": "^10.3.7", + "@tsconfig/node21": "^21.0.3", "@types/chance": "^1.1.6", "@types/compression": "^1.7.5", "@types/express": "^4.17.21", - "@types/jest": "^29.5.11", - "@types/lodash": "^4.14.202", - "@types/node": "^20.11.10", + "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.0", + "@types/node": "^20.12.7", "@types/supertest": "^6.0.2", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "chance": "^1.1.11", - "cspell": "^8.3.2", - "eslint": "^8.56.0", + "cspell": "^8.7.0", + "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-airbnb-typescript-prettier": "^5.0.0", @@ -67,22 +68,22 @@ "eslint-plugin-deprecation": "^2.0.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^27.6.3", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-jest-formatting": "^3.1.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-optimize-regex": "^1.2.1", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-security": "^2.1.0", + "eslint-plugin-security": "^2.1.1", "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-switch-case": "^1.1.2", - "eslint-plugin-unused-imports": "^3.0.0", - "husky": "^9.0.6", + "eslint-plugin-unused-imports": "^3.1.0", + "husky": "^9.0.11", "jest": "29.7.0", "jest-when": "^3.6.0", - "lint-staged": "^15.2.0", - "nock": "^13.5.1", - "prettier": "^3.2.4", - "sort-package-json": "^2.6.0", + "lint-staged": "^15.2.2", + "nock": "^13.5.4", + "prettier": "^3.2.5", + "sort-package-json": "^2.10.0", "source-map-support": "^0.5.21", "supertest": "^6.3.4", "ts-jest": "29.1.2", @@ -104,22 +105,22 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@angular-devkit/core": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.0.9.tgz", - "integrity": "sha512-r5jqwpWOgowqe9KSDqJ3iSbmsEt2XPjSvRG4DSI2T9s31bReoMtreo8b7wkRa2B3hbcDnstFbn8q27VvJDqRaQ==", + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.1.2.tgz", + "integrity": "sha512-ku+/W/HMCBacSWFppenr9y6Lx8mDuTuQvn1IkTyBLiJOpWnzgVbx9kHDeaDchGa1PwLlJUBBrv27t3qgJOIDPw==", "dev": true, "dependencies": { "ajv": "8.12.0", @@ -143,35 +144,13 @@ } } }, - "node_modules/@angular-devkit/core/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@angular-devkit/schematics": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.0.9.tgz", - "integrity": "sha512-5ti7g45F2KjDJS0DbgnOGI1GyKxGpn4XsKTYJFJrSAWj6VpuvPy/DINRrXNuRVo09VPEkqA+IW7QwaG9icptQg==", + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.1.2.tgz", + "integrity": "sha512-8S9RuM8olFN/gwN+mjbuF1CwHX61f0i59EGXz9tXLnKRUTjsRR+8vVMTAmX0dvVAT5fJTG/T69X+HX7FeumdqA==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.0.9", + "@angular-devkit/core": "17.1.2", "jsonc-parser": "3.2.0", "magic-string": "0.30.5", "ora": "5.4.1", @@ -184,15 +163,15 @@ } }, "node_modules/@angular-devkit/schematics-cli": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-17.0.9.tgz", - "integrity": "sha512-tznzzB26sy8jVUlV9HhXcbFYZcIIFMAiDMOuyLko2LZFjfoqW+OPvwa1mwAQwvVVSQZVAKvdndFhzwyl/axwFQ==", + "version": "17.1.2", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics-cli/-/schematics-cli-17.1.2.tgz", + "integrity": "sha512-bvXykYzSST05qFdlgIzUguNOb3z0hCa8HaTwtqdmQo9aFPf+P+/AC56I64t1iTchMjQtf3JrBQhYM25gUdcGbg==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.0.9", - "@angular-devkit/schematics": "17.0.9", + "@angular-devkit/core": "17.1.2", + "@angular-devkit/schematics": "17.1.2", "ansi-colors": "4.1.3", - "inquirer": "9.2.11", + "inquirer": "9.2.12", "symbol-observable": "4.0.0", "yargs-parser": "21.1.1" }, @@ -264,12 +243,12 @@ } }, "node_modules/@angular-devkit/schematics-cli/node_modules/inquirer": { - "version": "9.2.11", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.11.tgz", - "integrity": "sha512-B2LafrnnhbRzCWfAdOXisUzL89Kg8cVJlYmhqoi3flSiV/TveO+nsXwgKr9h9PIo+J1hz7nBSk6gegRIMBBf7g==", + "version": "9.2.12", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz", + "integrity": "sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==", "dev": true, "dependencies": { - "@ljharb/through": "^2.3.9", + "@ljharb/through": "^2.3.11", "ansi-escapes": "^4.3.2", "chalk": "^5.3.0", "cli-cursor": "^3.1.0", @@ -357,112 +336,178 @@ } }, "node_modules/@azure/core-auth": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.5.0.tgz", - "integrity": "sha512-udzoBuYG1VBoHVohDTrvKjyzel34zt77Bhp7dQntVGGD0ehVq48owENbBG8fIgkHRNUBQH5k1r0hpoMu5L8+kw==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.7.2.tgz", + "integrity": "sha512-Igm/S3fDYmnMq1uKS38Ae1/m37B3zigdlZw+kocwEhh5GjyKjPrXKO2J6rzpC1wAxrNil/jX9BJRqBshyjnF3g==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.1.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-client": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.7.3.tgz", - "integrity": "sha512-kleJ1iUTxcO32Y06dH9Pfi9K4U+Tlb111WXEnbt7R/ne+NLRwppZiTGJuTD5VVoxTMK5NTbEtm5t2vcdNCFe2g==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", + "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-rest-pipeline": "^1.9.1", "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.0.0", + "@azure/core-util": "^1.6.1", "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-client/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-http-compat": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-1.3.0.tgz", - "integrity": "sha512-ZN9avruqbQ5TxopzG3ih3KRy52n8OAbitX3fnZT5go4hzu0J+KVPSzkL+Wt3hpJpdG8WIfg1sBD1tWkgUdEpBA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz", + "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==", "dependencies": { - "@azure/abort-controller": "^1.0.4", + "@azure/abort-controller": "^2.0.0", "@azure/core-client": "^1.3.0", "@azure/core-rest-pipeline": "^1.3.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-http-compat/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-lro": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.5.4.tgz", - "integrity": "sha512-3GJiMVH7/10bulzOKGrrLeG/uCBH/9VtxqaMcB9lIqAeamI/xYQSHJL/KcsLDuH+yTjYpro/u6D/MuRe4dN70Q==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", "dependencies": { - "@azure/abort-controller": "^1.0.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-util": "^1.2.0", "@azure/logger": "^1.0.0", - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-lro/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/core-paging": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.5.0.tgz", - "integrity": "sha512-zqWdVIt+2Z+3wqxEOGzR5hXFZ8MGKK52x4vFLw8n58pR6ZfKRx3EXYTxTaYxYHc/PexPUTyimcTWFJbji9Z6Iw==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz", + "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==", "dependencies": { - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.13.0.tgz", - "integrity": "sha512-a62aP/wppgmnfIkJLfcB4ssPBcH94WzrzPVJ3tlJt050zX4lfmtnvy95D3igDo3f31StO+9BgPrzvkj4aOxnoA==", + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.15.2.tgz", + "integrity": "sha512-BmWfpjc/QXc2ipHOh6LbUzp3ONCaa6xzIssTU0DwH9bbYNXJlGUL6tujx5TrbVd/QQknmS+vlQJGrCq2oL1gZA==", "dependencies": { - "@azure/abort-controller": "^1.1.0", + "@azure/abort-controller": "^2.0.0", "@azure/core-auth": "^1.4.0", "@azure/core-tracing": "^1.0.1", "@azure/core-util": "^1.3.0", "@azure/logger": "^1.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "tslib": "^2.2.0" + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { "node": ">=18.0.0" } }, "node_modules/@azure/core-tracing": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz", - "integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz", + "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==", "dependencies": { - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/core-util": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.6.1.tgz", - "integrity": "sha512-h5taHeySlsV9qxuK64KZxy4iln1BtMYlNt5jbuEFN3UFSAd1EwKg/Gjl5a6tZ/W8t6li3xPnutOx7zbDyXnPmQ==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.9.0.tgz", + "integrity": "sha512-AfalUQ1ZppaKuxPPMsFEUdX6GZPB3d9paR9d/TTL7Ow2De8cJaC7ibi7kWVlFAVPCYo31OcnGymc0R89DX8Oaw==", "dependencies": { - "@azure/abort-controller": "^1.0.0", - "tslib": "^2.2.0" + "@azure/abort-controller": "^2.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=16.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-util/node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@azure/identity": { @@ -490,14 +535,14 @@ } }, "node_modules/@azure/keyvault-keys": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.7.2.tgz", - "integrity": "sha512-VdIH6PjbQ3J5ntK+xeI8eOe1WsDxF9ndXw8BPR/9MZVnIj0vQNtNCS6gpR7EFQeGcs8XjzMfHm0AvKGErobqJQ==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@azure/keyvault-keys/-/keyvault-keys-4.8.0.tgz", + "integrity": "sha512-jkuYxgkw0aaRfk40OQhFqDIupqblIOIlYESWB6DKCVDxQet1pyv86Tfk9M+5uFM0+mCs6+MUHU+Hxh3joiUn4Q==", "dependencies": { "@azure/abort-controller": "^1.0.0", "@azure/core-auth": "^1.3.0", "@azure/core-client": "^1.5.0", - "@azure/core-http-compat": "^1.3.0", + "@azure/core-http-compat": "^2.0.1", "@azure/core-lro": "^2.2.0", "@azure/core-paging": "^1.1.1", "@azure/core-rest-pipeline": "^1.8.1", @@ -507,45 +552,45 @@ "tslib": "^2.2.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/logger": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.0.4.tgz", - "integrity": "sha512-ustrPY8MryhloQj7OWGe+HrYx+aoiOxzbXTtgblbV3xwCqpzUK36phH3XNHQKj3EPonyFUuDTfR3qFhTEAuZEg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.2.tgz", + "integrity": "sha512-l170uE7bsKpIU6B/giRc9i4NI0Mj+tANMMMxf7Zi/5cKzEqPayP7+X1WPrG7e+91JgY8N+7K7nF2WOi7iVhXvg==", "dependencies": { - "tslib": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=18.0.0" } }, "node_modules/@azure/msal-browser": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.7.1.tgz", - "integrity": "sha512-EZnk81zn1/5/jv/VVN2Tp+dUVchHmwbbt7pn654Eqa+ua7wtEIg1btuW/mowB13BV2nGYcvniY9Mf+3Sbe0cCg==", + "version": "3.11.1", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.11.1.tgz", + "integrity": "sha512-tZFJnP5ZpgkmazSriEDW+Xl3/4WI823uhnYhWCHPkGywFWEZoPA5VkiCK8x4x8ECXp3mGr5qEI82MU43PBiaKA==", "dependencies": { - "@azure/msal-common": "14.6.1" + "@azure/msal-common": "14.8.1" }, "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-common": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.6.1.tgz", - "integrity": "sha512-yL97p2La0WrgU3MdXThOLOpdmBMvH8J69vwQ/skOqORYwOW/UYPdp9nZpvvfBO+zFZB5M3JkqA2NKtn4GfVBHw==", + "version": "14.8.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.8.1.tgz", + "integrity": "sha512-9HfBMDTIgtFFkils+o6gO/aGEoLLuc4z+QLLfhy/T1bTNPiVsX/9CjaBPMZGnMltN/IlMkU5SGGNggGh55p5xA==", "engines": { "node": ">=0.8.0" } }, "node_modules/@azure/msal-node": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.6.2.tgz", - "integrity": "sha512-XyP+5lUZxTpWpLCC2wAFGA9wXrUhHp1t4NLmQW0mQZzUdcSay3rG7kGGqxxeLf8mRdwoR0B70TCLmIGX6cfK/g==", + "version": "2.6.6", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.6.6.tgz", + "integrity": "sha512-j+1hW81ccglIYWukXufzRA4O71BCmpbmCO66ECDyE9FuPno6SjiR+K+mIk4tg6aQ7/UO2QA/EnRmT6YN0EF1Hw==", "dependencies": { - "@azure/msal-common": "14.6.1", + "@azure/msal-common": "14.8.1", "jsonwebtoken": "^9.0.0", "uuid": "^8.3.0" }, @@ -562,114 +607,43 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", - "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", - "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", - "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", + "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.9", - "@babel/parser": "^7.23.9", - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -694,14 +668,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", - "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz", + "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==", "dev": true, "dependencies": { - "@babel/types": "^7.23.6", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -768,12 +742,12 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -799,9 +773,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", "dev": true, "engines": { "node": ">=6.9.0" @@ -832,9 +806,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -859,28 +833,29 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", - "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz", + "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==", "dev": true, "dependencies": { - "@babel/template": "^7.23.9", - "@babel/traverse": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -958,9 +933,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz", - "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz", + "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -1030,12 +1005,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1132,12 +1107,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.0" }, "engines": { "node": ">=6.9.0" @@ -1147,9 +1122,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", - "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz", + "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==", "dev": true, "dependencies": { "regenerator-runtime": "^0.14.0" @@ -1159,33 +1134,33 @@ } }, "node_modules/@babel/template": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", - "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9" + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", - "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.23.5", - "@babel/generator": "^7.23.6", + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.9", - "@babel/types": "^7.23.9", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1203,9 +1178,9 @@ } }, "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", "dev": true, "dependencies": { "@babel/helper-string-parser": "^7.23.4", @@ -1233,16 +1208,16 @@ } }, "node_modules/@commitlint/cli": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.6.0.tgz", - "integrity": "sha512-FiH23cr9QG8VdfbmvJJZmdfHGVMCouOOAzoXZ3Cd7czGC52RbycwNt8YCI7SA69pAl+t30vh8LMaO/N+kcel6w==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-18.6.1.tgz", + "integrity": "sha512-5IDE0a+lWGdkOvKH892HHAZgbAjcj1mT5QrfA/SVbLJV/BbBMGyKN0W5mhgjekPJJwEQdVNvhl9PwUacY58Usw==", "dev": true, "dependencies": { - "@commitlint/format": "^18.6.0", - "@commitlint/lint": "^18.6.0", - "@commitlint/load": "^18.6.0", - "@commitlint/read": "^18.6.0", - "@commitlint/types": "^18.6.0", + "@commitlint/format": "^18.6.1", + "@commitlint/lint": "^18.6.1", + "@commitlint/load": "^18.6.1", + "@commitlint/read": "^18.6.1", + "@commitlint/types": "^18.6.1", "execa": "^5.0.0", "lodash.isfunction": "^3.0.9", "resolve-from": "5.0.0", @@ -1257,11 +1232,12 @@ } }, "node_modules/@commitlint/config-conventional": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-18.6.0.tgz", - "integrity": "sha512-CDCOf2eJz9D/TL44IBks0stM9TmdLCNE2B48owIU3YCadwzts/bobXPScagIgPQF6hhKYMEdj5zpUDlmbwuqwQ==", + "version": "18.6.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-18.6.3.tgz", + "integrity": "sha512-8ZrRHqF6je+TRaFoJVwszwnOXb/VeYrPmTwPhf0WxpzpGTcYy1p0SPyZ2eRn/sRi/obnWAcobtDAq6+gJQQNhQ==", "dev": true, "dependencies": { + "@commitlint/types": "^18.6.1", "conventional-changelog-conventionalcommits": "^7.0.2" }, "engines": { @@ -1269,47 +1245,25 @@ } }, "node_modules/@commitlint/config-validator": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-18.6.0.tgz", - "integrity": "sha512-Ptfa865arNozlkjxrYG3qt6wT9AlhNUHeuDyKEZiTL/l0ftncFhK/KN0t/EAMV2tec+0Mwxo0FmhbESj/bI+1g==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-18.6.1.tgz", + "integrity": "sha512-05uiToBVfPhepcQWE1ZQBR/Io3+tb3gEotZjnI4tTzzPk16NffN6YABgwFQCLmzZefbDcmwWqJWc2XT47q7Znw==", "dev": true, "dependencies": { - "@commitlint/types": "^18.6.0", + "@commitlint/types": "^18.6.1", "ajv": "^8.11.0" }, "engines": { "node": ">=v18" } }, - "node_modules/@commitlint/config-validator/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@commitlint/config-validator/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/@commitlint/ensure": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-18.6.0.tgz", - "integrity": "sha512-xY07NmOBJ7JuhX3tic021PaeLepZARIQyqpAQoNQZoml1keBFfB6MbA7XlWZv0ebbarUFE4yhKxOPw+WFv7/qw==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-18.6.1.tgz", + "integrity": "sha512-BPm6+SspyxQ7ZTsZwXc7TRQL5kh5YWt3euKmEIBZnocMFkJevqs3fbLRb8+8I/cfbVcAo4mxRlpTPfz8zX7SnQ==", "dev": true, "dependencies": { - "@commitlint/types": "^18.6.0", + "@commitlint/types": "^18.6.1", "lodash.camelcase": "^4.3.0", "lodash.kebabcase": "^4.1.1", "lodash.snakecase": "^4.1.1", @@ -1321,21 +1275,21 @@ } }, "node_modules/@commitlint/execute-rule": { - "version": "18.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-18.4.4.tgz", - "integrity": "sha512-a37Nd3bDQydtg9PCLLWM9ZC+GO7X5i4zJvrggJv5jBhaHsXeQ9ZWdO6ODYR+f0LxBXXNYK3geYXJrCWUCP8JEg==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-18.6.1.tgz", + "integrity": "sha512-7s37a+iWyJiGUeMFF6qBlyZciUkF8odSAnHijbD36YDctLhGKoYltdvuJ/AFfRm6cBLRtRk9cCVPdsEFtt/2rg==", "dev": true, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/format": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-18.6.0.tgz", - "integrity": "sha512-8UNWfs2slPPSQiiVpLGJTnPHv7Jkd5KYxfbNXbmLL583bjom4RrylvyrCVnmZReA8nNad7pPXq6mDH4FNVj6xg==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-18.6.1.tgz", + "integrity": "sha512-K8mNcfU/JEFCharj2xVjxGSF+My+FbUHoqR+4GqPGrHNqXOGNio47ziiR4HQUPKtiNs05o8/WyLBoIpMVOP7wg==", "dev": true, "dependencies": { - "@commitlint/types": "^18.6.0", + "@commitlint/types": "^18.6.1", "chalk": "^4.1.0" }, "engines": { @@ -1343,43 +1297,43 @@ } }, "node_modules/@commitlint/is-ignored": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-18.6.0.tgz", - "integrity": "sha512-Xjx/ZyyJ4FdLuz0FcOvqiqSFgiO2yYj3QN9XlvyrxqbXTxPVC7QFEXJYBVPulUSN/gR7WXH1Udw+HYYfD17xog==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-18.6.1.tgz", + "integrity": "sha512-MOfJjkEJj/wOaPBw5jFjTtfnx72RGwqYIROABudOtJKW7isVjFe9j0t8xhceA02QebtYf4P/zea4HIwnXg8rvA==", "dev": true, "dependencies": { - "@commitlint/types": "^18.6.0", - "semver": "7.5.4" + "@commitlint/types": "^18.6.1", + "semver": "7.6.0" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/lint": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-18.6.0.tgz", - "integrity": "sha512-ycbuDWfyykPmslgiHzhz8dL6F0BJYltXLVfc+M49z0c+FNITM0v+r0Vd2+Tdtq06VTc894p2+YSmZhulY8Jn3Q==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-18.6.1.tgz", + "integrity": "sha512-8WwIFo3jAuU+h1PkYe5SfnIOzp+TtBHpFr4S8oJWhu44IWKuVx6GOPux3+9H1iHOan/rGBaiacicZkMZuluhfQ==", "dev": true, "dependencies": { - "@commitlint/is-ignored": "^18.6.0", - "@commitlint/parse": "^18.6.0", - "@commitlint/rules": "^18.6.0", - "@commitlint/types": "^18.6.0" + "@commitlint/is-ignored": "^18.6.1", + "@commitlint/parse": "^18.6.1", + "@commitlint/rules": "^18.6.1", + "@commitlint/types": "^18.6.1" }, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/load": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-18.6.0.tgz", - "integrity": "sha512-RRssj7TmzT0bowoEKlgwg8uQ7ORXWkw7lYLsZZBMi9aInsJuGNLNWcMxJxRZbwxG3jkCidGUg85WmqJvRjsaDA==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-18.6.1.tgz", + "integrity": "sha512-p26x8734tSXUHoAw0ERIiHyW4RaI4Bj99D8YgUlVV9SedLf8hlWAfyIFhHRIhfPngLlCe0QYOdRKYFt8gy56TA==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^18.6.0", - "@commitlint/execute-rule": "^18.4.4", - "@commitlint/resolve-extends": "^18.6.0", - "@commitlint/types": "^18.6.0", + "@commitlint/config-validator": "^18.6.1", + "@commitlint/execute-rule": "^18.6.1", + "@commitlint/resolve-extends": "^18.6.1", + "@commitlint/types": "^18.6.1", "chalk": "^4.1.0", "cosmiconfig": "^8.3.6", "cosmiconfig-typescript-loader": "^5.0.0", @@ -1393,21 +1347,21 @@ } }, "node_modules/@commitlint/message": { - "version": "18.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-18.4.4.tgz", - "integrity": "sha512-lHF95mMDYgAI1LBXveJUyg4eLaMXyOqJccCK3v55ZOEUsMPrDi8upqDjd/NmzWmESYihaOMBTAnxm+6oD1WoDQ==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/message/-/message-18.6.1.tgz", + "integrity": "sha512-VKC10UTMLcpVjMIaHHsY1KwhuTQtdIKPkIdVEwWV+YuzKkzhlI3aNy6oo1eAN6b/D2LTtZkJe2enHmX0corYRw==", "dev": true, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/parse": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-18.6.0.tgz", - "integrity": "sha512-Y/G++GJpATFw54O0jikc/h2ibyGHgghtPnwsOk3O/aU092ydJ5XEHYcd7xGNQYuLweLzQis2uEwRNk9AVIPbQQ==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/parse/-/parse-18.6.1.tgz", + "integrity": "sha512-eS/3GREtvVJqGZrwAGRwR9Gdno3YcZ6Xvuaa+vUF8j++wsmxrA2En3n0ccfVO2qVOLJC41ni7jSZhQiJpMPGOQ==", "dev": true, "dependencies": { - "@commitlint/types": "^18.6.0", + "@commitlint/types": "^18.6.1", "conventional-changelog-angular": "^7.0.0", "conventional-commits-parser": "^5.0.0" }, @@ -1416,13 +1370,13 @@ } }, "node_modules/@commitlint/read": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-18.6.0.tgz", - "integrity": "sha512-w39ji8VfWhPKRquPhRHB3Yd8XIHwaNHgOh28YI1QEmZ59qVpuVUQo6h/NsVb+uoC6LbXZiofTZv2iFR084jKEA==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/read/-/read-18.6.1.tgz", + "integrity": "sha512-ia6ODaQFzXrVul07ffSgbZGFajpe8xhnDeLIprLeyfz3ivQU1dIoHp7yz0QIorZ6yuf4nlzg4ZUkluDrGN/J/w==", "dev": true, "dependencies": { - "@commitlint/top-level": "^18.4.4", - "@commitlint/types": "^18.6.0", + "@commitlint/top-level": "^18.6.1", + "@commitlint/types": "^18.6.1", "git-raw-commits": "^2.0.11", "minimist": "^1.2.6" }, @@ -1431,13 +1385,13 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-18.6.0.tgz", - "integrity": "sha512-k2Xp+Fxeggki2i90vGrbiLDMefPius3zGSTFFlRAPKce/SWLbZtI+uqE9Mne23mHO5lmcSV8z5m6ziiJwGpOcg==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-18.6.1.tgz", + "integrity": "sha512-ifRAQtHwK+Gj3Bxj/5chhc4L2LIc3s30lpsyW67yyjsETR6ctHAHRu1FSpt0KqahK5xESqoJ92v6XxoDRtjwEQ==", "dev": true, "dependencies": { - "@commitlint/config-validator": "^18.6.0", - "@commitlint/types": "^18.6.0", + "@commitlint/config-validator": "^18.6.1", + "@commitlint/types": "^18.6.1", "import-fresh": "^3.0.0", "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0", @@ -1448,15 +1402,15 @@ } }, "node_modules/@commitlint/rules": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-18.6.0.tgz", - "integrity": "sha512-pTalvCEvuCWrBWZA/YqO/3B3nZnY3Ncc+TmQsRajBdC1tkQIm5Iovdo4Ec7f2Dw1tVvpYMUUNAgcWqsY0WckWg==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-18.6.1.tgz", + "integrity": "sha512-kguM6HxZDtz60v/zQYOe0voAtTdGybWXefA1iidjWYmyUUspO1zBPQEmJZ05/plIAqCVyNUTAiRPWIBKLCrGew==", "dev": true, "dependencies": { - "@commitlint/ensure": "^18.6.0", - "@commitlint/message": "^18.4.4", - "@commitlint/to-lines": "^18.4.4", - "@commitlint/types": "^18.6.0", + "@commitlint/ensure": "^18.6.1", + "@commitlint/message": "^18.6.1", + "@commitlint/to-lines": "^18.6.1", + "@commitlint/types": "^18.6.1", "execa": "^5.0.0" }, "engines": { @@ -1464,18 +1418,18 @@ } }, "node_modules/@commitlint/to-lines": { - "version": "18.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-18.4.4.tgz", - "integrity": "sha512-mwe2Roa59NCz/krniAdCygFabg7+fQCkIhXqBHw00XQ8Y7lw4poZLLxeGI3p3bLpcEOXdqIDrEGLwHmG5lBdwQ==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/to-lines/-/to-lines-18.6.1.tgz", + "integrity": "sha512-Gl+orGBxYSNphx1+83GYeNy5N0dQsHBQ9PJMriaLQDB51UQHCVLBT/HBdOx5VaYksivSf5Os55TLePbRLlW50Q==", "dev": true, "engines": { "node": ">=v18" } }, "node_modules/@commitlint/top-level": { - "version": "18.4.4", - "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-18.4.4.tgz", - "integrity": "sha512-PBwW1drgeavl9CadB7IPRUk6rkUP/O8jEkxjlC+ofuh3pw0bzJdAT+Kw7M1Yc9KtTb9xTaqUB8uvRtaybHa/tQ==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/top-level/-/top-level-18.6.1.tgz", + "integrity": "sha512-HyiHQZUTf0+r0goTCDs/bbVv/LiiQ7AVtz6KIar+8ZrseB9+YJAIo8HQ2IC2QT1y3N1lbW6OqVEsTHjbT6hGSw==", "dev": true, "dependencies": { "find-up": "^5.0.0" @@ -1485,9 +1439,9 @@ } }, "node_modules/@commitlint/types": { - "version": "18.6.0", - "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-18.6.0.tgz", - "integrity": "sha512-oavoKLML/eJa2rJeyYSbyGAYzTxQ6voG5oeX3OrxpfrkRWhJfm4ACnhoRf5tgiybx2MZ+EVFqC1Lw3W8/uwpZA==", + "version": "18.6.1", + "resolved": "https://registry.npmjs.org/@commitlint/types/-/types-18.6.1.tgz", + "integrity": "sha512-gwRLBLra/Dozj2OywopeuHj2ac26gjGkz2cZ+86cTJOdtWfiRRr4+e77ZDAGc6MDWxaWheI+mAV5TLWWRwqrFg==", "dev": true, "dependencies": { "chalk": "^4.1.0" @@ -1497,16 +1451,16 @@ } }, "node_modules/@cspell/cspell-bundled-dicts": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.3.2.tgz", - "integrity": "sha512-3ubOgz1/MDixJbq//0rQ2omB3cSdhVJDviERZeiREGz4HOq84aaK1Fqbw5SjNZHvhpoq+AYXm6kJbIAH8YhKgg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.7.0.tgz", + "integrity": "sha512-B5YQI7Dd9m0JHTmHgs7PiyP4BWXzl8ixpK+HGOwhxzh7GyfFt1Eo/gxMxBDX/9SaewEzeb2OjRpRKEFtEsto3A==", "dev": true, "dependencies": { "@cspell/dict-ada": "^4.0.2", "@cspell/dict-aws": "^4.0.1", "@cspell/dict-bash": "^4.1.3", - "@cspell/dict-companies": "^3.0.29", - "@cspell/dict-cpp": "^5.0.10", + "@cspell/dict-companies": "^3.0.31", + "@cspell/dict-cpp": "^5.1.3", "@cspell/dict-cryptocurrencies": "^5.0.0", "@cspell/dict-csharp": "^4.0.2", "@cspell/dict-css": "^4.0.12", @@ -1515,39 +1469,42 @@ "@cspell/dict-docker": "^1.1.7", "@cspell/dict-dotnet": "^5.0.0", "@cspell/dict-elixir": "^4.0.3", - "@cspell/dict-en_us": "^4.3.13", + "@cspell/dict-en_us": "^4.3.17", "@cspell/dict-en-common-misspellings": "^2.0.0", "@cspell/dict-en-gb": "1.1.33", "@cspell/dict-filetypes": "^3.0.3", "@cspell/dict-fonts": "^4.0.0", "@cspell/dict-fsharp": "^1.0.1", "@cspell/dict-fullstack": "^3.1.5", - "@cspell/dict-gaming-terms": "^1.0.4", + "@cspell/dict-gaming-terms": "^1.0.5", "@cspell/dict-git": "^3.0.0", "@cspell/dict-golang": "^6.0.5", "@cspell/dict-haskell": "^4.0.1", "@cspell/dict-html": "^4.0.5", "@cspell/dict-html-symbol-entities": "^4.0.0", "@cspell/dict-java": "^5.0.6", + "@cspell/dict-julia": "^1.0.1", "@cspell/dict-k8s": "^1.0.2", "@cspell/dict-latex": "^4.0.0", "@cspell/dict-lorem-ipsum": "^4.0.0", "@cspell/dict-lua": "^4.0.3", "@cspell/dict-makefile": "^1.0.0", + "@cspell/dict-monkeyc": "^1.0.6", "@cspell/dict-node": "^4.0.3", - "@cspell/dict-npm": "^5.0.14", - "@cspell/dict-php": "^4.0.5", + "@cspell/dict-npm": "^5.0.15", + "@cspell/dict-php": "^4.0.6", "@cspell/dict-powershell": "^5.0.3", - "@cspell/dict-public-licenses": "^2.0.5", + "@cspell/dict-public-licenses": "^2.0.6", "@cspell/dict-python": "^4.1.11", "@cspell/dict-r": "^2.0.1", "@cspell/dict-ruby": "^5.0.2", - "@cspell/dict-rust": "^4.0.1", + "@cspell/dict-rust": "^4.0.2", "@cspell/dict-scala": "^5.0.0", - "@cspell/dict-software-terms": "^3.3.15", + "@cspell/dict-software-terms": "^3.3.18", "@cspell/dict-sql": "^2.1.3", "@cspell/dict-svelte": "^1.0.2", "@cspell/dict-swift": "^2.0.1", + "@cspell/dict-terraform": "^1.0.0", "@cspell/dict-typescript": "^3.1.2", "@cspell/dict-vue": "^3.0.0" }, @@ -1556,30 +1513,30 @@ } }, "node_modules/@cspell/cspell-json-reporter": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.3.2.tgz", - "integrity": "sha512-gHSz4jXMJPcxx+lOGfXhHuoyenAWQ8PVA/atHFrWYKo1LzKTbpkEkrsDnlX8QNJubc3EMH63Uy+lOIaFDVyHiQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.7.0.tgz", + "integrity": "sha512-LTQPEvXvCqnc+ok9WXpSISZyt4/nGse9fVEM430g0BpGzKpt3RMx49B8uasvvnanzCuikaW9+wFLmwgvraERhA==", "dev": true, "dependencies": { - "@cspell/cspell-types": "8.3.2" + "@cspell/cspell-types": "8.7.0" }, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-pipe": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.3.2.tgz", - "integrity": "sha512-GZmDwvQGOjQi3IjD4k9xXeVTDANczksOsgVKb3v2QZk9mR4Qj8c6Uarjd4AgSiIhu/wBliJfzr5rWFJu4X2VfQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.7.0.tgz", + "integrity": "sha512-ePqddIQ4arqPQgOkC146SkZxvZb9/jL7xIM5Igy2n3tiWTC5ijrX/mbHpPZ1VGcFck+1M0cJUuyhuJk+vMj3rg==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-resolver": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.3.2.tgz", - "integrity": "sha512-w2Tmb95bzdEz9L4W5qvsP5raZbyEzKL7N2ksU/+yh8NEJcTuExmAl/nMnb3aIk7m2b+kPHnMOcJuwfUMLmyv4A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.7.0.tgz", + "integrity": "sha512-grZwDFYqcBYQDaz4AkUtdyqc4UUH2J3/7yWVkBbYDPE+FQHa9ofFXzXxyjs56GJlPfi9ULpe5/Wz6uVLg8rQkQ==", "dev": true, "dependencies": { "global-directory": "^4.0.1" @@ -1589,18 +1546,18 @@ } }, "node_modules/@cspell/cspell-service-bus": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.3.2.tgz", - "integrity": "sha512-skTHNyVi74//W/O+f4IauDhm6twA9S2whkylonsIzPxEl4Pn3y2ZEMXNki/MWUwZfDIzKKSxlcREH61g7zCvhg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.7.0.tgz", + "integrity": "sha512-KW48iu0nTDzbedixc7iB7K7mlAZQ7QeMLuM/akxigOlvtOdVJrRa9Pfn44lwejts1ANb/IXil3GH8YylkVi76Q==", "dev": true, "engines": { "node": ">=18" } }, "node_modules/@cspell/cspell-types": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.3.2.tgz", - "integrity": "sha512-qS/gWd9ItOrN6ZX5pwC9lJjnBoyiAyhxYq0GUXuV892LQvwrBmECGk6KhsA1lPW7JJS7o57YTAS1jmXnmXMEpg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.7.0.tgz", + "integrity": "sha512-Rb+LCE5I9JEb/LE8nSViVSF8z1CWv/z4mPBIG37VMa7aUx2gAQa6gJekNfpY9YZiMzx4Tv3gDujN80ytks4pGA==", "dev": true, "engines": { "node": ">=18" @@ -1631,9 +1588,9 @@ "dev": true }, "node_modules/@cspell/dict-cpp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-5.1.1.tgz", - "integrity": "sha512-Qy9fNsR/5RcQ6G85gDKFjvzh0AdgAilLQeSXPtqY21Fx1kCjUqdVVJYMmHUREgcxH6ptAxtn5knTWU4PIhQtOw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-5.1.3.tgz", + "integrity": "sha512-sqnriXRAInZH9W75C+APBh6dtben9filPqVbIsiRMUXGg+s02ekz0z6LbS7kXeJ5mD2qXoMLBrv13qH2eIwutQ==", "dev": true }, "node_modules/@cspell/dict-cryptocurrencies": { @@ -1691,9 +1648,9 @@ "dev": true }, "node_modules/@cspell/dict-en_us": { - "version": "4.3.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.14.tgz", - "integrity": "sha512-Od7vPVNN4td0Fild5BcCPikx+lBJ2L809zWeO3lThYHqtZXqsbaBNzfv9qlB1bXW199Ru461vu02CrklU1oD+Q==", + "version": "4.3.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.17.tgz", + "integrity": "sha512-CS0Tb2f2YwQZ4VZ6+WLAO5uOzb0iO/iYSRl34kX4enq6quXxLYzwdfGAwv85wSYHPdga8tGiZFP+p8GPsi2JEg==", "dev": true }, "node_modules/@cspell/dict-en-common-misspellings": { @@ -1774,6 +1731,12 @@ "integrity": "sha512-kdE4AHHHrixyZ5p6zyms1SLoYpaJarPxrz8Tveo6gddszBVVwIUZ+JkQE1bWNLK740GWzIXdkznpUfw1hP9nXw==", "dev": true }, + "node_modules/@cspell/dict-julia": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.0.1.tgz", + "integrity": "sha512-4JsCLCRhhLMLiaHpmR7zHFjj1qOauzDI5ZzCNQS31TUMfsOo26jAKDfo0jljFAKgw5M2fEG7sKr8IlPpQAYrmQ==", + "dev": true + }, "node_modules/@cspell/dict-k8s": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.2.tgz", @@ -1804,6 +1767,12 @@ "integrity": "sha512-3W9tHPcSbJa6s0bcqWo6VisEDTSN5zOtDbnPabF7rbyjRpNo0uHXHRJQF8gAbFzoTzBBhgkTmrfSiuyQm7vBUQ==", "dev": true }, + "node_modules/@cspell/dict-monkeyc": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.6.tgz", + "integrity": "sha512-oO8ZDu/FtZ55aq9Mb67HtaCnsLn59xvhO/t2mLLTHAp667hJFxpp7bCtr2zOrR1NELzFXmKln/2lw/PvxMSvrA==", + "dev": true + }, "node_modules/@cspell/dict-node": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-4.0.3.tgz", @@ -1817,9 +1786,9 @@ "dev": true }, "node_modules/@cspell/dict-php": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.5.tgz", - "integrity": "sha512-9r8ao7Z/mH9Z8pSB7yLtyvcCJWw+/MnQpj7xGVYzIV7V2ZWDRjXZAMgteHMJ37m8oYz64q5d4tiipD300QSetQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.6.tgz", + "integrity": "sha512-ySAXisf7twoVFZqBV2o/DKiCLIDTHNqfnj0EfH9OoOUR7HL3rb6zJkm0viLUFDO2G/8SyIi6YrN/6KX+Scjjjg==", "dev": true }, "node_modules/@cspell/dict-powershell": { @@ -1829,9 +1798,9 @@ "dev": true }, "node_modules/@cspell/dict-public-licenses": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.5.tgz", - "integrity": "sha512-91HK4dSRri/HqzAypHgduRMarJAleOX5NugoI8SjDLPzWYkwZ1ftuCXSk+fy8DLc3wK7iOaFcZAvbjmnLhVs4A==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.6.tgz", + "integrity": "sha512-bHqpSpJvLCUcWxj1ov/Ki8WjmESpYwRpQlqfdchekOTc93Huhvjm/RXVN1R4fVf4Hspyem1QVkCGqAmjJMj6sw==", "dev": true }, "node_modules/@cspell/dict-python": { @@ -1868,9 +1837,9 @@ "dev": true }, "node_modules/@cspell/dict-software-terms": { - "version": "3.3.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.3.16.tgz", - "integrity": "sha512-ixorEP80LGxAU+ODVSn/CYIDjV0XAlZ2VrBu7CT+PwUFJ7h8o3JX1ywKB4qnt0hHru3JjWFtBoBThmZdrXnREQ==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-3.3.18.tgz", + "integrity": "sha512-LJZGGMGqS8KzgXJrSMs3T+6GoqHG9z8Bc+rqLzLzbtoR3FbsMasE9U8oP2PmS3q7jJLFjQkzmg508DrcuZuo2g==", "dev": true }, "node_modules/@cspell/dict-sql": { @@ -1891,6 +1860,12 @@ "integrity": "sha512-gxrCMUOndOk7xZFmXNtkCEeroZRnS2VbeaIPiymGRHj5H+qfTAzAKxtv7jJbVA3YYvEzWcVE2oKDP4wcbhIERw==", "dev": true }, + "node_modules/@cspell/dict-terraform": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.0.0.tgz", + "integrity": "sha512-Ak+vy4HP/bOgzf06BAMC30+ZvL9mzv21xLM2XtfnBLTDJGdxlk/nK0U6QT8VfFLqJ0ZZSpyOxGsUebWDCTr/zQ==", + "dev": true + }, "node_modules/@cspell/dict-typescript": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.2.tgz", @@ -1904,9 +1879,9 @@ "dev": true }, "node_modules/@cspell/dynamic-import": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.3.2.tgz", - "integrity": "sha512-4t0xM5luA3yQhar2xWvYK4wQSDB2r0u8XkpzzJqd57MnJXd7uIAxI0awGUrDXukadRaCo0tDIlMUBemH48SNVg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.7.0.tgz", + "integrity": "sha512-xlEPdiHVDu+4xYkvwjL9MgklxOi9XB+Pr1H9s3Ww9WEq+q6BA3xOHxLIU/k8mhqFTMZGFZRCsdy/EwMu6SyRhQ==", "dev": true, "dependencies": { "import-meta-resolve": "^4.0.0" @@ -1916,9 +1891,9 @@ } }, "node_modules/@cspell/strong-weak-map": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.3.2.tgz", - "integrity": "sha512-Mte/2000ap278kRYOUhiGWI7MNr1+A7WSWJmlcdP4CAH5SO20sZI3/cyZLjJJEyapdhK5vaP1L5J9sUcVDHd3A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.7.0.tgz", + "integrity": "sha512-0bo0WwDr2lzGoCP7vbpWbDpPyuOrHKK+218txnUpx6Pn1EDBLfcDQsiZED5B6zlpwgbGi6y3vc0rWtJbjKvwzg==", "dev": true, "engines": { "node": ">=18" @@ -1928,7 +1903,7 @@ "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -1940,7 +1915,7 @@ "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "devOptional": true, + "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -1993,6 +1968,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -2003,6 +1994,12 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2016,18 +2013,18 @@ } }, "node_modules/@eslint/js": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", - "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@faker-js/faker": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.0.tgz", - "integrity": "sha512-htW87352wzUCdX1jyUQocUcmAaFqcR/w082EC8iP/gtkF0K+aKcBp0hR5Arb7dzR8tQ1TrhE9DNa5EbJELm84w==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz", + "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==", "funding": [ { "type": "opencollective", @@ -2089,9 +2086,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -2643,57 +2640,57 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "devOptional": true, + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "devOptional": true + "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -2701,17 +2698,17 @@ } }, "node_modules/@js-joda/core": { - "version": "5.6.1", - "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.6.1.tgz", - "integrity": "sha512-Xla/d7ZMMR6+zRd6lTio0wRZECfcfFJP7GGe9A9L4tDOlD5CX4YcZ4YZle9w58bBYzssojVapI84RraKWDQZRg==" + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.6.2.tgz", + "integrity": "sha512-ow4R+7C24xeTjiMTTZ4k6lvxj7MRBqvqLCQjThQff3RjOmIMokMP20LNYVFhGafJtUx/Xo2Qp4qU8eNoTVH0SA==" }, "node_modules/@ljharb/through": { - "version": "2.3.12", - "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.12.tgz", - "integrity": "sha512-ajo/heTlG3QgC8EGP6APIejksVAYt4ayz4tqoP3MolFELzcH1x1fzwEYRJTPO0IELutZ5HQ0c26/GqAYy79u3g==", + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.5" + "call-bind": "^1.0.7" }, "engines": { "node": ">= 0.4" @@ -2725,29 +2722,33 @@ "node": ">=8" } }, + "node_modules/@microsoft/tsdoc": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", + "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==" + }, "node_modules/@nestjs/axios": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.1.tgz", - "integrity": "sha512-VlOZhAGDmOoFdsmewn8AyClAdGpKXQQaY1+3PGB+g6ceurGIdTxZgRX3VXc1T6Zs60PedWjg3A82TDOB05mrzQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.2.tgz", + "integrity": "sha512-Z6GuOUdNQjP7FX+OuV2Ybyamse+/e0BFdTWBX5JxpBDKA+YkdLynDgG6HTF04zy6e9zPa19UX0WA2VDoehwhXQ==", "peerDependencies": { "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", "axios": "^1.3.1", - "reflect-metadata": "^0.1.12", "rxjs": "^6.0.0 || ^7.0.0" } }, "node_modules/@nestjs/cli": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.3.0.tgz", - "integrity": "sha512-37h+wSDItY0NE/x3a/M9yb2cXzfsD4qoE26rHgFn592XXLelDN12wdnfn7dTIaiRZT7WOCdQ+BYP9mQikR4AsA==", + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@nestjs/cli/-/cli-10.3.2.tgz", + "integrity": "sha512-aWmD1GLluWrbuC4a1Iz/XBk5p74Uj6nIVZj6Ov03JbTfgtWqGFLtXuMetvzMiHxfrHehx/myt2iKAPRhKdZvTg==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.0.9", - "@angular-devkit/schematics": "17.0.9", - "@angular-devkit/schematics-cli": "17.0.9", + "@angular-devkit/core": "17.1.2", + "@angular-devkit/schematics": "17.1.2", + "@angular-devkit/schematics-cli": "17.1.2", "@nestjs/schematics": "^10.0.1", "chalk": "4.1.2", - "chokidar": "3.5.3", + "chokidar": "3.6.0", "cli-table3": "0.6.3", "commander": "4.1.1", "fork-ts-checker-webpack-plugin": "9.0.2", @@ -2762,7 +2763,7 @@ "tsconfig-paths": "4.2.0", "tsconfig-paths-webpack-plugin": "4.1.0", "typescript": "5.3.3", - "webpack": "5.89.0", + "webpack": "5.90.1", "webpack-node-externals": "3.0.0" }, "bin": { @@ -2772,7 +2773,7 @@ "node": ">= 16.14" }, "peerDependencies": { - "@swc/cli": "^0.1.62", + "@swc/cli": "^0.1.62 || ^0.3.0", "@swc/core": "^1.3.62" }, "peerDependenciesMeta": { @@ -2784,10 +2785,23 @@ } } }, + "node_modules/@nestjs/cli/node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/@nestjs/common": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.1.tgz", - "integrity": "sha512-YuxeIlVemVQCuXMkNbBpNlmwZgp/Cu6dwCOjki63mhyYHEFX48GNNA4zZn5MFRjF4h7VSceABsScROuzsxs9LA==", + "version": "10.3.7", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.7.tgz", + "integrity": "sha512-gKFtFzcJznrwsRYjtNZoPAvSOPYdNgxbTYoAyLTpoy393cIKgLmJTHu6ReH8/qIB9AaZLdGaFLkx98W/tFWFUw==", "dependencies": { "iterare": "1.2.1", "tslib": "2.6.2", @@ -2800,7 +2814,7 @@ "peerDependencies": { "class-transformer": "*", "class-validator": "*", - "reflect-metadata": "^0.1.12", + "reflect-metadata": "^0.1.12 || ^0.2.0", "rxjs": "^7.1.0" }, "peerDependenciesMeta": { @@ -2813,35 +2827,24 @@ } }, "node_modules/@nestjs/config": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.1.1.tgz", - "integrity": "sha512-qu5QlNiJdqQtOsnB6lx4JCXPQ96jkKUsOGd+JXfXwqJqZcOSAq6heNFg0opW4pq4J/VZoNwoo87TNnx9wthnqQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@nestjs/config/-/config-3.2.2.tgz", + "integrity": "sha512-vGICPOui5vE6kPz1iwQ7oCnp3qWgqxldPmBQ9onkVoKlBtyc83KJCr7CjuVtf4OdovMAVcux1d8Q6jglU2ZphA==", "dependencies": { - "dotenv": "16.3.1", + "dotenv": "16.4.5", "dotenv-expand": "10.0.0", "lodash": "4.17.21", - "uuid": "9.0.0" + "uuid": "9.0.1" }, "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "reflect-metadata": "^0.1.13" - } - }, - "node_modules/@nestjs/config/node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "rxjs": "^7.1.0" } }, "node_modules/@nestjs/core": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.1.tgz", - "integrity": "sha512-mh6FwTKh2R3CmLRuB50BF5q/lzc+Mz+7qAlEvpgCiTSIfSXzbQ47vWpfgLirwkL3SlCvtFS8onxOeI69RpxvXA==", + "version": "10.3.7", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.7.tgz", + "integrity": "sha512-hsdlnfiQ3kgqHL5k7js3CU0PV7hBJVi+LfFMgCkoagRxNMf67z0GFGeOV2jk5d65ssB19qdYsDa1MGVuEaoUpg==", "hasInstallScript": true, "dependencies": { "@nuxtjs/opencollective": "0.3.2", @@ -2860,7 +2863,7 @@ "@nestjs/microservices": "^10.0.0", "@nestjs/platform-express": "^10.0.0", "@nestjs/websockets": "^10.0.0", - "reflect-metadata": "^0.1.12", + "reflect-metadata": "^0.1.12 || ^0.2.0", "rxjs": "^7.1.0" }, "peerDependenciesMeta": { @@ -2876,14 +2879,14 @@ } }, "node_modules/@nestjs/mapped-types": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.4.tgz", - "integrity": "sha512-xl+gUSp0B+ln1VSNoUftlglk8dfpUes3DHGxKZ5knuBxS5g2H/8p9/DSBOYWUfO5f4u9s6ffBPZ71WO+tbe5SA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz", + "integrity": "sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg==", "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", "class-transformer": "^0.4.0 || ^0.5.0", "class-validator": "^0.13.0 || ^0.14.0", - "reflect-metadata": "^0.1.12" + "reflect-metadata": "^0.1.12 || ^0.2.0" }, "peerDependenciesMeta": { "class-transformer": { @@ -2904,13 +2907,13 @@ } }, "node_modules/@nestjs/platform-express": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.3.1.tgz", - "integrity": "sha512-Rj21quI5h4Lry7q9an+nO4ADQiQUy9A6XK74o5aTUHo3Ysm25ujqh2NgU4XbT3M2oXU9qzhE59OfhkQ7ZUvTAg==", + "version": "10.3.7", + "resolved": "https://registry.npmjs.org/@nestjs/platform-express/-/platform-express-10.3.7.tgz", + "integrity": "sha512-noNJ+PyIxQJLCKfuXz0tcQtlVAynfLIuKy62g70lEZ86UrIqSrZFqvWs/rFUgkbT6J8H7Rmv11hASOnX+7M2rA==", "dependencies": { "body-parser": "1.20.2", "cors": "2.8.5", - "express": "4.18.2", + "express": "4.19.2", "multer": "1.4.4-lts.1", "tslib": "2.6.2" }, @@ -2924,39 +2927,46 @@ } }, "node_modules/@nestjs/schematics": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.1.0.tgz", - "integrity": "sha512-HQWvD3F7O0Sv3qHS2jineWxPLmBTLlyjT6VdSw2EAIXulitmV+ErxB3TCVQQORlNkl5p5cwRYWyBaOblDbNFIQ==", + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/@nestjs/schematics/-/schematics-10.1.1.tgz", + "integrity": "sha512-o4lfCnEeIkfJhGBbLZxTuVWcGuqDCFwg5OrvpgRUBM7vI/vONvKKiB5riVNpO+JqXoH0I42NNeDb0m4V5RREig==", "dev": true, "dependencies": { - "@angular-devkit/core": "17.0.9", - "@angular-devkit/schematics": "17.0.9", + "@angular-devkit/core": "17.1.2", + "@angular-devkit/schematics": "17.1.2", "comment-json": "4.2.3", - "jsonc-parser": "3.2.0", + "jsonc-parser": "3.2.1", "pluralize": "8.0.0" }, "peerDependencies": { "typescript": ">=4.8.2" } }, + "node_modules/@nestjs/schematics/node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", + "dev": true + }, "node_modules/@nestjs/swagger": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.2.0.tgz", - "integrity": "sha512-W7WPq561/79w27ZEgViXS7c5hqPwT7QXhsLsSeu2jeBROUhMM825QKDFKbMmtb643IW5dznJ4PjherlZZgtMvg==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/@nestjs/swagger/-/swagger-7.3.1.tgz", + "integrity": "sha512-LUC4mr+5oAleEC/a2j8pNRh1S5xhKXJ1Gal5ZdRjt9XebQgbngXCdW7JTA9WOEcwGtFZN9EnKYdquzH971LZfw==", "dependencies": { - "@nestjs/mapped-types": "2.0.4", + "@microsoft/tsdoc": "^0.14.2", + "@nestjs/mapped-types": "2.0.5", "js-yaml": "4.1.0", "lodash": "4.17.21", "path-to-regexp": "3.2.0", - "swagger-ui-dist": "5.11.0" + "swagger-ui-dist": "5.11.2" }, "peerDependencies": { - "@fastify/static": "^6.0.0", + "@fastify/static": "^6.0.0 || ^7.0.0", "@nestjs/common": "^9.0.0 || ^10.0.0", "@nestjs/core": "^9.0.0 || ^10.0.0", "class-transformer": "*", "class-validator": "*", - "reflect-metadata": "^0.1.12" + "reflect-metadata": "^0.1.12 || ^0.2.0" }, "peerDependenciesMeta": { "@fastify/static": { @@ -2971,9 +2981,9 @@ } }, "node_modules/@nestjs/terminus": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/@nestjs/terminus/-/terminus-10.2.1.tgz", - "integrity": "sha512-23abPhotIP4+hrCZ8YkLEOmZ3m7eUYh1QOwdyrNkU9eMz/nc5LpVzy7jFbsNUuvlnT4MPV/7KXfyQTruQkTouw==", + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/@nestjs/terminus/-/terminus-10.2.3.tgz", + "integrity": "sha512-iX7gXtAooePcyQqFt57aDke5MzgdkBeYgF5YsFNNFwOiAFdIQEhfv3PR0G+HlH9F6D7nBCDZt9U87Pks/qHijg==", "dependencies": { "boxen": "5.1.2", "check-disk-space": "3.4.0" @@ -2992,7 +3002,7 @@ "@nestjs/typeorm": "^9.0.0 || ^10.0.0", "@prisma/client": "*", "mongoose": "*", - "reflect-metadata": "0.1.x", + "reflect-metadata": "0.1.x || 0.2.x", "rxjs": "7.x", "sequelize": "*", "typeorm": "*" @@ -3040,9 +3050,9 @@ } }, "node_modules/@nestjs/testing": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.3.1.tgz", - "integrity": "sha512-74aSAugWT31jSPnStyRWDXgjHXWO3GYaUfAZ2T7Dml88UGkGy95iwaWgYy7aYM8/xVFKcDYkfL5FAYqZYce/yg==", + "version": "10.3.7", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.3.7.tgz", + "integrity": "sha512-PmwZXyoCC/m3F3IFgpgD+SNN6cDPQa/vi3YQxFruvfX3cuHq+P6ZFvBB7hwaKKsLlhA0so42LsMm41oFBkdouw==", "dev": true, "dependencies": { "tslib": "2.6.2" @@ -3067,32 +3077,20 @@ } }, "node_modules/@nestjs/typeorm": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.1.tgz", - "integrity": "sha512-YVFYL7D25VAVp5/G+KLXIgsRfYomA+VaFZBpm2rtwrrBOmkXNrxr7kuI2bBBO/Xy4kKBDe6wbvIVVFeEA7/ngA==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/typeorm/-/typeorm-10.0.2.tgz", + "integrity": "sha512-H738bJyydK4SQkRCTeh1aFBxoO1E9xdL/HaLGThwrqN95os5mEyAtK7BLADOS+vldP4jDZ2VQPLj4epWwRqCeQ==", "dependencies": { "uuid": "9.0.1" }, "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", - "reflect-metadata": "^0.1.13", + "reflect-metadata": "^0.1.13 || ^0.2.0", "rxjs": "^7.2.0", "typeorm": "^0.3.0" } }, - "node_modules/@nestjs/typeorm/node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3197,42 +3195,34 @@ "resolved": "https://registry.npmjs.org/@tediousjs/connection-string/-/connection-string-0.5.0.tgz", "integrity": "sha512-7qSgZbincDDDFyRweCIEvZULFAw5iz/DeunhvuxpL31nfntX3P4Yd4HkHBRg9H8CdqY1e5WFN1PZIz/REL9MVQ==" }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "engines": { - "node": ">= 10" - } - }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "devOptional": true + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "devOptional": true + "dev": true }, "node_modules/@tsconfig/node21": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/@tsconfig/node21/-/node21-21.0.1.tgz", - "integrity": "sha512-2Khg79N+z2Qkb9SjLzOi8cz2PSa/oUpHIeQm1YWzmWXkoFcPXFZSHgs+Z8iPCDjIoXFqMNYntiTXxfLYQMcRhw==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node21/-/node21-21.0.3.tgz", + "integrity": "sha512-qTX4pGNfnRTutaiRPx+c4GFL1DB1u6GHkwfoYSNn/KelE9m86Mkn3RpFBhhxDh6yHeqaVuAx0tz+n7LrjBUEpw==", "dev": true }, "node_modules/@types/babel__core": { @@ -3317,9 +3307,9 @@ "dev": true }, "node_modules/@types/eslint": { - "version": "8.56.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.2.tgz", - "integrity": "sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==", + "version": "8.56.7", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.7.tgz", + "integrity": "sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA==", "dev": true, "dependencies": { "@types/estree": "*", @@ -3355,9 +3345,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.42", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.42.tgz", - "integrity": "sha512-ckM3jm2bf/MfB3+spLPWYPUH573plBFwpOhqQ2WottxYV85j1HQFlxmnTq57X1yHY9awZPig06hL/cLMgNWHIQ==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -3406,9 +3396,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.11", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.11.tgz", - "integrity": "sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==", + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -3428,9 +3418,9 @@ "dev": true }, "node_modules/@types/lodash": { - "version": "4.14.202", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", - "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "version": "4.17.0", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", + "integrity": "sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==", "dev": true }, "node_modules/@types/methods": { @@ -3452,10 +3442,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.10.tgz", - "integrity": "sha512-rZEfe/hJSGYmdfX9tvcPMYeYPW2sNl50nsw4jZmRcaG0HIAb0WYEpsB05GOb53vjqpyE9GUhlDQ4jLSoB5q9kg==", - "devOptional": true, + "version": "20.12.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz", + "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==", "dependencies": { "undici-types": "~5.26.4" } @@ -3467,9 +3456,9 @@ "dev": true }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", "dev": true }, "node_modules/@types/range-parser": { @@ -3478,10 +3467,19 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", "dev": true }, + "node_modules/@types/readable-stream": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.11.tgz", + "integrity": "sha512-R3eUMUTTKoIoaz7UpYLxvZCrOmCRPRbAmoDDHKcimTEySltaJhF8hLzj4+EzyDifiX5eK6oDQGSfmNnXjxZzYQ==", + "dependencies": { + "@types/node": "*", + "safe-buffer": "~5.1.1" + } + }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/send": { @@ -3495,14 +3493,14 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/stack-utils": { @@ -3512,9 +3510,9 @@ "dev": true }, "node_modules/@types/superagent": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.3.tgz", - "integrity": "sha512-R/CfN6w2XsixLb1Ii8INfn+BT9sGPvw74OavfkW4SwY+jeUcAwLZv2+bXLJkndnimxjEBm0RPHgcjW9pLCa8cw==", + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.6.tgz", + "integrity": "sha512-yzBOv+6meEHSzV2NThYYOA6RtqvPr3Hbob9ZLp3i07SH27CrYVfm8CrF7ydTmidtelsFiKx2I4gZAiAOamGgvQ==", "dev": true, "dependencies": { "@types/cookiejar": "^2.1.5", @@ -3533,9 +3531,9 @@ } }, "node_modules/@types/validator": { - "version": "13.11.8", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.8.tgz", - "integrity": "sha512-c/hzNDBh7eRF+KbCf+OoZxKbnkpaK/cKp9iLQWqB7muXtM+MtL9SUUH8vCFcLn6dH1Qm05jiexK0ofWY7TfOhQ==" + "version": "13.11.9", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.9.tgz", + "integrity": "sha512-FCTsikRozryfayPuiI46QzH3fnrOoctTjvOYZkho9BTFLCOZ2rgZJHMOVgCOfttjPJcgOx52EpkY0CMfy87MIw==" }, "node_modules/@types/yargs": { "version": "17.0.32", @@ -3553,16 +3551,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz", - "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/type-utils": "6.19.1", - "@typescript-eslint/utils": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -3588,15 +3586,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz", - "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { @@ -3616,13 +3614,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz", - "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3633,13 +3631,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz", - "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.1", - "@typescript-eslint/utils": "6.19.1", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -3660,9 +3658,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz", - "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3673,13 +3671,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz", - "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/visitor-keys": "6.19.1", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3701,17 +3699,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz", - "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.1", - "@typescript-eslint/types": "6.19.1", - "@typescript-eslint/typescript-estree": "6.19.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { @@ -3726,12 +3724,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz", - "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.1", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -3749,9 +3747,9 @@ "dev": true }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", - "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", "dev": true, "dependencies": { "@webassemblyjs/helper-numbers": "1.11.6", @@ -3771,9 +3769,9 @@ "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", - "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { @@ -3794,15 +3792,15 @@ "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", - "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6" + "@webassemblyjs/wasm-gen": "1.12.1" } }, "node_modules/@webassemblyjs/ieee754": { @@ -3830,28 +3828,28 @@ "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", - "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", - "@webassemblyjs/helper-wasm-section": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-opt": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6", - "@webassemblyjs/wast-printer": "1.11.6" + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", - "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", "@webassemblyjs/leb128": "1.11.6", @@ -3859,24 +3857,24 @@ } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", - "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", - "@webassemblyjs/helper-buffer": "1.11.6", - "@webassemblyjs/wasm-gen": "1.11.6", - "@webassemblyjs/wasm-parser": "1.11.6" + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", - "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@webassemblyjs/helper-api-error": "1.11.6", "@webassemblyjs/helper-wasm-bytecode": "1.11.6", "@webassemblyjs/ieee754": "1.11.6", @@ -3885,12 +3883,12 @@ } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.6", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", - "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/ast": "1.12.1", "@xtuc/long": "4.2.2" } }, @@ -3933,7 +3931,7 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "devOptional": true, + "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -3963,31 +3961,31 @@ "version": "8.3.2", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.4.0" } }, "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dependencies": { - "debug": "4" + "debug": "^4.3.4" }, "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -4012,28 +4010,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, "node_modules/ajv-keywords": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", @@ -4159,7 +4135,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "devOptional": true + "dev": true }, "node_modules/argparse": { "version": "2.0.1", @@ -4176,12 +4152,15 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4199,15 +4178,16 @@ "dev": true }, "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", "is-string": "^1.0.7" }, "engines": { @@ -4232,17 +4212,38 @@ "node": ">=8" } }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4287,30 +4288,43 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.tosorted": { + "node_modules/array.prototype.toreversed": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", - "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", "is-shared-array-buffer": "^1.0.2" }, "engines": { @@ -4341,15 +4355,6 @@ "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", "dev": true }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -4364,9 +4369,12 @@ } }, "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -4384,11 +4392,11 @@ } }, "node_modules/axios": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", - "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", "dependencies": { - "follow-redirects": "^1.15.4", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -4554,12 +4562,15 @@ } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { @@ -4664,9 +4675,9 @@ } }, "node_modules/browserslist": { - "version": "4.22.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", - "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", "dev": true, "funding": [ { @@ -4683,8 +4694,8 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001580", - "electron-to-chromium": "^1.4.648", + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", "node-releases": "^2.0.14", "update-browserslist-db": "^1.0.13" }, @@ -4770,13 +4781,18 @@ } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4829,9 +4845,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001580", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001580.tgz", - "integrity": "sha512-mtj5ur2FFPZcCEpXFy8ADXbDACuNFXg6mxVDqp7tqooX6l3zwm+d8EPoeOSIFRDvHs8qu7/SLFOGniULkcH2iA==", + "version": "1.0.30001608", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001608.tgz", + "integrity": "sha512-cjUJTQkk9fQlJR2s4HMuPMvTiRggl0rAVMtthQuyOlDWuqHXqN8azLq+pi8B2TjwKJ32diHjUqRIKeFX4z1FoA==", "dev": true, "funding": [ { @@ -4920,16 +4936,10 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4942,6 +4952,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -5513,9 +5526,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -5616,7 +5629,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "devOptional": true + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", @@ -5659,27 +5672,27 @@ } }, "node_modules/cspell": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.3.2.tgz", - "integrity": "sha512-V8Ub3RO/a5lwSsltW/ib3Z3G/sczKtSpBBN1JChzbSCfEgaY2mJY8JW0BpkSV+Ug6uJitpXNOOaxa3Xr489i7g==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.7.0.tgz", + "integrity": "sha512-77nRPgLl240C6FK8RKVKo34lP15Lzp/6bk+SKYJFwUKKXlcgWXDis+Lw4JolA741/JgHtuxmhW1C8P7dCKjJ3w==", "dev": true, "dependencies": { - "@cspell/cspell-json-reporter": "8.3.2", - "@cspell/cspell-pipe": "8.3.2", - "@cspell/cspell-types": "8.3.2", - "@cspell/dynamic-import": "8.3.2", + "@cspell/cspell-json-reporter": "8.7.0", + "@cspell/cspell-pipe": "8.7.0", + "@cspell/cspell-types": "8.7.0", + "@cspell/dynamic-import": "8.7.0", "chalk": "^5.3.0", "chalk-template": "^1.1.0", - "commander": "^11.1.0", - "cspell-gitignore": "8.3.2", - "cspell-glob": "8.3.2", - "cspell-io": "8.3.2", - "cspell-lib": "8.3.2", + "commander": "^12.0.0", + "cspell-gitignore": "8.7.0", + "cspell-glob": "8.7.0", + "cspell-io": "8.7.0", + "cspell-lib": "8.7.0", "fast-glob": "^3.3.2", "fast-json-stable-stringify": "^2.1.0", "file-entry-cache": "^8.0.0", "get-stdin": "^9.0.0", - "semver": "^7.5.4", + "semver": "^7.6.0", "strip-ansi": "^7.1.0", "vscode-uri": "^3.0.8" }, @@ -5695,42 +5708,42 @@ } }, "node_modules/cspell-config-lib": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.3.2.tgz", - "integrity": "sha512-Wc98XhBNLwDxnxCzMtgRJALI9a69cu3C5Gf1rGjNTKSFo9JYiQmju0Ur3z25Pkx9Sa86f+2IjvNCf33rUDSoBQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.7.0.tgz", + "integrity": "sha512-depsd01GbLBo71/tfRrL5iECWQLS4CjCxA9C01dVkFAJqVB0s+K9KLKjTlq5aHOhcvo9Z3dHV+bGQCf5/Q7bfw==", "dev": true, "dependencies": { - "@cspell/cspell-types": "8.3.2", + "@cspell/cspell-types": "8.7.0", "comment-json": "^4.2.3", - "yaml": "^2.3.4" + "yaml": "^2.4.1" }, "engines": { "node": ">=18" } }, "node_modules/cspell-dictionary": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.3.2.tgz", - "integrity": "sha512-xyK95hO2BMPFxIo8zBwGml8035qOxSBdga1BMhwW/p2wDrQP8S4Cdm/54//tCDmKn6uRkFQvyOfWGaX2l8WMEg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.7.0.tgz", + "integrity": "sha512-S6IpZSzIMxlOO/33NgCOuP0TPH2mZbw8d5CP44z5jajflloq8l74MeJLkeDzYfCRcm0Rtk0A5drBeMg+Ai34OA==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.3.2", - "@cspell/cspell-types": "8.3.2", - "cspell-trie-lib": "8.3.2", + "@cspell/cspell-pipe": "8.7.0", + "@cspell/cspell-types": "8.7.0", + "cspell-trie-lib": "8.7.0", "fast-equals": "^5.0.1", - "gensequence": "^6.0.0" + "gensequence": "^7.0.0" }, "engines": { "node": ">=18" } }, "node_modules/cspell-gitignore": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.3.2.tgz", - "integrity": "sha512-3Qc9P5BVvl/cg//s2s+zIMGKcoH5v7oOtRgwn4UQry8yiyo19h0tiTKkSR574FMhF5NtcShTnwIwPSIXVBPFHA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.7.0.tgz", + "integrity": "sha512-yvUZ86qyopUpDgn+YXP1qTpUe/lp65ZFvpMtw21lWHTFlg1OWKntr349EQU/5ben/K6koxk1FiElCBV7Lr4uFg==", "dev": true, "dependencies": { - "cspell-glob": "8.3.2", + "cspell-glob": "8.7.0", "find-up-simple": "^1.0.0" }, "bin": { @@ -5741,9 +5754,9 @@ } }, "node_modules/cspell-glob": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.3.2.tgz", - "integrity": "sha512-KtIFxE+3l5dGEofND4/CdZffXP8XN1+XGQKxJ96lIzWsc01mkotfhxTkla6mgvfH039t7BsY/SWv0460KyGslQ==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.7.0.tgz", + "integrity": "sha512-AMdfx0gvROA/aIL8t8b5Y5NtMgscGZELFj6WhCSZiQSuWRxXUKiLGGLUFjx2y0hgXN9LUYOo6aBjvhnxI/v71g==", "dev": true, "dependencies": { "micromatch": "^4.0.5" @@ -5753,13 +5766,13 @@ } }, "node_modules/cspell-grammar": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.3.2.tgz", - "integrity": "sha512-tYCkOmRzJe1a6/R+8QGSwG7TwTgznLPqsHtepKzLmnS4YX54VXjKRI9zMARxXDzUVfyCSVdW5MyiY/0WTNoy+A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.7.0.tgz", + "integrity": "sha512-SGcXc7322wU2WNRi7vtpToWDXTqZHhxqvR+aIXHT2kkxlMSWp3Rvfpshd0ckgY54nZtgw7R/JtKND2jeACRpwQ==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.3.2", - "@cspell/cspell-types": "8.3.2" + "@cspell/cspell-pipe": "8.7.0", + "@cspell/cspell-types": "8.7.0" }, "bin": { "cspell-grammar": "bin.mjs" @@ -5769,40 +5782,40 @@ } }, "node_modules/cspell-io": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.3.2.tgz", - "integrity": "sha512-WYpKsyBCQP0SY4gXnhW5fPuxcYchKYKG1PIXVV3ezFU4muSgW6GuLNbGuSfwv/8YNXRgFSN0e3hYH0rdBK2Aow==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.7.0.tgz", + "integrity": "sha512-o7OltyyvVkRG1gQrIqGpN5pUkHNnv6rvihb7Qu6cJ8jITinLGuWJuEQpgt0eF5yIr624jDbFwSzAxsFox8riQg==", "dev": true, "dependencies": { - "@cspell/cspell-service-bus": "8.3.2" + "@cspell/cspell-service-bus": "8.7.0" }, "engines": { "node": ">=18" } }, "node_modules/cspell-lib": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.3.2.tgz", - "integrity": "sha512-wTvdaev/TyGB/ln6CVD1QbVs2D7/+QiajQ67S7yj1suLHM6YcNQQb/5sPAM8VPtj0E7PgwgPXf3bq18OtPvnFg==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.7.0.tgz", + "integrity": "sha512-qDSHZGekwiDmouYRECTQokE+hgAuPqREm+Hb+G3DoIo3ZK5H47TtEUo8fNCw22XsKefcF8X28LiyoZwiYHVpSg==", "dev": true, "dependencies": { - "@cspell/cspell-bundled-dicts": "8.3.2", - "@cspell/cspell-pipe": "8.3.2", - "@cspell/cspell-resolver": "8.3.2", - "@cspell/cspell-types": "8.3.2", - "@cspell/dynamic-import": "8.3.2", - "@cspell/strong-weak-map": "8.3.2", + "@cspell/cspell-bundled-dicts": "8.7.0", + "@cspell/cspell-pipe": "8.7.0", + "@cspell/cspell-resolver": "8.7.0", + "@cspell/cspell-types": "8.7.0", + "@cspell/dynamic-import": "8.7.0", + "@cspell/strong-weak-map": "8.7.0", "clear-module": "^4.1.2", "comment-json": "^4.2.3", "configstore": "^6.0.0", - "cspell-config-lib": "8.3.2", - "cspell-dictionary": "8.3.2", - "cspell-glob": "8.3.2", - "cspell-grammar": "8.3.2", - "cspell-io": "8.3.2", - "cspell-trie-lib": "8.3.2", + "cspell-config-lib": "8.7.0", + "cspell-dictionary": "8.7.0", + "cspell-glob": "8.7.0", + "cspell-grammar": "8.7.0", + "cspell-io": "8.7.0", + "cspell-trie-lib": "8.7.0", "fast-equals": "^5.0.1", - "gensequence": "^6.0.0", + "gensequence": "^7.0.0", "import-fresh": "^3.3.0", "resolve-from": "^5.0.0", "vscode-languageserver-textdocument": "^1.0.11", @@ -5813,14 +5826,14 @@ } }, "node_modules/cspell-trie-lib": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.3.2.tgz", - "integrity": "sha512-8qh2FqzkLMwzlTlvO/5Z+89fhi30rrfekocpight/BmqKbE2XFJQD7wS2ml24e7q/rdHJLXVpJbY/V5mByucCA==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.7.0.tgz", + "integrity": "sha512-W3Nh2cO7gMV91r+hLqyTMgKlvRl4W5diKs5YiyOxjZumRkMBy42IzcNYtgIIacOxghklv96F5Bd1Vx/zY6ylGA==", "dev": true, "dependencies": { - "@cspell/cspell-pipe": "8.3.2", - "@cspell/cspell-types": "8.3.2", - "gensequence": "^6.0.0" + "@cspell/cspell-pipe": "8.7.0", + "@cspell/cspell-types": "8.7.0", + "gensequence": "^7.0.0" }, "engines": { "node": ">=18" @@ -5839,12 +5852,12 @@ } }, "node_modules/cspell/node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.0.0.tgz", + "integrity": "sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/damerau-levenshtein": { @@ -5862,10 +5875,58 @@ "node": ">=8" } }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/date-fns": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz", - "integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -5935,9 +5996,9 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, "peerDependencies": { "babel-plugin-macros": "^3.1.0" @@ -5976,16 +6037,19 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-lazy-prop": { @@ -6038,9 +6102,9 @@ } }, "node_modules/destr": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.2.tgz", - "integrity": "sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.3.tgz", + "integrity": "sha512-2N3BOUU4gYMpTP24s5rF5iP7BDr7uNTCs4ozw3kf/eKfvWSIu93GEBi5m427YoyJoeOzQ5smuu4nNAPGb8idSQ==" }, "node_modules/destroy": { "version": "1.2.0", @@ -6083,7 +6147,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "devOptional": true, + "dev": true, "engines": { "node": ">=0.3.1" } @@ -6134,14 +6198,14 @@ } }, "node_modules/dotenv": { - "version": "16.4.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.1.tgz", - "integrity": "sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==", + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://dotenvx.com" } }, "node_modules/dotenv-expand": { @@ -6176,9 +6240,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.648", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.648.tgz", - "integrity": "sha512-EmFMarXeqJp9cUKu/QEciEApn0S/xRcpZWuAm32U7NgoZCimjsilKXHRO9saeEW55eHZagIDg6XTUOv32w9pjg==", + "version": "1.4.733", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.733.tgz", + "integrity": "sha512-gUI9nhI2iBGF0OaYYLKOaOtliFMl+Bt1rY7VmEjwxOxqoYLub/D9xmduPEhbw2imE6gYkJKhIE5it+KE2ulVxQ==", "dev": true }, "node_modules/emittery": { @@ -6215,9 +6279,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -6227,6 +6291,17 @@ "node": ">=10.13.0" } }, + "node_modules/envix": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/envix/-/envix-1.5.0.tgz", + "integrity": "sha512-IOxTKT+tffjxgvX2O5nq6enbkv6kBQ/QdMy18bZWo0P0rKPvsRp2/EypIPwTvJfnmk3VdOlq/KcRSZCswefM/w==", + "dependencies": { + "std-env": "^3.7.0" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6237,49 +6312,56 @@ } }, "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", + "version": "1.23.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", + "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", "globalthis": "^1.0.3", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", + "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", "object-inspect": "^1.13.1", "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.6", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" @@ -6289,18 +6371,18 @@ } }, "node_modules/es-aggregate-error": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.11.tgz", - "integrity": "sha512-DCiZiNlMlbvofET/cE55My387NiLvuGToBEZDdK9U2G3svDCjL8WOgO5Il6lO83nQ8qmag/R9nArdpaFQ/m3lA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.13.tgz", + "integrity": "sha512-KkzhUUuD2CUMqEc8JEqsXEMDHzDPE8RCjZeUBitsnB1eNcAJWQPiciKsMXe3Yytj4Flw1XLl46Qcf9OxvZha7A==", "dependencies": { - "define-data-property": "^1.1.0", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.22.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "set-function-name": "^2.0.1" + "has-property-descriptors": "^1.0.2", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -6309,42 +6391,75 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-iterator-helpers": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", - "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", "dev": true, "dependencies": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "define-properties": "^1.2.1", - "es-abstract": "^1.22.1", - "es-set-tostringtag": "^2.0.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", + "internal-slot": "^1.0.7", "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.0.1" + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/es-module-lexer": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", - "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.0.tgz", + "integrity": "sha512-pqrTKmwEIgafsYZAGw9kszYzmagcE/n4dbgwGWLEXg7J4QFJVQRBld8j3Q3GNez79jzxZshq0bcT962QHOghjw==", "dev": true }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -6376,9 +6491,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "engines": { "node": ">=6" } @@ -6401,16 +6516,16 @@ } }, "node_modules/eslint": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", - "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.56.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -6857,9 +6972,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -7061,9 +7176,9 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "27.6.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.3.tgz", - "integrity": "sha512-+YsJFVH6R+tOiO3gCJon5oqn4KWc+mDq2leudk8mrp8RFubLOo9CVyi3cib4L7XMpxExmkmBZQTPDYVBzgpgOA==", + "version": "27.9.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.9.0.tgz", + "integrity": "sha512-QIT7FH7fNmd9n4se7FFKHbsLKGQiw885Ds6Y/sxKgCZ6natwCsXdgPOADnYVxN2QrRweF0FZWbJ6S7Rsn7llug==", "dev": true, "dependencies": { "@typescript-eslint/utils": "^5.10.0" @@ -7072,7 +7187,7 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0", + "@typescript-eslint/eslint-plugin": "^5.0.0 || ^6.0.0 || ^7.0.0", "eslint": "^7.0.0 || ^8.0.0", "jest": "*" }, @@ -7365,27 +7480,29 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", "dev": true, "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", + "es-iterator-helpers": "^1.0.17", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", + "resolve": "^2.0.0-next.5", "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" + "string.prototype.matchall": "^4.0.10" }, "engines": { "node": ">=4" @@ -7467,9 +7584,9 @@ } }, "node_modules/eslint-plugin-security": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-2.1.0.tgz", - "integrity": "sha512-ywxclP954bf8d3gr6KOQ/AFc+PRvWuhOxtPOEtiHmVYiZr/mcgQtmSJq6+hTEXC5ylTjHnPPG+PEnzlDiWMXbQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-2.1.1.tgz", + "integrity": "sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w==", "dev": true, "dependencies": { "safe-regex": "^2.1.1" @@ -7498,9 +7615,9 @@ } }, "node_modules/eslint-plugin-unused-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz", - "integrity": "sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.1.0.tgz", + "integrity": "sha512-9l1YFCzXKkw1qtAru1RWUtG2EVDZY0a0eChKXcL+EZ5jitG7qxdctu4RnvhOJHv4xfmUf7h+JJPINlVpGhZMrw==", "dev": true, "dependencies": { "eslint-rule-composer": "^0.3.0" @@ -7509,8 +7626,8 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.0.0", - "eslint": "^8.0.0" + "@typescript-eslint/eslint-plugin": "6 - 7", + "eslint": "8" }, "peerDependenciesMeta": { "@typescript-eslint/eslint-plugin": { @@ -7579,6 +7696,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -7656,6 +7789,12 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -7846,16 +7985,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -7894,29 +8033,6 @@ "basic-auth": "^2.0.1" } }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7935,20 +8051,6 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7983,9 +8085,9 @@ } }, "node_modules/fast-copy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.1.tgz", - "integrity": "sha512-Knr7NOtK3HWRYGtHoJrjkaWepqT8thIVGAwt0p0aUs1zqkAzXZV4vo9fFNwyb5fcqK1GKYFYxldQdIDVKhUAfA==" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==" }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -8036,9 +8138,9 @@ "dev": true }, "node_modules/fast-redact": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.3.0.tgz", - "integrity": "sha512-6T5V1QK1u4oF+ATxs1lWUmlEk6P2T9HqJG3e2DnHOdVgZy2rFJBoEnrIedcTXlkAHU/zKC+7KETJ+KGGKwxgMQ==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", "engines": { "node": ">=6" } @@ -8049,9 +8151,9 @@ "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" }, "node_modules/fastq": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.0.tgz", - "integrity": "sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dependencies": { "reusify": "^1.0.4" } @@ -8179,47 +8281,28 @@ } }, "node_modules/flat-cache": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.0.tgz", - "integrity": "sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.4", - "rimraf": "^5.0.5" + "keyv": "^4.5.4" }, "engines": { "node": ">=16" } }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, "node_modules/follow-redirects": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", - "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -8437,12 +8520,12 @@ } }, "node_modules/gensequence": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-6.0.0.tgz", - "integrity": "sha512-8WwuywE9pokJRAcg2QFR/plk3cVPebSUqRPzpGQh3WQ0wIiHAw+HyOQj5IuHyUTQBHpBKFoB2JUMu9zT3vJ16Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-7.0.0.tgz", + "integrity": "sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==", "dev": true, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/gensync": { @@ -8475,15 +8558,19 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8522,12 +8609,13 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" }, "engines": { "node": ">= 0.4" @@ -8537,9 +8625,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", - "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", "dev": true, "dependencies": { "resolve-pkg-maps": "^1.0.0" @@ -8823,20 +8911,20 @@ } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { "node": ">= 0.4" }, @@ -8856,11 +8944,11 @@ } }, "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dependencies": { - "has-symbols": "^1.0.2" + "has-symbols": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -8870,9 +8958,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -8954,28 +9042,27 @@ } }, "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dependencies": { - "agent-base": "6", + "agent-base": "^7.0.2", "debug": "4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/human-signals": { @@ -8988,12 +9075,12 @@ } }, "node_modules/husky": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.6.tgz", - "integrity": "sha512-EEuw/rfTiMjOfuL7pGO/i9otg1u36TXxqjIA6D9qxVjd/UXoDOsLor/BSFf5hTK50shwzCU3aVVwdXDp/lp7RA==", + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.11.tgz", + "integrity": "sha512-AB6lFlbwwyIqMdHYhwPe+kjOC3Oc5P3nThEoW/AaO2BX3vJDjWPFxYLxokUZOo6RNX20He3AaT8sESs9NJcmEw==", "dev": true, "bin": { - "husky": "bin.js" + "husky": "bin.mjs" }, "engines": { "node": ">=18" @@ -9033,9 +9120,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -9211,11 +9298,11 @@ } }, "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", "dependencies": { - "get-intrinsic": "^1.2.2", + "es-errors": "^1.3.0", "hasown": "^2.0.0", "side-channel": "^1.0.4" }, @@ -9241,13 +9328,15 @@ } }, "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9335,6 +9424,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-date-object": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", @@ -9440,18 +9543,21 @@ } }, "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "engines": { "node": ">= 0.4" }, @@ -9527,20 +9633,26 @@ } }, "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", "dependencies": { - "call-bind": "^1.0.2" + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9599,11 +9711,11 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", "dependencies": { - "which-typed-array": "^1.1.11" + "which-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -9631,10 +9743,13 @@ } }, "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9651,13 +9766,16 @@ } }, "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9694,14 +9812,14 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -9747,9 +9865,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -10532,9 +10650,9 @@ "dev": true }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, "node_modules/json-stable-stringify-without-jsonify": { @@ -10745,9 +10863,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.10.54", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.54.tgz", - "integrity": "sha512-P+38dUgJsmh0gzoRDoM4F5jLbyfztkU6PY6eSK6S5HwTi/LPvnwXqVCQZlAy1FxZ5c48q25QhxGQ0pq+WQcSlQ==" + "version": "1.10.60", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.60.tgz", + "integrity": "sha512-Ctgq2lXUpEJo5j1762NOzl2xo7z7pqmVWYai0p07LvAkQ32tbPv3wb+tcUeHEiXhKU5buM4H9MXsXo6OlM6C2g==" }, "node_modules/lilconfig": { "version": "3.0.0", @@ -10765,9 +10883,9 @@ "dev": true }, "node_modules/lint-staged": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.0.tgz", - "integrity": "sha512-TFZzUEV00f+2YLaVPWBWGAMq7So6yQx+GG8YRMDeOEIf95Zn5RyiLMsEiX4KTNl9vq/w+NqRJkLA1kPIo15ufQ==", + "version": "15.2.2", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", + "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", "dev": true, "dependencies": { "chalk": "5.3.0", @@ -10775,7 +10893,7 @@ "debug": "4.3.4", "execa": "8.0.1", "lilconfig": "3.0.0", - "listr2": "8.0.0", + "listr2": "8.0.1", "micromatch": "4.0.5", "pidtree": "0.6.0", "string-argv": "0.3.2", @@ -10881,9 +10999,9 @@ } }, "node_modules/lint-staged/node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -10946,10 +11064,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lint-staged/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, "node_modules/listr2": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.0.tgz", - "integrity": "sha512-u8cusxAcyqAiQ2RhYvV7kRKNLgUvtObIbhOX2NCXqvp1UU32xIg5CT22ykS2TPKJXZWJwtK3IKLiqAGlGNE+Zg==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", + "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", @@ -11040,16 +11167,16 @@ } }, "node_modules/locter": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/locter/-/locter-2.0.2.tgz", - "integrity": "sha512-bb/7J2yiGa9UzoFRoTXXQSPBEGirz7wddD996LcrJ6x0MV6TxrwkL6lVNIsFoYboj7gQLjnZLaB6f0F1pBdRRQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/locter/-/locter-2.1.0.tgz", + "integrity": "sha512-QUPPtb6CQ3hOacDZq2kc6KMzYn9z6r9B2RtFJTBD9nqxmyQJVYnTNZNqY6Z5NcJfwsGEgJLddnfFpofg7EJMDg==", "dependencies": { - "destr": "^2.0.2", + "destr": "^2.0.3", "ebec": "^2.3.0", "fast-glob": "^3.3.2", "flat": "^5.0.2", "jiti": "^1.21.0", - "yaml": "^2.3.4" + "yaml": "^2.4.1" } }, "node_modules/lodash": { @@ -11200,13 +11327,10 @@ } }, "node_modules/log-update/node_modules/ansi-escapes": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.0.tgz", - "integrity": "sha512-kzRaCqXnpzWs+3z5ABPQiVke+iq0KXkHo8xiWV4RPTi5Yli0l97BEQuhXV1s7+aSU/fu1kUuxgS4MsQ0fRuygw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", + "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, - "dependencies": { - "type-fest": "^3.0.0" - }, "engines": { "node": ">=14.16" }, @@ -11311,18 +11435,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/type-fest": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", - "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", @@ -11400,7 +11512,7 @@ "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "devOptional": true + "dev": true }, "node_modules/makeerror": { "version": "1.0.12", @@ -11736,9 +11848,9 @@ } }, "node_modules/nock": { - "version": "13.5.1", - "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.1.tgz", - "integrity": "sha512-+s7b73fzj5KnxbKH4Oaqz07tQ8degcMilU4rrmnKvI//b0JMBU4wEXFQ8zqr+3+L4eWSfU3H/UoIVGUV0tue1Q==", + "version": "13.5.4", + "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.4.tgz", + "integrity": "sha512-yAyTfdeNJGGBFxWdzSKCBYxs5FxLbCg5X5Q4ets974hcQzG1+qCxvIyOo4j2Ry6MUlhWVMX4OoYDefAIIwupjw==", "dev": true, "dependencies": { "debug": "^4.1.0", @@ -11872,28 +11984,29 @@ } }, "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -11903,39 +12016,45 @@ } }, "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" } }, "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", "dev": true, "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -12251,11 +12370,11 @@ "dev": true }, "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", + "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { @@ -12323,14 +12442,14 @@ } }, "node_modules/pino": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/pino/-/pino-8.17.2.tgz", - "integrity": "sha512-LA6qKgeDMLr2ux2y/YiUt47EfgQ+S9LznBWOJdN3q1dx2sv0ziDLUBeVpyVv17TEcGCBuWf0zNtg3M5m1NhhWQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-8.20.0.tgz", + "integrity": "sha512-uhIfMj5TVp+WynVASaVEJFTncTUe4dHBq6CWplu/vBgvGHhvBvQfxz+vcOrnnBQdORH3izaGEurLfNlq3YxdFQ==", "dependencies": { "atomic-sleep": "^1.0.0", "fast-redact": "^3.1.1", "on-exit-leak-free": "^2.1.0", - "pino-abstract-transport": "v1.1.0", + "pino-abstract-transport": "^1.1.0", "pino-std-serializers": "^6.0.0", "process-warning": "^3.0.0", "quick-format-unescaped": "^4.0.3", @@ -12604,6 +12723,14 @@ "node": ">=4" } }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -12614,9 +12741,9 @@ } }, "node_modules/prettier": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.4.tgz", - "integrity": "sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -12753,14 +12880,15 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "engines": { "node": ">=6" } }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -13075,20 +13203,21 @@ } }, "node_modules/reflect-metadata": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", - "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==" + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==" }, "node_modules/reflect.getprototypeof": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", - "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", "globalthis": "^1.0.3", "which-builtin-type": "^1.1.3" }, @@ -13115,13 +13244,14 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -13363,12 +13493,12 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -13399,12 +13529,12 @@ } }, "node_modules/safe-regex-test": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", - "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", "is-regex": "^1.1.4" }, "engines": { @@ -13445,15 +13575,37 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/secure-json-parse": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -13545,28 +13697,30 @@ } }, "node_modules/set-function-length": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.0.tgz", - "integrity": "sha512-4DBHDoyHlM1IRPGYcoxexgh67y4ueR53FKV1yyxwFMY7aCqcN/38M1+SwZ/qJQ8iLv7+ck385ot4CcisOAPT9w==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dependencies": { - "define-data-property": "^1.0.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -13668,13 +13822,17 @@ } }, "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -13730,14 +13888,14 @@ } }, "node_modules/smob": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", - "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==" }, "node_modules/sonic-boom": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.0.tgz", - "integrity": "sha512-ybz6OYOUjoQQCQ/i4LU8kaToD8ACtYP+Cj5qd2AO36bwbdewxWJ3ArmJ2cr6AvxlL2o0PqnCcPGUgkILbfkaCA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-3.8.1.tgz", + "integrity": "sha512-y4Z8LCDBuum+PBP3lSV7RHrXscqksve/bi0as7mhwVnBW+/wUqKT/2Kb7um8yqcFy0duYbbPxzt89Zy2nOCaxg==", "dependencies": { "atomic-sleep": "^1.0.0" } @@ -13749,9 +13907,9 @@ "dev": true }, "node_modules/sort-package-json": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-2.6.0.tgz", - "integrity": "sha512-XSQ+lY9bAYA8ZsoChcEoPlgcSMaheziEp1beox1JVxy1SV4F2jSq9+h2rJ+3mC/Dhu9Ius1DLnInD5AWcsDXZw==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-2.10.0.tgz", + "integrity": "sha512-MYecfvObMwJjjJskhxYfuOADkXp1ZMMnCFC8yhp+9HDsk7HhR336hd7eiBs96lTXfiqmUNI+WQCeCMRBhl251g==", "dev": true, "dependencies": { "detect-indent": "^7.0.1", @@ -13760,6 +13918,7 @@ "git-hooks-list": "^3.0.0", "globby": "^13.1.2", "is-plain-obj": "^4.1.0", + "semver": "^7.6.0", "sort-object-keys": "^1.1.3" }, "bin": { @@ -13848,9 +14007,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", - "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -13864,9 +14023,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/split2": { @@ -13911,6 +14070,11 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" + }, "node_modules/stoppable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", @@ -14071,33 +14235,40 @@ } }, "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", "dev": true, "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -14107,26 +14278,29 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -14277,9 +14451,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.0.tgz", - "integrity": "sha512-j0PIATqQSEFGOLmiJOJZj1X1Jt6bFIur3JpY7+ghliUnfZs0fpWDdHEkn9q7QUlBtKbkn6TepvSxTqnE8l3s0A==" + "version": "5.11.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.11.2.tgz", + "integrity": "sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A==" }, "node_modules/symbol-observable": { "version": "4.0.0", @@ -14324,9 +14498,9 @@ } }, "node_modules/tedious": { - "version": "16.6.1", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-16.6.1.tgz", - "integrity": "sha512-KKSDB1OPrPk0WbMPug9YqRbPl44zMjdL2hFyzLEidr2IkItzpV0ZbzW8VA47QIS2oyWhCU7ifIEQY12n23IRDA==", + "version": "16.7.1", + "resolved": "https://registry.npmjs.org/tedious/-/tedious-16.7.1.tgz", + "integrity": "sha512-NmedZS0NJiTv3CoYnf1FtjxIDUgVYzEmavrc8q2WHRb+lP4deI9BpQfmNnBZZaWusDbP5FVFZCcvzb3xOlNVlQ==", "dependencies": { "@azure/identity": "^3.4.1", "@azure/keyvault-keys": "^4.4.0", @@ -14338,7 +14512,6 @@ "jsbi": "^4.3.0", "native-duplexpair": "^1.0.0", "node-abort-controller": "^3.1.1", - "punycode": "^2.3.0", "sprintf-js": "^1.1.2" }, "engines": { @@ -14346,10 +14519,11 @@ } }, "node_modules/tedious/node_modules/bl": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.10.tgz", - "integrity": "sha512-F14DFhDZfxtVm2FY0k9kG2lWAwzZkO9+jX3Ytuoy/V0E1/5LBuBzzQHXAjqpxXEDIpmTPZZf5GVIGPQcLxFpaA==", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.12.tgz", + "integrity": "sha512-EnEYHilP93oaOa2MnmNEjAcovPS3JlQZOyzGXi3EyEpPhm9qWvdDp7BmAVEVusGzp8LlwQK56Av+OkDoRjzE0w==", "dependencies": { + "@types/readable-stream": "^4.0.0", "buffer": "^6.0.3", "inherits": "^2.0.4", "readable-stream": "^4.2.0" @@ -14432,9 +14606,9 @@ } }, "node_modules/terser": { - "version": "5.27.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz", - "integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==", + "version": "5.30.3", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.30.3.tgz", + "integrity": "sha512-STdUgOUx8rLbMGO9IOwHLpCqolkDITFFQSMYYwKE1N2lY6MVSaeoi10z/EhWxRc6ybqoVmKSkhKYH/XUpl7vSA==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -14718,12 +14892,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -14796,7 +14970,7 @@ "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "devOptional": true, + "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -14941,27 +15115,28 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -14971,15 +15146,16 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" }, "engines": { "node": ">= 0.4" @@ -14989,13 +15165,19 @@ } }, "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", "dependencies": { - "call-bind": "^1.0.2", + "call-bind": "^1.0.7", "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -15121,17 +15303,18 @@ } }, "node_modules/typeorm-extension": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/typeorm-extension/-/typeorm-extension-3.4.0.tgz", - "integrity": "sha512-eQsOZmea8tSF8GULPIbc0HPuYRUTLvGBnP8B/Y9Hyk5q0JFj09+PGKeG7YL1jm9hOsVqZLF0Lab7p0vKdaR+Cg==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/typeorm-extension/-/typeorm-extension-3.5.1.tgz", + "integrity": "sha512-gykF1eBattSIt+F0+134c+j+AFODYCb/6uIjmFCNzAoc63UW5j7d25JnzDah10viWnDi99BY03UUIxRcQWcR+w==", "dependencies": { - "@faker-js/faker": "^8.3.1", + "@faker-js/faker": "^8.4.1", "consola": "^3.2.3", - "locter": "^2.0.2", + "envix": "^1.5.0", + "locter": "^2.1.0", "pascal-case": "^3.1.2", "rapiq": "^0.9.0", - "reflect-metadata": "^0.2.1", - "smob": "^1.4.1", + "reflect-metadata": "^0.2.2", + "smob": "^1.5.0", "yargs": "^17.7.2" }, "bin": { @@ -15191,9 +15374,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -15230,8 +15413,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "devOptional": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unique-string": { "version": "3.0.0", @@ -15318,9 +15500,13 @@ } }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -15329,7 +15515,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "devOptional": true + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.2.0", @@ -15393,9 +15579,9 @@ } }, "node_modules/watchpack": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz", + "integrity": "sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==", "dev": true, "dependencies": { "glob-to-regexp": "^0.4.1", @@ -15420,19 +15606,19 @@ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "version": "5.90.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.1.tgz", + "integrity": "sha512-SstPdlAC5IvgFnhiRok8hqJo/+ArAbNv7rhU4fnWGHNVfN59HSQFaxZDSAL3IFG2YmqxuRs+IU33milSxbPlog==", "dev": true, "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.11.5", "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -15446,7 +15632,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, @@ -15577,30 +15763,33 @@ "dev": true }, "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -15743,9 +15932,12 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } @@ -15779,7 +15971,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "devOptional": true, + "dev": true, "engines": { "node": ">=6" } diff --git a/package.json b/package.json index 731bb763..44d7fe8a 100644 --- a/package.json +++ b/package.json @@ -28,20 +28,20 @@ ] }, "dependencies": { - "@nestjs/axios": "^3.0.1", - "@nestjs/common": "^10.3.1", - "@nestjs/config": "^3.1.1", - "@nestjs/core": "^10.3.1", + "@nestjs/axios": "^3.0.2", + "@nestjs/common": "^10.3.7", + "@nestjs/config": "^3.2.2", + "@nestjs/core": "^10.3.7", "@nestjs/passport": "^10.0.3", - "@nestjs/platform-express": "^10.3.1", - "@nestjs/swagger": "^7.2.0", - "@nestjs/terminus": "^10.2.1", - "@nestjs/typeorm": "^10.0.1", - "axios": "^1.6.7", + "@nestjs/platform-express": "^10.3.7", + "@nestjs/swagger": "^7.3.1", + "@nestjs/terminus": "^10.2.3", + "@nestjs/typeorm": "^10.0.2", + "axios": "^1.6.8", "class-transformer": "^0.5.1", "class-validator": "^0.14.1", "compression": "^1.7.4", - "date-fns": "^3.3.1", + "date-fns": "^3.6.0", "dotenv": "^16.4.1", "express-basic-auth": "^1.2.1", "lodash": "^4.17.21", @@ -51,33 +51,33 @@ "passport-headerapikey": "^1.2.2", "pino-http": "^9.0.0", "pino-pretty": "^10.3.1", - "reflect-metadata": "^0.2.1", + "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "tsconfig-paths": "^4.2.0", "tslib": "^2.6.2", "typeorm": "^0.3.20", - "typeorm-extension": "^3.4.0", - "typescript": "^5.3.3" + "typeorm-extension": "^3.5.1", + "typescript": "^5.4.5" }, "devDependencies": { - "@commitlint/cli": "^18.6.0", - "@commitlint/config-conventional": "^18.6.0", - "@nestjs/cli": "^10.3.0", - "@nestjs/schematics": "^10.1.0", - "@nestjs/testing": "^10.3.1", - "@tsconfig/node21": "^21.0.1", + "@commitlint/cli": "^18.6.1", + "@commitlint/config-conventional": "^18.6.3", + "@nestjs/cli": "^10.3.2", + "@nestjs/schematics": "^10.1.1", + "@nestjs/testing": "^10.3.7", + "@tsconfig/node21": "^21.0.3", "@types/chance": "^1.1.6", "@types/compression": "^1.7.5", "@types/express": "^4.17.21", - "@types/jest": "^29.5.11", - "@types/lodash": "^4.14.202", - "@types/node": "^20.11.10", + "@types/jest": "^29.5.12", + "@types/lodash": "^4.17.0", + "@types/node": "^20.12.7", "@types/supertest": "^6.0.2", - "@typescript-eslint/eslint-plugin": "^6.19.1", - "@typescript-eslint/parser": "^6.19.1", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", "chance": "^1.1.11", - "cspell": "^8.3.2", - "eslint": "^8.56.0", + "cspell": "^8.7.0", + "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-airbnb-typescript-prettier": "^5.0.0", @@ -86,22 +86,22 @@ "eslint-plugin-deprecation": "^2.0.0", "eslint-plugin-eslint-comments": "^3.2.0", "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jest": "^27.6.3", + "eslint-plugin-jest": "^27.9.0", "eslint-plugin-jest-formatting": "^3.1.0", "eslint-plugin-node": "^11.1.0", "eslint-plugin-optimize-regex": "^1.2.1", "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-security": "^2.1.0", + "eslint-plugin-security": "^2.1.1", "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-switch-case": "^1.1.2", - "eslint-plugin-unused-imports": "^3.0.0", - "husky": "^9.0.6", + "eslint-plugin-unused-imports": "^3.1.0", + "husky": "^9.0.11", "jest": "29.7.0", "jest-when": "^3.6.0", - "lint-staged": "^15.2.0", - "nock": "^13.5.1", - "prettier": "^3.2.4", - "sort-package-json": "^2.6.0", + "lint-staged": "^15.2.2", + "nock": "^13.5.4", + "prettier": "^3.2.5", + "sort-package-json": "^2.10.0", "source-map-support": "^0.5.21", "supertest": "^6.3.4", "ts-jest": "29.1.2", From c8cb1bc98c72f3258f8bc9d498effdfe561ff45b Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 11 Apr 2024 13:53:36 +0100 Subject: [PATCH 11/56] feat(DTFS2-7052): api-tests for geospatial/get-address-by-postcode --- ...ordnance-survey-auth-error-response.dto.ts | 8 + .../ordnance-survey.service.ts | 1 - src/modules/geospatial/geospatial.service.ts | 4 + .../get-docs-yaml.api-test.ts.snap | 146 +++++++-- .../get-address-by-postcode.api-test.ts | 303 ++++++++---------- test/support/api.ts | 2 +- test/support/environment-variables.ts | 9 + .../get-geospatial-addresses-generator.ts | 98 +++++- .../generator/random-value-generator.ts | 5 + 9 files changed, 359 insertions(+), 217 deletions(-) create mode 100644 src/helper-modules/ordnance-survey/dto/ordnance-survey-auth-error-response.dto.ts diff --git a/src/helper-modules/ordnance-survey/dto/ordnance-survey-auth-error-response.dto.ts b/src/helper-modules/ordnance-survey/dto/ordnance-survey-auth-error-response.dto.ts new file mode 100644 index 00000000..36c25260 --- /dev/null +++ b/src/helper-modules/ordnance-survey/dto/ordnance-survey-auth-error-response.dto.ts @@ -0,0 +1,8 @@ +export type OrdnanceSurveyAuthErrorResponse = { + fault: { + faultstring: string; + detail: { + errorcode: string; + }; + }; +}; diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts index 4dbd137c..a079baab 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -22,7 +22,6 @@ export class OrdnanceSurveyService { async getAddressesByPostcode(postcode): Promise { const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(this.key)}`; - const { data } = await this.httpClient.get({ path, headers: { 'Content-Type': 'application/json' }, diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index 0c1b999e..e1cf93df 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -13,6 +13,10 @@ export class GeospatialService { const addresses = []; const response: GetAddressOrdnanceSurveyResponse = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); + if (!response?.results) { + return []; + } + response.results.forEach((item) => { // Ordnance survey sends duplicated results with the welsh version too via 'CY' const item_data = item[Object.keys(item)[0]]; diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index df16b21b..77af87e5 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -17,7 +17,7 @@ paths: type: array items: $ref: '#/components/schemas/CurrencyEntity' - tags: &ref_0 + tags: - currencies /api/v1/currencies/exchange: get: @@ -58,7 +58,8 @@ paths: application/json: schema: $ref: '#/components/schemas/GetCurrencyExchangeDto' - tags: *ref_0 + tags: + - currencies /api/v1/currencies/{isoCode}: get: operationId: CurrenciesController_findOne @@ -80,7 +81,8 @@ paths: type: array items: $ref: '#/components/schemas/CurrencyEntity' - tags: *ref_0 + tags: + - currencies /api/v1/customers: get: operationId: CustomersController_getCustomers @@ -194,38 +196,43 @@ paths: example: ok info: type: object - example: &ref_1 - database: &ref_2 + example: + database: status: up additionalProperties: type: object + required: + - status properties: status: type: string - additionalProperties: - type: string + additionalProperties: true nullable: true error: type: object example: {} additionalProperties: type: object + required: + - status properties: status: type: string - additionalProperties: - type: string + additionalProperties: true nullable: true details: type: object - example: *ref_1 + example: + database: + status: up additionalProperties: type: object + required: + - status properties: status: type: string - additionalProperties: - type: string + additionalProperties: true '503': description: The Health Check is not successful content: @@ -238,41 +245,49 @@ paths: example: error info: type: object - example: *ref_1 + example: + database: + status: up additionalProperties: type: object + required: + - status properties: status: type: string - additionalProperties: - type: string + additionalProperties: true nullable: true error: type: object example: - redis: &ref_3 + redis: status: down message: Could not connect additionalProperties: type: object + required: + - status properties: status: type: string - additionalProperties: - type: string + additionalProperties: true nullable: true details: type: object example: - database: *ref_2 - redis: *ref_3 + database: + status: up + redis: + status: down + message: Could not connect additionalProperties: type: object + required: + - status properties: status: type: string - additionalProperties: - type: string + additionalProperties: true tags: - healthcheck /api/v1/interest-rates: @@ -342,7 +357,7 @@ paths: responses: '201': description: '' - tags: &ref_4 + tags: - numbers get: operationId: NumbersController_findOne @@ -373,7 +388,8 @@ paths: type: array items: $ref: '#/components/schemas/UkefId' - tags: *ref_4 + tags: + - numbers /api/v1/premium/schedule: post: operationId: PremiumSchedulesController_create @@ -390,7 +406,7 @@ paths: responses: '201': description: '' - tags: &ref_5 + tags: - premium-schedules /api/v1/premium/segments/{facilityId}: get: @@ -415,7 +431,8 @@ paths: type: array items: $ref: '#/components/schemas/PremiumScheduleEntity' - tags: *ref_5 + tags: + - premium-schedules /api/v1/sector-industries: get: operationId: SectorIndustriesController_find @@ -469,6 +486,35 @@ paths: $ref: '#/components/schemas/YieldRateEntity' tags: - yield-rates + /api/v1/geospatial/addresses/postcode: + get: + operationId: GeospatialController_getGeospatial + summary: >- + A search based on a property's postcode. Will accept a full postcode + consisting of the area, district, sector and unit e.g. SO16 0AS. + parameters: + - name: postcode + required: true + in: query + example: SW1A 2AQ + description: Postcode to search for + schema: + type: string + responses: + '200': + description: >- + Returns addresses from Ordanance survey Delivery Point Address (DPA) + system. + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/GetAddressesResponseItem' + '404': + description: Customer not found. + tags: + - geospatial info: title: MDM API Specification description: MDM API documentation @@ -850,8 +896,8 @@ components: type: number example: 1 description: >- - Payment frequency. It can be: 0 -> Null (At maturity), 1 -> Monthly, 2 -> Quarterly, 3-> - Semi-annually or 4 -> Annually + Payment frequency. It can be: 0 -> Null (At maturity), 1 -> Monthly, + 2 -> Quarterly, 3-> Semi-annually or 4 -> Annually guaranteeCommencementDate: format: date-time type: string @@ -1087,6 +1133,50 @@ components: - updated - effectiveTo - effectiveFrom + GetAddressesResponseItem: + type: object + properties: + organisationName: + type: string + description: Organisation name if available + example: CHURCHILL MUSEUM & CABINET WAR ROOMS + addressLine1: + type: string + description: Address line 1 + example: CLIVE STEPS KING CHARLES STREET + addressLine2: + type: string + description: Address line 2 + example: null + addressLine3: + type: string + description: Address line 3 + example: null + locality: + type: string + description: Locality, Town + example: LONDON + postalCode: + type: string + description: Postcode + example: SW1A 2AQ + country: + type: string + description: Country of address record + example: England + enum: + - England + - Scotland + - Wales + - Northern Ireland + required: + - organisationName + - addressLine1 + - addressLine2 + - addressLine3 + - locality + - postalCode + - country security: - ApiKeyHeader: [] " diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts index a1522d29..770ef319 100644 --- a/test/geospatial/get-address-by-postcode.api-test.ts +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -1,8 +1,7 @@ -// import { CUSTOMERS, ENUMS } from '@ukef/constants'; -// import { IncorrectAuthArg, withClientAuthenticationTests } from '@ukef-test/common-tests/client-authentication-api-tests'; +import { GEOSPATIAL } from '@ukef/constants'; +import { IncorrectAuthArg, withClientAuthenticationTests } from '@ukef-test/common-tests/client-authentication-api-tests'; import { Api } from '@ukef-test/support/api'; -// import { ENVIRONMENT_VARIABLES, TIME_EXCEEDING_INFORMATICA_TIMEOUT } from '@ukef-test/support/environment-variables'; -import { ENVIRONMENT_VARIABLES } from '@ukef-test/support/environment-variables'; +import { ENVIRONMENT_VARIABLES, TIME_EXCEEDING_ORDNANCE_SURVEY_TIMEOUT } from '@ukef-test/support/environment-variables'; import { GetGeospatialAddressesGenerator } from '@ukef-test/support/generator/get-geospatial-addresses-generator'; import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; import nock from 'nock'; @@ -12,13 +11,21 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { let api: Api; - const { ordnanceSurveyPath, mdmPath, getAddressesByPostcodeResponse, getAddressOrdnanceSurveyResponse } = new GetGeospatialAddressesGenerator( - valueGenerator, - ).generate({ + const { + ordnanceSurveyPath, + mdmPath, + getAddressByPostcodeResponse, + getAddressOrdnanceSurveyResponse, + getAddressOrdnanceSurveyEmptyResponse, + getAddressessOrdnanceSurveyResponse, + ordnanceSurveyAuthErrorResponse, + } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ + postcode: GEOSPATIAL.EXAMPLES.POSTCODE, + key: ENVIRONMENT_VARIABLES.ORDNANCE_SURVEY_KEY, numberToGenerate: 2, }); - // const getMdmUrl = (postcode: string) => `/api/v1/geospatial/addresses/postcode?postcode=${encodeURIComponent(postcode)}`; + const getMdmUrl = (postcode: string) => `/api/v1/geospatial/addresses/postcode?postcode=${encodeURIComponent(postcode)}`; beforeAll(async () => { api = await Api.create(); @@ -33,181 +40,121 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { nock.cleanAll(); }); - // withClientAuthenticationTests({ - // givenTheRequestWouldOtherwiseSucceed: () => { - // requestToGetCustomers(mdmPath[0]).reply(200, getAddressesByPostcodeResponse[0]); - // }, - // makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPath[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), - // }); + // MDM auth tests + withClientAuthenticationTests({ + givenTheRequestWouldOtherwiseSucceed: () => { + requestToGetAddressesByPostcode(mdmPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + }, + makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPath[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), + }); + + it('returns a 200 response with the address if it is returned by Ordnance Survey API', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + + const { status, body } = await api.get(mdmPath[0]); + + expect(status).toBe(200); + expect(body).toStrictEqual(getAddressByPostcodeResponse[0]); + }); + + it('returns a 200 response with the addresses if they are returned by Ordnance Survey API', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressessOrdnanceSurveyResponse); + + const { status, body } = await api.get(mdmPath[0]); - it.only('returns a 200 response with the customers if they are returned by Informatica', async () => { - requestToGetCustomers(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + expect(status).toBe(200); + expect(body).toStrictEqual([getAddressByPostcodeResponse[0][0], getAddressByPostcodeResponse[1][0]]); + }); + + it('returns a empty 200 response if Ordnance Survey API returns a 200 without results', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyEmptyResponse[0]); const { status, body } = await api.get(mdmPath[0]); expect(status).toBe(200); - expect(body).toStrictEqual(getAddressesByPostcodeResponse[0]); + expect(body).toStrictEqual([]); + }); + + it('returns a 500 response if Ordnance Survey API returns a status code 401', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(401); + + const { status, body } = await api.get(mdmPath[0]); + + expect(status).toBe(500); + expect(body).toStrictEqual({ + statusCode: 500, + message: 'Internal server error', + }); + }); + + it('returns a 500 response if Ordnance Survey API returns a status code 404', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(404); + + const { status, body } = await api.get(mdmPath[0]); + + expect(status).toBe(500); + expect(body).toStrictEqual({ + statusCode: 500, + message: 'Internal server error', + }); + }); + + it('returns a 500 response if Ordnance Survey API times out', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).delay(TIME_EXCEEDING_ORDNANCE_SURVEY_TIMEOUT).reply(200, getAddressOrdnanceSurveyResponse[0]); + + const { status, body } = await api.get(mdmPath[0]); + + expect(status).toBe(500); + expect(body).toStrictEqual({ + statusCode: 500, + message: 'Internal server error', + }); + }); + + it('returns a 500 response if Ordnance Survey API returns error', async () => { + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(401, ordnanceSurveyAuthErrorResponse); + + const { status, body } = await api.get(mdmPath[0]); + + expect(status).toBe(500); + expect(body).toStrictEqual({ + statusCode: 500, + message: 'Internal server error', + }); + }); + + it.each([ + { + postcode: valueGenerator.string({ length: 4 }), + expectedError: 'postcode must be longer than or equal to 5 characters', + }, + { + postcode: valueGenerator.string({ length: 9 }), + expectedError: 'postcode must be shorter than or equal to 8 characters', + }, + { + postcode: valueGenerator.stringOfNumericCharacters({ length: 5 }), + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + { + postcode: 'AA1 1CL', + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + { + postcode: 'SW1 2AQ', + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + ])('returns a 400 response with error array if postcode is "$postcode"', async ({ postcode, expectedError }) => { + const { status, body } = await api.get(getMdmUrl(postcode)); + + expect(status).toBe(400); + expect(body).toMatchObject({ + error: 'Bad Request', + message: expect.arrayContaining([expectedError]), + statusCode: 400, + }); }); - // it.each([ - // { - // query: { name: CUSTOMERS.EXAMPLES.NAME, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.YES }, - // }, - // { - // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.YES }, - // }, - // { - // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.YES }, - // }, - // { - // query: { name: CUSTOMERS.EXAMPLES.NAME, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.NO }, - // }, - // { - // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.NO }, - // }, - // { - // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.NO }, - // }, - // { - // query: { name: CUSTOMERS.EXAMPLES.NAME, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.LEGACY_ONLY }, - // }, - // { - // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.LEGACY_ONLY }, - // }, - // { - // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN, fallbackToLegacyData: ENUMS.FALLBACK_TO_LEGACY_DATA.LEGACY_ONLY }, - // }, - // { - // query: { name: CUSTOMERS.EXAMPLES.NAME }, - // }, - // { - // query: { companyReg: CUSTOMERS.EXAMPLES.COMPANYREG }, - // }, - // { - // query: { partyUrn: CUSTOMERS.EXAMPLES.PARTYURN }, - // }, - // ])('returns a 200 response with the customers if query is "$query"', async ({ query }) => { - // const { mdmPath, informaticaPath, getCustomersResponse } = new GetCustomersGenerator(valueGenerator).generate({ - // numberToGenerate: 1, - // query, - // }); - // requestToGetCustomers(informaticaPath).reply(200, getCustomersResponse[0]); - - // const { status, body } = await api.get(mdmPath); - - // expect(status).toBe(200); - // expect(body).toStrictEqual(getCustomersResponse[0]); - // }); - - // it('returns a 404 response if Informatica returns a 404 response with the string "null"', async () => { - // requestToGetCustomers(informaticaPath).reply(404, [ - // { - // errorCode: '404', - // errorDateTime: '2023-06-30T13:41:33Z', - // errorMessage: 'Company registration not found', - // errorDescription: 'Party details request for the requested company registration not found.', - // }, - // ]); - - // const { status, body } = await api.get(mdmPath); - - // expect(status).toBe(404); - // expect(body).toStrictEqual({ - // statusCode: 404, - // message: 'Customer not found.', - // }); - // }); - - // it('returns a 500 response if Informatica returns a status code that is NOT 200', async () => { - // requestToGetCustomers(informaticaPath).reply(401); - - // const { status, body } = await api.get(mdmPath); - - // expect(status).toBe(500); - // expect(body).toStrictEqual({ - // statusCode: 500, - // message: 'Internal server error', - // }); - // }); - - // it('returns a 500 response if getting the facility investors from ACBS times out', async () => { - // requestToGetCustomers(informaticaPath).delay(TIME_EXCEEDING_INFORMATICA_TIMEOUT).reply(200, getCustomersResponse[0]); - - // const { status, body } = await api.get(mdmPath); - - // expect(status).toBe(500); - // expect(body).toStrictEqual({ - // statusCode: 500, - // message: 'Internal server error', - // }); - // }); - - // it.each([ - // { - // query: { name: valueGenerator.string({ length: 1 }) }, - // expectedError: 'name must be longer than or equal to 2 characters', - // }, - // { - // query: { name: valueGenerator.string({ length: 256 }) }, - // expectedError: 'name must be shorter than or equal to 255 characters', - // }, - // { - // query: { name: valueGenerator.word(), extraParameter: valueGenerator.word() }, - // expectedError: 'property extraParameter should not exist', - // }, - // { - // query: { companyReg: valueGenerator.string({ length: 7 }) }, - // expectedError: 'companyReg must be longer than or equal to 8 characters', - // }, - // { - // query: { companyReg: valueGenerator.string({ length: 11 }) }, - // expectedError: 'companyReg must be shorter than or equal to 10 characters', - // }, - // { - // query: { partyUrn: valueGenerator.stringOfNumericCharacters({ length: 7 }) }, - // expectedError: 'partyUrn must match /^\\d{8}$/ regular expression', - // }, - // { - // query: { partyUrn: valueGenerator.stringOfNumericCharacters({ length: 9 }) }, - // expectedError: 'partyUrn must match /^\\d{8}$/ regular expression', - // }, - // { - // query: { partyUrn: valueGenerator.word() }, - // expectedError: 'partyUrn must match /^\\d{8}$/ regular expression', - // }, - // ])('returns a 400 response with error array if query is "$query"', async ({ query, expectedError }) => { - // const { status, body } = await api.get(getMdmUrl(query)); - - // expect(status).toBe(400); - // expect(body).toMatchObject({ - // error: 'Bad Request', - // message: expect.arrayContaining([expectedError]), - // statusCode: 400, - // }); - // }); - - // it.each([ - // { - // query: {}, - // expectedError: 'One and just one search parameter is required', - // }, - // { - // query: { name: valueGenerator.word(), companyReg: valueGenerator.string({ length: 8 }) }, - // expectedError: 'One and just one search parameter is required', - // }, - // ])('returns a 400 response with error string if query is "$query"', async ({ query, expectedError }) => { - // const { status, body } = await api.get(getMdmUrl(query)); - - // expect(status).toBe(400); - // expect(body).toMatchObject({ - // error: 'Bad Request', - // message: expectedError, - // statusCode: 400, - // }); - // }); - - const basicAuth = Buffer.from(`${ENVIRONMENT_VARIABLES.APIM_INFORMATICA_USERNAME}:${ENVIRONMENT_VARIABLES.APIM_INFORMATICA_PASSWORD}`).toString('base64'); - - const requestToGetCustomers = (informaticaPath: string): nock.Interceptor => - nock(ENVIRONMENT_VARIABLES.APIM_INFORMATICA_URL).get(informaticaPath).matchHeader('authorization', `Basic ${basicAuth}`); + const requestToGetAddressesByPostcode = (ordnanceSurveyPath: string): nock.Interceptor => + nock(ENVIRONMENT_VARIABLES.ORDNANCE_SURVEY_URL).get(ordnanceSurveyPath); }); diff --git a/test/support/api.ts b/test/support/api.ts index 48e84d9b..dc03f634 100644 --- a/test/support/api.ts +++ b/test/support/api.ts @@ -29,7 +29,7 @@ export class Api { return this.app.destroy(); } - private request(): request.SuperTest { + private request(): any { return request(this.app.getHttpServer()); } diff --git a/test/support/environment-variables.ts b/test/support/environment-variables.ts index 1c9a8d29..5f57fa07 100644 --- a/test/support/environment-variables.ts +++ b/test/support/environment-variables.ts @@ -17,6 +17,12 @@ export const ENVIRONMENT_VARIABLES = Object.freeze({ APIM_INFORMATICA_MAX_REDIRECTS: 0, APIM_INFORMATICA_TIMEOUT: 1000, + ORDNANCE_SURVEY_URL: valueGenerator.httpsUrl(), + ORDNANCE_SURVEY_KEY: valueGenerator.word(), + + ORDNANCE_SURVEY_MAX_REDIRECTS: 0, + ORDNANCE_SURVEY_TIMEOUT: 5000, + API_KEY: valueGenerator.string(), }); @@ -26,6 +32,9 @@ export const getEnvironmentVariablesForProcessEnv = (): NodeJS.ProcessEnv => ({ SINGLE_LINE_LOG_FORMAT: ENVIRONMENT_VARIABLES.SINGLE_LINE_LOG_FORMAT.toString(), APIM_INFORMATICA_MAX_REDIRECTS: ENVIRONMENT_VARIABLES.APIM_INFORMATICA_MAX_REDIRECTS.toString(), APIM_INFORMATICA_TIMEOUT: ENVIRONMENT_VARIABLES.APIM_INFORMATICA_TIMEOUT.toString(), + ORDNANCE_SURVEY_MAX_REDIRECTS: ENVIRONMENT_VARIABLES.ORDNANCE_SURVEY_MAX_REDIRECTS.toString(), + ORDNANCE_SURVEY_TIMEOUT: ENVIRONMENT_VARIABLES.ORDNANCE_SURVEY_TIMEOUT.toString(), }); export const TIME_EXCEEDING_INFORMATICA_TIMEOUT = ENVIRONMENT_VARIABLES.APIM_INFORMATICA_TIMEOUT + 500; +export const TIME_EXCEEDING_ORDNANCE_SURVEY_TIMEOUT = ENVIRONMENT_VARIABLES.ORDNANCE_SURVEY_TIMEOUT + 500; diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index e24fab8a..efabd55c 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -1,5 +1,6 @@ import { ENUMS, GEOSPATIAL } from '@ukef/constants'; import { GetAddressOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; +import { OrdnanceSurveyAuthErrorResponse } from '@ukef/helper-modules/ordnance-survey/dto/ordnance-survey-auth-error-response.dto'; import { GetAddressByPostcodeQueryDto } from '@ukef/modules/geospatial/dto/get-address-by-postcode-query.dto'; import { GetAddressesResponse } from '@ukef/modules/geospatial/dto/get-addresses-response.dto'; @@ -20,17 +21,12 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator ({ postcode: postcode || v.POSTCODE }) as GetAddressByPostcodeQueryDto); @@ -44,7 +40,7 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator [ + const getAddressByPostcodeResponse: GetAddressesResponse[] = values.map((v) => [ { organisationName: v.ORGANISATION_NAME, addressLine1: `${v.BUILDING_NAME} ${v.BUILDING_NUMBER} ${v.THOROUGHFARE_NAME}`, @@ -111,13 +107,94 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator ({ + DPA: { + UPRN: 'test', + UDPRN: 'test', + ADDRESS: 'test', + BUILDING_NAME: v.BUILDING_NAME, + BUILDING_NUMBER: v.BUILDING_NUMBER, + ORGANISATION_NAME: v.ORGANISATION_NAME, + DEPENDENT_LOCALITY: v.DEPENDENT_LOCALITY, + THOROUGHFARE_NAME: v.THOROUGHFARE_NAME, + POST_TOWN: v.POST_TOWN, + POSTCODE: v.POSTCODE, + RPC: 'test', + X_COORDINATE: 12345, + Y_COORDINATE: 12345, + STATUS: 'test', + LOGICAL_STATUS_CODE: 'test', + CLASSIFICATION_CODE: 'test', + CLASSIFICATION_CODE_DESCRIPTION: 'test', + LOCAL_CUSTODIAN_CODE: 12345, + LOCAL_CUSTODIAN_CODE_DESCRIPTION: 'test', + COUNTRY_CODE: v.COUNTRY_CODE, + COUNTRY_CODE_DESCRIPTION: 'test', + POSTAL_ADDRESS_CODE: 'test', + POSTAL_ADDRESS_CODE_DESCRIPTION: 'test', + BLPU_STATE_CODE: 'test', + BLPU_STATE_CODE_DESCRIPTION: 'test', + TOPOGRAPHY_LAYER_TOID: 'test', + LAST_UPDATE_DATE: 'test', + ENTRY_DATE: 'test', + BLPU_STATE_DATE: 'test', + LANGUAGE: 'test', + MATCH: 12345, + MATCH_DESCRIPTION: 'test', + DELIVERY_POINT_SUFFIX: 'test', + }, + })), + }; + + const getAddressOrdnanceSurveyEmptyResponse: GetAddressOrdnanceSurveyResponse[] = values.map(() => ({ + header: { + uri: 'test', + query: 'test', + offset: 0, + totalresults: 0, + format: 'test', + dataset: 'test', + lr: 'test', + maxresults: 100, + epoch: 'test', + lastupdate: 'test', + output_srs: 'test', + }, + })); + + const ordnanceSurveyAuthErrorResponse = { + fault: { + faultstring: 'Invalid ApiKey', + detail: { + errorcode: 'oauth.v2.InvalidApiKey', + }, + }, + }; + return { request, // ordnanceSurveyRequest, ordnanceSurveyPath, mdmPath, - getAddressesByPostcodeResponse, + getAddressByPostcodeResponse, getAddressOrdnanceSurveyResponse, + getAddressOrdnanceSurveyEmptyResponse, + getAddressessOrdnanceSurveyResponse, + ordnanceSurveyAuthErrorResponse, }; } } @@ -143,6 +220,9 @@ interface GenerateResult { //ordnanceSurveyRequest: GetCustomersInformaticaQueryDto[]; ordnanceSurveyPath: string[]; mdmPath: string[]; - getAddressesByPostcodeResponse: GetAddressesResponse[]; + getAddressByPostcodeResponse: GetAddressesResponse[]; getAddressOrdnanceSurveyResponse: GetAddressOrdnanceSurveyResponse[]; + getAddressessOrdnanceSurveyResponse: GetAddressOrdnanceSurveyResponse; + getAddressOrdnanceSurveyEmptyResponse: GetAddressOrdnanceSurveyResponse[]; + ordnanceSurveyAuthErrorResponse: OrdnanceSurveyAuthErrorResponse; } diff --git a/test/support/generator/random-value-generator.ts b/test/support/generator/random-value-generator.ts index 612f9d59..929fce0e 100644 --- a/test/support/generator/random-value-generator.ts +++ b/test/support/generator/random-value-generator.ts @@ -75,4 +75,9 @@ export class RandomValueGenerator { const possibleValues = Object.values(theEnum); return possibleValues[this.integer({ min: 0, max: possibleValues.length - 1 })] as T; } + + enumKey(theEnum: Enum): T { + const possibleValues = Object.keys(theEnum); + return possibleValues[this.integer({ min: 0, max: possibleValues.length - 1 })] as T; + } } From c91144daa23e806764e5cd80382d1726d4380339 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 11 Apr 2024 15:21:50 +0100 Subject: [PATCH 12/56] feat(DTFS2-7052): refactor api tests to match TFS and solve type issues --- test/api.ts | 44 --------------- test/app.api-test.ts | 19 +++---- test/createApp.ts | 30 ---------- test/currencies/currencies.api-test.ts | 43 +++++++------- .../exposure-period.api-test.ts | 49 ++++++++-------- .../interest-rates/interest-rates.api-test.ts | 19 +++---- test/markets/markets.api-test.ts | 56 +++++++++---------- test/numbers/numbers.api-test.ts | 55 +++++++++--------- .../premium-schedules.api-test.ts | 47 +++++++--------- .../sector-industries.api-test.ts | 33 +++++------ test/support/api.ts | 4 ++ test/yield-rates/yield-rates.api-test.ts | 47 +++++++--------- 12 files changed, 166 insertions(+), 280 deletions(-) delete mode 100644 test/api.ts delete mode 100644 test/createApp.ts diff --git a/test/api.ts b/test/api.ts deleted file mode 100644 index 68d549d9..00000000 --- a/test/api.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { INestApplication } from '@nestjs/common'; -import request from 'supertest'; - -export class Api { - app: INestApplication; - - public constructor(app: INestApplication) { - this.app = app; - } - - get(url: string) { - return request(this.app).get(url); - } - - post(data: string | object) { - return { to: (url: string) => request(this.app).post(url).send(data) }; - } - - postEach(list: any) { - return { - to: async (url: string) => { - const results = []; - - for (const data of list) { - const result = await request(this.app).post(url).send(data); - - results.push(result); - } - - return results; - }, - }; - } - - put(data: string | object) { - return { to: (url: string) => request(this.app).put(url).send(data) }; - } - - remove(data: string | object) { - return { - to: (url: string) => request(this.app).delete(url).send(data), - }; - } -} diff --git a/test/app.api-test.ts b/test/app.api-test.ts index 6acfd80b..0853661c 100644 --- a/test/app.api-test.ts +++ b/test/app.api-test.ts @@ -1,24 +1,19 @@ -import { INestApplication } from '@nestjs/common'; - -import { Api } from './api'; -import { CreateApp } from './createApp'; +import { Api } from '@ukef-test/support/api'; describe('AppController (e2e)', () => { - let app: INestApplication; let api; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it(`GET /ready`, async () => { - const { status } = await api.get('/ready'); + const { status } = await api.get('/api/v1/ready'); expect(status).toBe(200); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/createApp.ts b/test/createApp.ts deleted file mode 100644 index aee3bcee..00000000 --- a/test/createApp.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { ValidationPipe } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; - -import { MainModule } from '../src/main.module'; - -export class CreateApp { - // NestJs app initialisation happens in /src/main.ts, here is some duplication of same process. - // TODO: maybe it is possible to reuse initialisation in /src/main.ts as similar approach is done in DTFS projects. - async init() { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [MainModule], - }).compile(); - - const app = moduleFixture.createNestApplication(); - - // Validation pipeline is require to check validations. - app.useGlobalPipes( - new ValidationPipe({ - whitelist: true, - transform: true, - forbidNonWhitelisted: true, - transformOptions: { - enableImplicitConversion: true, - }, - }), - ); - await app.init(); - return app; - } -} diff --git a/test/currencies/currencies.api-test.ts b/test/currencies/currencies.api-test.ts index 595d9d51..3e6fdf9e 100644 --- a/test/currencies/currencies.api-test.ts +++ b/test/currencies/currencies.api-test.ts @@ -1,10 +1,6 @@ -import { INestApplication } from '@nestjs/common'; - -import { Api } from '../api'; -import { CreateApp } from '../createApp'; +import { Api } from '@ukef-test/support/api'; describe('Currencies', () => { - let app: INestApplication; let api: Api; const expectedResult = expect.arrayContaining([ @@ -25,31 +21,34 @@ describe('Currencies', () => { ]); beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); describe('/currencies/exchange', () => { it('should return 200 on GET `/currencies/exchange?source=GBP&target=AED&exchangeRateDate=2021-01-26`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=GBP&target=AED&exchangeRateDate=2021-01-26'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=GBP&target=AED&exchangeRateDate=2021-01-26'); expect(status).toBe(200); expect(body).toEqual(expectedResult); }); it('should return 200 on GET `/currencies/exchange?source=GBP&target=AED`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=GBP&target=AED'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=GBP&target=AED'); expect(status).toBe(200); expect(body).toEqual(expectedResult); }); it('should return 200 on GET `currencies/exchange?source=USD&target=GBP`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=USD&target=GBP'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=USD&target=GBP'); expect(status).toBe(200); expect(body).toEqual(expectedResult); }); it('should return 404 on GET `/currencies/exchange?source=AED&target=GBP`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=AED&target=GBP'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=AED&target=GBP'); expect(status).toBe(404); expect(body).toEqual({ statusCode: 404, @@ -59,7 +58,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/exchange?source=GBP&target=abc`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=GBP&target=abc'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=GBP&target=abc'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -69,7 +68,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/exchange?source=abc&target=AED`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=abc&target=AED'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=abc&target=AED'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -79,7 +78,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/exchange?source=abc&target=def`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=abc&target=def'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=abc&target=def'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -89,7 +88,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/exchange`', async () => { - const { status, body } = await api.get('/currencies/exchange'); + const { status, body } = await api.get('/api/v1/currencies/exchange'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -99,7 +98,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/exchange?source=GBP`', async () => { - const { status, body } = await api.get('/currencies/exchange?source=GBP'); + const { status, body } = await api.get('/api/v1/currencies/exchange?source=GBP'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -109,7 +108,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/exchange?target=GBP`', async () => { - const { status, body } = await api.get('/currencies/exchange?target=GBP'); + const { status, body } = await api.get('/api/v1/currencies/exchange?target=GBP'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -121,7 +120,7 @@ describe('Currencies', () => { describe('/currencies', () => { it('should return 200 on GET `/currencies`', async () => { - const { status, body } = await api.get('/currencies'); + const { status, body } = await api.get('/api/v1/currencies'); expect(status).toBe(200); expect(body).toEqual( expect.arrayContaining([ @@ -142,7 +141,7 @@ describe('Currencies', () => { describe('/currencies/{isoCode}', () => { it('should return 200 on GET `/currencies/GBP`', async () => { - const { status, body } = await api.get('/currencies/GBP'); + const { status, body } = await api.get('/api/v1/currencies/GBP'); expect(status).toBe(200); expect(body).toEqual( expect.arrayContaining([ @@ -161,7 +160,7 @@ describe('Currencies', () => { }); it('should return 400 on GET `/currencies/abc`', async () => { - const { status, body } = await api.get('/currencies/abc'); + const { status, body } = await api.get('/api/v1/currencies/abc'); expect(status).toBe(400); expect(body).toEqual({ statusCode: 400, @@ -170,8 +169,4 @@ describe('Currencies', () => { }); }); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/exposure-period/exposure-period.api-test.ts b/test/exposure-period/exposure-period.api-test.ts index 80095e8e..0781ea76 100644 --- a/test/exposure-period/exposure-period.api-test.ts +++ b/test/exposure-period/exposure-period.api-test.ts @@ -1,38 +1,37 @@ -import { INestApplication } from '@nestjs/common'; import { PRODUCTS } from '@ukef/constants'; - -import { Api } from '../api'; -import { CreateApp } from '../createApp'; +import { Api } from '@ukef-test/support/api'; describe('Exposure period', () => { - let app: INestApplication; let api: Api; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it(`GET /exposure-period?startdate=2017-07-04&enddate=2018-07-04&productgroup=${PRODUCTS.EW}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-07-04&enddate=2018-07-04&productgroup=${PRODUCTS.EW}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-07-04&enddate=2018-07-04&productgroup=${PRODUCTS.EW}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(12); }); it(`GET /exposure-period?startdate=2017-07-04&enddate=2018-07-05&productgroup=${PRODUCTS.EW}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-07-04&enddate=2018-07-05&productgroup=${PRODUCTS.EW}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-07-04&enddate=2018-07-05&productgroup=${PRODUCTS.EW}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(13); }); it(`GET /exposure-period?startdate=2017-07-04&enddate=2018-07-04&productgroup=${PRODUCTS.BS}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-07-04&enddate=2018-07-04&productgroup=${PRODUCTS.BS}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-07-04&enddate=2018-07-04&productgroup=${PRODUCTS.BS}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(13); }); it(`GET /exposure-period?startdate=2017-07-04&enddate=2018-07-05&productgroup=${PRODUCTS.BS}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-07-04&enddate=2018-07-05&productgroup=${PRODUCTS.BS}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-07-04&enddate=2018-07-05&productgroup=${PRODUCTS.BS}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(13); }); @@ -50,42 +49,42 @@ describe('Exposure period', () => { // EW Start is EOM it(`GET /exposure-period?startdate=2017-03-31&enddate=2017-04-01&productgroup=${PRODUCTS.EW}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-03-31&enddate=2017-04-01&productgroup=${PRODUCTS.EW}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-03-31&enddate=2017-04-01&productgroup=${PRODUCTS.EW}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(1); }); // BS Start is EOM it(`GET /exposure-period?startdate=2017-03-31&enddate=2017-04-29&productgroup=${PRODUCTS.BS}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-03-31&enddate=2017-04-29&productgroup=${PRODUCTS.BS}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-03-31&enddate=2017-04-29&productgroup=${PRODUCTS.BS}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(1); }); // EW Start is EOM, end is EOM it(`GET /exposure-period?startdate=2017-03-31&enddate=2017-04-30&productgroup=${PRODUCTS.EW}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-03-31&enddate=2017-04-30&productgroup=${PRODUCTS.EW}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-03-31&enddate=2017-04-30&productgroup=${PRODUCTS.EW}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(1); }); // BS Start is EOM, end is EOM, +1 for exposure it(`GET /exposure-period?startdate=2017-03-31&enddate=2017-04-30&productgroup=${PRODUCTS.BS}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-03-31&enddate=2017-04-30&productgroup=${PRODUCTS.BS}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-03-31&enddate=2017-04-30&productgroup=${PRODUCTS.BS}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(2); }); // EW Start DOM = End DOM it(`GET /exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=${PRODUCTS.EW}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=${PRODUCTS.EW}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=${PRODUCTS.EW}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(1); }); // BS Start DOM = End DOM, +1 for exposure it(`GET /exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=${PRODUCTS.BS}`, async () => { - const { status, body } = await api.get(`/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=${PRODUCTS.BS}`); + const { status, body } = await api.get(`/api/v1/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=${PRODUCTS.BS}`); expect(status).toBe(200); expect(body.exposurePeriod).toBe(2); }); @@ -93,7 +92,7 @@ describe('Exposure period', () => { // Input error handling checks it('GET /exposure-period', async () => { - const { status, body } = await api.get(`/exposure-period`); + const { status, body } = await api.get(`/api/v1/exposure-period`); expect(status).toBe(400); expect(body.message).toContain('startdate must be a valid ISO 8601 date string'); expect(body.message).toContain('enddate must be a valid ISO 8601 date string'); @@ -102,7 +101,7 @@ describe('Exposure period', () => { }); it('Should fail Feb 29 and Feb 30 - GET /exposure-period?startdate=2017-02-29&enddate=2017-02-30&productgroup=test', async () => { - const { status, body } = await api.get('/exposure-period?startdate=2017-02-29&enddate=2017-02-30&productgroup=test'); + const { status, body } = await api.get('/api/v1/exposure-period?startdate=2017-02-29&enddate=2017-02-30&productgroup=test'); expect(status).toBe(400); expect(body.message).toContain('startdate must be a valid ISO 8601 date string'); expect(body.message).toContain('enddate must be a valid ISO 8601 date string'); @@ -110,7 +109,7 @@ describe('Exposure period', () => { }); it('GET /exposure-period?startdate=2017-01-32&enddate=2017-02-32&productgroup=test', async () => { - const { status, body } = await api.get('/exposure-period?startdate=2017-01-32&enddate=2017-02-32&productgroup=test'); + const { status, body } = await api.get('/api/v1/exposure-period?startdate=2017-01-32&enddate=2017-02-32&productgroup=test'); expect(status).toBe(400); expect(body.message).toContain('startdate must be a valid ISO 8601 date string'); expect(body.message).toContain('enddate must be a valid ISO 8601 date string'); @@ -118,7 +117,7 @@ describe('Exposure period', () => { }); it('GET /exposure-period?startdate=null&enddate=null&productgroup=null', async () => { - const { status, body } = await api.get('/exposure-period?startdate=null&enddate=null&productgroup=null'); + const { status, body } = await api.get('/api/v1/exposure-period?startdate=null&enddate=null&productgroup=null'); expect(status).toBe(400); expect(body.message).toContain('startdate must be a valid ISO 8601 date string'); expect(body.message).toContain('enddate must be a valid ISO 8601 date string'); @@ -126,7 +125,7 @@ describe('Exposure period', () => { }); it('GET /exposure-period?startdate=undefined&enddate=undefined&productgroup=undefined', async () => { - const { status, body } = await api.get('/exposure-period?startdate=undefined&enddate=undefined&productgroup=undefined'); + const { status, body } = await api.get('/api/v1/exposure-period?startdate=undefined&enddate=undefined&productgroup=undefined'); expect(status).toBe(400); expect(body.message).toContain('startdate must be a valid ISO 8601 date string'); expect(body.message).toContain('enddate must be a valid ISO 8601 date string'); @@ -134,12 +133,8 @@ describe('Exposure period', () => { }); it('GET /exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=new', async () => { - const { status, body } = await api.get('/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=new'); + const { status, body } = await api.get('/api/v1/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=new'); expect(status).toBe(400); expect(body.message).toContain('productgroup must be one of the following values: EW, BS'); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/interest-rates/interest-rates.api-test.ts b/test/interest-rates/interest-rates.api-test.ts index 4831efde..2d63091d 100644 --- a/test/interest-rates/interest-rates.api-test.ts +++ b/test/interest-rates/interest-rates.api-test.ts @@ -1,19 +1,18 @@ -import { INestApplication } from '@nestjs/common'; - -import { Api } from '../api'; -import { CreateApp } from '../createApp'; +import { Api } from '@ukef-test/support/api'; describe('Interest rates', () => { - let app: INestApplication; let api: Api; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it(`GET /interest-rates`, async () => { - const { status, body } = await api.get('/interest-rates'); + const { status, body } = await api.get('/api/v1/interest-rates'); expect(status).toBe(200); expect(body).toEqual( @@ -35,8 +34,4 @@ describe('Interest rates', () => { ]), ); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/markets/markets.api-test.ts b/test/markets/markets.api-test.ts index 3a61a2dd..1443fb20 100644 --- a/test/markets/markets.api-test.ts +++ b/test/markets/markets.api-test.ts @@ -1,11 +1,8 @@ -import { INestApplication } from '@nestjs/common'; +import { Api } from '@ukef-test/support/api'; -import { Api } from '../api'; -import { CreateApp } from '../createApp'; import { TEST_CONSTANTS } from '../test-constants'; describe('Markets', () => { - let app: INestApplication; let api: Api; const marketSchema = { @@ -30,19 +27,22 @@ describe('Markets', () => { }; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it(`GET /markets`, async () => { - const { status, body } = await api.get('/markets'); + const { status, body } = await api.get('/api/v1/markets'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(marketSchema)])); }); it(`GET /markets?active=Y`, async () => { - const { status, body } = await api.get('/markets?active=Y'); + const { status, body } = await api.get('/api/v1/markets?active=Y'); expect(status).toBe(200); expect(body).toEqual( @@ -56,7 +56,7 @@ describe('Markets', () => { }); it(`GET /markets?active=N`, async () => { - const { status, body } = await api.get('/markets?active=N'); + const { status, body } = await api.get('/api/v1/markets?active=N'); expect(status).toBe(200); expect(body).toEqual( @@ -70,15 +70,15 @@ describe('Markets', () => { }); it(`returns more results from GET /markets?active=Y than GET /markets?active=N`, async () => { - const responseActive = await api.get('/markets?active=Y'); - const responseDisabled = await api.get('/markets?active=N'); + const responseActive = await api.get('/api/v1/markets?active=Y'); + const responseDisabled = await api.get('/api/v1/markets?active=N'); // We expect more active markets than disabled expect(responseActive.body.length).toBeGreaterThan(responseDisabled.body.length); }); it(`GET /markets?active=something-else`, async () => { - const { status, body } = await api.get('/markets?active=something-else'); + const { status, body } = await api.get('/api/v1/markets?active=something-else'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -86,7 +86,7 @@ describe('Markets', () => { }); it(`GET /markets?active=`, async () => { - const { status, body } = await api.get('/markets?active='); + const { status, body } = await api.get('/api/v1/markets?active='); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -94,7 +94,7 @@ describe('Markets', () => { }); it(`GET /markets?active=null`, async () => { - const { status, body } = await api.get('/markets?active=null'); + const { status, body } = await api.get('/api/v1/markets?active=null'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -102,7 +102,7 @@ describe('Markets', () => { }); it(`GET /markets?active=undefined`, async () => { - const { status, body } = await api.get('/markets?active=undefined'); + const { status, body } = await api.get('/api/v1/markets?active=undefined'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -112,7 +112,7 @@ describe('Markets', () => { // Testing "search" query parameter it(`GET /markets?search=Aus`, async () => { - const { status, body } = await api.get('/markets?search=Aus'); + const { status, body } = await api.get('/api/v1/markets?search=Aus'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(marketSchema)])); @@ -120,7 +120,7 @@ describe('Markets', () => { }); it(`GET /markets?search=AUT`, async () => { - const { status, body } = await api.get('/markets?search=AUT'); + const { status, body } = await api.get('/api/v1/markets?search=AUT'); expect(status).toBe(200); @@ -130,8 +130,8 @@ describe('Markets', () => { }); it(`test that query param search is not case sensitive`, async () => { - const { status, body } = await api.get('/markets?search=Aus'); - const lowerCaseResponse = await api.get('/markets?search=aus'); + const { status, body } = await api.get('/api/v1/markets?search=Aus'); + const lowerCaseResponse = await api.get('/api/v1/markets?search=aus'); expect(status).toBe(200); expect(lowerCaseResponse.status).toBe(200); @@ -140,55 +140,51 @@ describe('Markets', () => { }); it(`GET /markets?active=Y&search=Aus`, async () => { - const { status, body } = await api.get('/markets?active=Y&search=Aus'); + const { status, body } = await api.get('/api/v1/markets?active=Y&search=Aus'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(marketSchema)])); }); it(`GET /markets?active=N&search=Aus`, async () => { - const { status, body } = await api.get('/markets?active=N&search=Aus'); + const { status, body } = await api.get('/api/v1/markets?active=N&search=Aus'); expect(status).toBe(200); expect(body).toEqual([]); }); it(`GET /markets?search=undefined`, async () => { - const { status, body } = await api.get('/markets?search=undefined'); + const { status, body } = await api.get('/api/v1/markets?search=undefined'); expect(status).toBe(200); expect(body).toEqual([]); }); it(`GET /markets?search=null`, async () => { - const { status, body } = await api.get('/markets?search=null'); + const { status, body } = await api.get('/api/v1/markets?search=null'); expect(status).toBe(200); expect(body).toEqual([]); }); it(`GET /markets?search=`, async () => { - const { status, body } = await api.get('/markets?search='); + const { status, body } = await api.get('/api/v1/markets?search='); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(marketSchema)])); }); it(`GET /markets?search=${TEST_CONSTANTS.SPECIAL_CHARACTERS}`, async () => { - const { status, body } = await api.get(`/markets?search=${TEST_CONSTANTS.SPECIAL_CHARACTERS}`); + const { status, body } = await api.get(`/api/v1/markets?search=${TEST_CONSTANTS.SPECIAL_CHARACTERS}`); expect(status).toBe(200); expect(body).toEqual([]); }); it(`GET /markets?search=%20%20%20`, async () => { - const { status, body } = await api.get('/markets?search=%20%20%20'); + const { status, body } = await api.get('/api/v1/markets?search=%20%20%20'); expect(status).toBe(200); expect(body).toEqual([]); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/numbers/numbers.api-test.ts b/test/numbers/numbers.api-test.ts index 25cb95e4..a0128a1b 100644 --- a/test/numbers/numbers.api-test.ts +++ b/test/numbers/numbers.api-test.ts @@ -1,19 +1,18 @@ -import { INestApplication } from '@nestjs/common'; - -import { Api } from '../api'; -import { CreateApp } from '../createApp'; +import { Api } from '@ukef-test/support/api'; describe('Numbers', () => { - let app: INestApplication; let api: Api; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it(`GET /numbers?type=1&ukefId=0010581069`, async () => { - const { status, body } = await api.get('/numbers?type=1&ukefId=0010581069'); + const { status, body } = await api.get('/api/v1/numbers?type=1&ukefId=0010581069'); expect(status).toBe(404); expect(body.error).toMatch('Not Found'); @@ -31,25 +30,25 @@ describe('Numbers', () => { }, ]; // Generate - const postResponse = await api.post(postNumbersPayload).to('/numbers'); + const postResponse = await api.post('/api/v1/numbers', postNumbersPayload); expect(postResponse.status).toBe(201); // Test - const getResponse = await api.get('/numbers?type=' + postResponse.body[0].type + '&ukefId=' + postResponse.body[0].maskedId); + const getResponse = await api.get('/api/v1/numbers?type=' + postResponse.body[0].type + '&ukefId=' + postResponse.body[0].maskedId); expect(getResponse.status).toBe(200); expect(postResponse.body[0]).toEqual(getResponse.body); }); it(`GET /numbers?type=2&ukefId=0030581069`, async () => { - const { status } = await api.get('/numbers?type=2&ukefId=0030581069'); + const { status } = await api.get('/api/v1/numbers?type=2&ukefId=0030581069'); expect(status).toBe(404); }); it(`GET /numbers?type=a&ukefId=a`, async () => { - const { status, body } = await api.get('/numbers?type=a&ukefId=a'); + const { status, body } = await api.get('/api/v1/numbers?type=a&ukefId=a'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -58,7 +57,7 @@ describe('Numbers', () => { }); it(`GET /numbers?type=null&ukefId=null`, async () => { - const { status, body } = await api.get('/numbers?type=null&ukefId=null'); + const { status, body } = await api.get('/api/v1/numbers?type=null&ukefId=null'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -67,7 +66,7 @@ describe('Numbers', () => { }); it(`GET /numbers?type=undefined&ukefId=undefined`, async () => { - const { status, body } = await api.get('/numbers?type=undefined&ukefId=undefined'); + const { status, body } = await api.get('/api/v1/numbers?type=undefined&ukefId=undefined'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -76,7 +75,7 @@ describe('Numbers', () => { }); it(`GET /numbers?type=a&ukefId=0030581069`, async () => { - const { status, body } = await api.get('/numbers?type=a&ukefId=0030581069'); + const { status, body } = await api.get('/api/v1/numbers?type=a&ukefId=0030581069'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -84,7 +83,7 @@ describe('Numbers', () => { }); it(`GET /numbers?type=3&ukefId=0030581069`, async () => { - const { status, body } = await api.get('/numbers?type=3&ukefId=0030581069'); + const { status, body } = await api.get('/api/v1/numbers?type=3&ukefId=0030581069'); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -99,7 +98,7 @@ describe('Numbers', () => { requestingSystem: 'Jest 1 - Deal', }, ]; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(201); expect(body).toHaveLength(1); @@ -119,7 +118,7 @@ describe('Numbers', () => { requestingSystem: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mau', }, ]; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(201); expect(body).toHaveLength(1); @@ -139,7 +138,7 @@ describe('Numbers', () => { requestingSystem: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris ac magna ipsum', }, ]; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -149,7 +148,7 @@ describe('Numbers', () => { it(`POST /numbers single, missing fields`, async () => { const payload = [{}]; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -160,7 +159,7 @@ describe('Numbers', () => { it(`POST /numbers single, empty payload`, async () => { const payload = ''; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -169,7 +168,7 @@ describe('Numbers', () => { it(`POST /numbers single, empty array`, async () => { const payload = []; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -178,7 +177,7 @@ describe('Numbers', () => { it(`POST /numbers single, not parsable array`, async () => { const payload = '[]'; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -187,7 +186,7 @@ describe('Numbers', () => { it(`POST /numbers single, bad json`, async () => { const payload = 'asd'; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -217,7 +216,7 @@ describe('Numbers', () => { requestingSystem: 'Jest 4 - Covenant', }, ]; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(201); expect(body).toHaveLength(4); @@ -295,7 +294,7 @@ describe('Numbers', () => { requestingSystem: 'Jest 4 - Party', }, ]; - const { status, body } = await api.post(payload).to('/numbers'); + const { status, body } = await api.post('/api/v1/numbers', payload); expect(status).toBe(201); expect(body).toHaveLength(payload.length); @@ -314,8 +313,4 @@ describe('Numbers', () => { return previousValues; }, Object.create(null)); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/premium-schedules/premium-schedules.api-test.ts b/test/premium-schedules/premium-schedules.api-test.ts index a9b75486..d259c96b 100644 --- a/test/premium-schedules/premium-schedules.api-test.ts +++ b/test/premium-schedules/premium-schedules.api-test.ts @@ -1,14 +1,10 @@ -import { INestApplication } from '@nestjs/common'; import { PRODUCTS } from '@ukef/constants'; +import { Api } from '@ukef-test/support/api'; import Chance from 'chance'; -import { Api } from '../api'; -import { CreateApp } from '../createApp'; - const chance = new Chance(); describe('Premium schedules', () => { - let app: INestApplication; let api: Api; const premiumScheduleSchema = { @@ -28,12 +24,15 @@ describe('Premium schedules', () => { }; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it('GET /premium/segments/12345678', async () => { - const { status, body } = await api.get('/premium/segments/12345678'); + const { status, body } = await api.get('/api/v1/premium/segments/12345678'); // Not generated yet. expect(status).toBe(404); @@ -60,7 +59,7 @@ describe('Premium schedules', () => { maximumLiability: 40000, }, ]; - const postResponse = await api.post(createSchedules).to('/premium/schedule'); + const postResponse = await api.post('/api/v1/premium/schedule', createSchedules); expect(postResponse.status).toBe(201); expect(postResponse.body).toHaveLength(1); @@ -85,12 +84,12 @@ describe('Premium schedules', () => { }, ]; // Generate - const postResponse = await api.post(createSchedules).to('/premium/schedule'); + const postResponse = await api.post('/api/v1/premium/schedule', createSchedules); expect(postResponse.status).toBe(201); // Test - const getResponse = await api.get('/premium/segments/' + postResponse.body[0].facilityURN); + const getResponse = await api.get('/api/v1/premium/segments/' + postResponse.body[0].facilityURN); expect(getResponse.status).toBe(200); expect(getResponse.body).toHaveLength(16); @@ -116,7 +115,7 @@ describe('Premium schedules', () => { maximumLiability: 40000, }, ]; - const postResponse = await api.post(createSchedules).to('/premium/schedule'); + const postResponse = await api.post('/api/v1/premium/schedule', createSchedules); expect(postResponse.status).toBe(201); expect(postResponse.body).toHaveLength(1); @@ -140,7 +139,7 @@ describe('Premium schedules', () => { maximumLiability: 40000, }, ]; - const postResponse = await api.post(createSchedules).to('/premium/schedule'); + const postResponse = await api.post('/api/v1/premium/schedule', createSchedules); expect(postResponse.status).toBe(201); expect(postResponse.body).toHaveLength(1); @@ -164,7 +163,7 @@ describe('Premium schedules', () => { maximumLiability: 40000, }, ]; - const postResponse = await api.post(createSchedules).to('/premium/schedule'); + const postResponse = await api.post('/api/v1/premium/schedule', createSchedules); expect(postResponse.status).toBe(201); expect(postResponse.body).toHaveLength(1); @@ -188,7 +187,7 @@ describe('Premium schedules', () => { maximumLiability: 40000, }, ]; - const { status, body } = await api.post(createSchedules).to('/premium/schedule'); + const { status, body } = await api.post('/api/v1/premium/schedule', createSchedules); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -213,7 +212,7 @@ describe('Premium schedules', () => { }, ]; - const { status, body } = await api.post(createSchedules).to('/premium/schedule'); + const { status, body } = await api.post('/api/v1/premium/schedule', createSchedules); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -223,20 +222,20 @@ describe('Premium schedules', () => { }); it('GET /premium/segments/null', async () => { - const { status, body } = await api.get('/premium/segments/null'); + const { status, body } = await api.get('/api/v1/premium/segments/null'); expect(status).toBe(400); expect(body.message).toContain('facilityId must match /^\\d{8,10}$/ regular expression'); }); it('GET /premium/segments/undefined', async () => { - const { status, body } = await api.get('/premium/segments/undefined'); + const { status, body } = await api.get('/api/v1/premium/segments/undefined'); expect(status).toBe(400); expect(body.message).toContain('facilityId must match /^\\d{8,10}$/ regular expression'); }); it('POST /premium/schedule, empty array', async () => { const payload = []; - const { status, body } = await api.post(payload).to('/premium/schedule'); + const { status, body } = await api.post('/api/v1/premium/schedule', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -245,7 +244,7 @@ describe('Premium schedules', () => { it('POST /premium/schedule, not parsable array', async () => { const payload = '[]'; - const { status, body } = await api.post(payload).to('/premium/schedule'); + const { status, body } = await api.post('/api/v1/premium/schedule', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -254,7 +253,7 @@ describe('Premium schedules', () => { it('POST /premium/schedule, bad json', async () => { const payload = 'asd'; - const { status, body } = await api.post(payload).to('/premium/schedule'); + const { status, body } = await api.post('/api/v1/premium/schedule', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -263,7 +262,7 @@ describe('Premium schedules', () => { it('POST /premium/schedule, field validation', async () => { const payload = [{}]; - const { status, body } = await api.post(payload).to('/premium/schedule'); + const { status, body } = await api.post('/api/v1/premium/schedule', payload); expect(status).toBe(400); expect(body.error).toMatch('Bad Request'); @@ -291,8 +290,4 @@ describe('Premium schedules', () => { expect(body.message).toContain('maximumLiability should not be empty'); expect(body.message).toContain('maximumLiability must be a number conforming to the specified constraints'); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/sector-industries/sector-industries.api-test.ts b/test/sector-industries/sector-industries.api-test.ts index d9b62091..bedf4145 100644 --- a/test/sector-industries/sector-industries.api-test.ts +++ b/test/sector-industries/sector-industries.api-test.ts @@ -1,10 +1,6 @@ -import { INestApplication } from '@nestjs/common'; - -import { Api } from '../api'; -import { CreateApp } from '../createApp'; +import { Api } from '@ukef-test/support/api'; describe('Sector industries', () => { - let app: INestApplication; let api: Api; const sectorIndustriesSchema = { @@ -25,63 +21,62 @@ describe('Sector industries', () => { }; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); it(`GET /sector-industries`, async () => { - const { status, body } = await api.get('/sector-industries'); + const { status, body } = await api.get('/api/v1/sector-industries'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(sectorIndustriesSchema)])); }); it(`GET /sector-industries?ukefSectorId=1001`, async () => { - const { status, body } = await api.get('/sector-industries?ukefSectorId=1001'); + const { status, body } = await api.get('/api/v1/sector-industries?ukefSectorId=1001'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(sectorIndustriesSchema)])); expect(body.length).toBeGreaterThan(1); }); it(`GET /sector-industries?ukefIndustryId=01120`, async () => { - const { status, body } = await api.get('/sector-industries?ukefIndustryId=01120'); + const { status, body } = await api.get('/api/v1/sector-industries?ukefIndustryId=01120'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(sectorIndustriesSchema)])); expect(body).toHaveLength(1); }); it(`GET /sector-industries?ukefSectorId=1001&ukefIndustryId=01120`, async () => { - const { status, body } = await api.get('/sector-industries?ukefSectorId=1001&ukefIndustryId=01120'); + const { status, body } = await api.get('/api/v1/sector-industries?ukefSectorId=1001&ukefIndustryId=01120'); expect(status).toBe(200); expect(body).toHaveLength(1); }); it(`GET /sector-industries?ukefSectorId=1234`, async () => { - const { status } = await api.get('/sector-industries?ukefSectorId=1234'); + const { status } = await api.get('/api/v1/sector-industries?ukefSectorId=1234'); expect(status).toBe(404); }); it(`GET /sector-industries?ukefSectorId=a&ukefIndustryId=a`, async () => { - const { status, body } = await api.get('/sector-industries?ukefSectorId=a&ukefIndustryId=a'); + const { status, body } = await api.get('/api/v1/sector-industries?ukefSectorId=a&ukefIndustryId=a'); expect(status).toBe(400); expect(body.message).toContain('ukefSectorId must match /^\\d{4}$/ regular expression'); expect(body.message).toContain('ukefIndustryId must match /^\\d{5}$/ regular expression'); }); it(`GET /sector-industries?ukefSectorId=null&ukefIndustryId=null`, async () => { - const { status, body } = await api.get('/sector-industries?ukefSectorId=null&ukefIndustryId=null'); + const { status, body } = await api.get('/api/v1/sector-industries?ukefSectorId=null&ukefIndustryId=null'); expect(status).toBe(400); expect(body.message).toContain('ukefSectorId must match /^\\d{4}$/ regular expression'); expect(body.message).toContain('ukefIndustryId must match /^\\d{5}$/ regular expression'); }); it(`GET /sector-industries?ukefSectorId=undefined&ukefIndustryId=undefined`, async () => { - const { status, body } = await api.get('/sector-industries?ukefSectorId=undefined&ukefIndustryId=undefined'); + const { status, body } = await api.get('/api/v1/sector-industries?ukefSectorId=undefined&ukefIndustryId=undefined'); expect(status).toBe(400); expect(body.message).toContain('ukefSectorId must match /^\\d{4}$/ regular expression'); expect(body.message).toContain('ukefIndustryId must match /^\\d{5}$/ regular expression'); }); - - afterAll(async () => { - await app.close(); - }); }); diff --git a/test/support/api.ts b/test/support/api.ts index dc03f634..f86625d2 100644 --- a/test/support/api.ts +++ b/test/support/api.ts @@ -16,6 +16,10 @@ export class Api { return this.request().get(url).set(this.getValidAuthHeader()); } + post(url: string, body: string | object): request.Test { + return this.request().post(url).send(body).set(this.getValidAuthHeader()); + } + getWithoutAuth(url: string, strategy?: string, key?: string): request.Test { const query = this.request().get(url); return this.setQueryWithAuthStrategyIfPresent(query, strategy, key); diff --git a/test/yield-rates/yield-rates.api-test.ts b/test/yield-rates/yield-rates.api-test.ts index 0386c8db..756dbfe8 100644 --- a/test/yield-rates/yield-rates.api-test.ts +++ b/test/yield-rates/yield-rates.api-test.ts @@ -1,16 +1,15 @@ -import { INestApplication } from '@nestjs/common'; import { DATE } from '@ukef/constants'; - -import { Api } from '../api'; -import { CreateApp } from '../createApp'; +import { Api } from '@ukef-test/support/api'; describe('Interest rates', () => { - let app: INestApplication; - let api: Api; + let api; beforeAll(async () => { - app = await new CreateApp().init(); - api = new Api(app.getHttpServer()); + api = await Api.create(); + }); + + afterAll(async () => { + await api.destroy(); }); const yieldRateSchema = { @@ -31,13 +30,13 @@ describe('Interest rates', () => { }; it(`GET /yield-rates`, async () => { - const { status, body } = await api.get('/yield-rates'); + const { status, body } = await api.get('/api/v1/yield-rates'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining({ ...yieldRateSchema, effectiveTo: DATE.MAXIMUM_TIMEZONE_LIMIT })])); }); it(`GET /yield-rates?searchDate=2023-03-02`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=2023-03-02'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=2023-03-02'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining(yieldRateSchema)])); @@ -47,78 +46,74 @@ describe('Interest rates', () => { // UKEF at the moment has yield rates since 2010-03-15, maybe some old data will be retired in future. it(`returns 404 for any date past 2010-03-15 where the yield data does not exist`, async () => { - const { status } = await api.get('/yield-rates?searchDate=2010-03-14'); + const { status } = await api.get('/api/v1/yield-rates?searchDate=2010-03-14'); expect(status).toBe(404); }); // Current yield rates have effective date till 9999-12-31, so 9999-12-30 is max date with results. it(`GET /yield-rates?searchDate=9999-12-30`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=9999-12-30'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=9999-12-30'); expect(status).toBe(200); expect(body).toEqual(expect.arrayContaining([expect.objectContaining({ ...yieldRateSchema, effectiveTo: DATE.MAXIMUM_TIMEZONE_LIMIT })])); }); // Current yield rates have effective date till 9999-12-31, so no rates for this max date. it(`returns 404 for GET /yield-rates?searchDate=9999-12-31`, async () => { - const { status } = await api.get('/yield-rates?searchDate=9999-12-31'); + const { status } = await api.get('/api/v1/yield-rates?searchDate=9999-12-31'); expect(status).toBe(404); }); it(`returns 400 for GET /yield-rates?searchDate=2023-03-02T16:29:04.027Z`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=2023-03-02T16:29:04.027Z'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=2023-03-02T16:29:04.027Z'); expect(status).toBe(400); expect(body.message).toContain('searchDate should use format YYYY-MM-DD'); }); it(`returns 400 for GET /yield-rates?searchDate=null`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=null'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=null'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=undefined`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=undefined'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=undefined'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=ABC`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=ABC'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=ABC'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=123`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=123'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=123'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=!"£!"£`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=!"£!"£'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=!"£!"£'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=A%20£`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=A%20£'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=A%20£'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=++`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=++'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=++'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); it(`returns 400 for GET /yield-rates?searchDate=0000-00-00`, async () => { - const { status, body } = await api.get('/yield-rates?searchDate=0000-00-00'); + const { status, body } = await api.get('/api/v1/yield-rates?searchDate=0000-00-00'); expect(status).toBe(400); expect(body.message).toContain('searchDate must be a valid ISO 8601 date string'); }); - - afterAll(async () => { - await app.close(); - }); }); From 837a48254d14c6369f1f394aeb2d0646bdeb2ed9 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 15 Apr 2024 10:25:00 +0100 Subject: [PATCH 13/56] feat(DTFS2-7052): tests for ordnance survey API endpoint --- .../geospatial/geospatial.controller.test.ts | 62 +++++++++++++++++ .../geospatial/geospatial.controller.ts | 7 +- .../geospatial/geospatial.service.test.ts | 67 +++++++++++++++++++ src/modules/geospatial/geospatial.service.ts | 2 +- .../get-docs-yaml.api-test.ts.snap | 11 ++- .../get-address-by-postcode.api-test.ts | 7 +- .../get-geospatial-addresses-generator.ts | 12 ++-- 7 files changed, 150 insertions(+), 18 deletions(-) create mode 100644 src/modules/geospatial/geospatial.controller.test.ts create mode 100644 src/modules/geospatial/geospatial.service.test.ts diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts new file mode 100644 index 00000000..d60c0a83 --- /dev/null +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -0,0 +1,62 @@ +import { GEOSPATIAL } from '@ukef/constants'; +import { GetGeospatialAddressesGenerator } from '@ukef-test/support/generator/get-geospatial-addresses-generator'; +import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; +import { resetAllWhenMocks, when } from 'jest-when'; + +import { GeospatialController } from './geospatial.controller'; +import { GeospatialService } from './geospatial.service'; + +describe('GeospatialController', () => { + let geospatialServiceGetAddressesByPostcode: jest.Mock; + + let controller: GeospatialController; + + const valueGenerator = new RandomValueGenerator(); + const { getAddressByPostcodeResponse, getAddressByPostcodeMultipleResponse } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ + numberToGenerate: 2, + }); + + beforeEach(() => { + resetAllWhenMocks(); + const geospatialService = new GeospatialService(null); + geospatialServiceGetAddressesByPostcode = jest.fn(); + geospatialService.getAddressesByPostcode = geospatialServiceGetAddressesByPostcode; + + controller = new GeospatialController(geospatialService); + }); + + it('should be defined', () => { + expect(GeospatialController).toBeDefined(); + }); + + describe('getAddressesByPostcode()', () => { + const postcode = GEOSPATIAL.EXAMPLES.POSTCODE; + + it('returns address for postcode', async () => { + when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressByPostcodeResponse[0]); + + const response = await controller.getAddressesByPostcode({ postcode }); + + expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalled(); + expect(response).toEqual(getAddressByPostcodeResponse[0]); + }); + + it('returns multiple addressess for postcode', async () => { + when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressByPostcodeMultipleResponse); + + const response = await controller.getAddressesByPostcode({ postcode }); + + expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalled(); + expect(response).toEqual(getAddressByPostcodeMultipleResponse); + }); + + it('returns empty response for postcode', async () => { + when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce([]); + + const response = await controller.getAddressesByPostcode({ postcode }); + + expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalled(); + expect(response).toEqual([]); + }); + }); +}); diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 4d1580b7..50486d98 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -12,17 +12,18 @@ export class GeospatialController { @Get('addresses/postcode') @ApiOperation({ - summary: "A search based on a property's postcode. Will accept a full postcode consisting of the area, district, sector and unit e.g. SO16 0AS.", + summary: + "A search based on a property's postcode. Will accept a full valid postcode. Returns addresses from Ordanance survey Delivery Point Address (DPA) system.", }) @ApiResponse({ status: 200, - description: 'Returns addresses from Ordanance survey Delivery Point Address (DPA) system.', + description: 'Returns simplified addresses that are ready to show to users.', type: [GetAddressesResponseItem], }) @ApiNotFoundResponse({ description: 'Customer not found.', }) - getGeospatial(@Query() query: GetAddressByPostcodeQueryDto): Promise { + getAddressesByPostcode(@Query() query: GetAddressByPostcodeQueryDto): Promise { return this.geospatialService.getAddressesByPostcode(query.postcode); } } diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts new file mode 100644 index 00000000..ec3165dd --- /dev/null +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -0,0 +1,67 @@ +import { ConfigService } from '@nestjs/config'; +import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; +import { GetGeospatialAddressesGenerator } from '@ukef-test/support/generator/get-geospatial-addresses-generator'; +import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; +import { resetAllWhenMocks, when } from 'jest-when'; + +import { GeospatialService } from './geospatial.service'; + +jest.mock('@ukef/modules/informatica/informatica.service'); + +describe('CustomerService', () => { + const valueGenerator = new RandomValueGenerator(); + + let service: GeospatialService; + let configServiceGet: jest.Mock; + let informaticaServiceGetAddressesByPostcode: jest.Mock; + + beforeEach(() => { + const configService = new ConfigService(); + configServiceGet = jest.fn().mockReturnValue({ key: valueGenerator.word() }); + configService.get = configServiceGet; + + informaticaServiceGetAddressesByPostcode = jest.fn(); + const ordnanceSurveyService = new OrdnanceSurveyService(null, configService); + ordnanceSurveyService.getAddressesByPostcode = informaticaServiceGetAddressesByPostcode; + resetAllWhenMocks(); + + service = new GeospatialService(ordnanceSurveyService); + }); + + describe('getAddressesByPostcode', () => { + const { + getAddressByPostcodeResponse, + getAddressByPostcodeMultipleResponse, + getAddressOrdnanceSurveyResponse, + getAddressOrdnanceSurveyMultipleResponse, + getAddressOrdnanceSurveyEmptyResponse, + } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ + numberToGenerate: 2, + }); + const postcode = getAddressByPostcodeResponse[0][0].postalCode; + + it('returns address from the backend service', async () => { + when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyResponse[0]); + + const response = await service.getAddressesByPostcode(postcode); + + expect(response).toEqual(getAddressByPostcodeResponse[0]); + }); + + it('returns multiple addressess from the backend service', async () => { + when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyMultipleResponse); + + const response = await service.getAddressesByPostcode(postcode); + + expect(response).toEqual(getAddressByPostcodeMultipleResponse); + }); + + it('can handle empty backend response', async () => { + when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyEmptyResponse[0]); + + const response = await service.getAddressesByPostcode(postcode); + + expect(response).toEqual([]); + }); + }); +}); diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index e1cf93df..b3cb515d 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -27,7 +27,7 @@ export class GeospatialService { addressLine3: null, locality: item_data.POST_TOWN || null, postalCode: item_data.POSTCODE || null, - country: ENUMS.GEOSPATIAL_COUNTRIES[item_data.COUNTRY_CODE], + country: ENUMS.GEOSPATIAL_COUNTRIES[item_data.COUNTRY_CODE] || null, }); }); diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index 77af87e5..b71b8f1e 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -488,10 +488,11 @@ paths: - yield-rates /api/v1/geospatial/addresses/postcode: get: - operationId: GeospatialController_getGeospatial + operationId: GeospatialController_getAddressesByPostcode summary: >- - A search based on a property's postcode. Will accept a full postcode - consisting of the area, district, sector and unit e.g. SO16 0AS. + A search based on a property's postcode. Will accept a full valid + postcode. Returns addresses from Ordanance survey Delivery Point Address + (DPA) system. parameters: - name: postcode required: true @@ -502,9 +503,7 @@ paths: type: string responses: '200': - description: >- - Returns addresses from Ordanance survey Delivery Point Address (DPA) - system. + description: Returns simplified addresses that are ready to show to users. content: application/json: schema: diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts index 770ef319..64f0283b 100644 --- a/test/geospatial/get-address-by-postcode.api-test.ts +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -15,9 +15,10 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { ordnanceSurveyPath, mdmPath, getAddressByPostcodeResponse, + getAddressByPostcodeMultipleResponse, getAddressOrdnanceSurveyResponse, getAddressOrdnanceSurveyEmptyResponse, - getAddressessOrdnanceSurveyResponse, + getAddressOrdnanceSurveyMultipleResponse, ordnanceSurveyAuthErrorResponse, } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ postcode: GEOSPATIAL.EXAMPLES.POSTCODE, @@ -58,12 +59,12 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { }); it('returns a 200 response with the addresses if they are returned by Ordnance Survey API', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressessOrdnanceSurveyResponse); + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyMultipleResponse); const { status, body } = await api.get(mdmPath[0]); expect(status).toBe(200); - expect(body).toStrictEqual([getAddressByPostcodeResponse[0][0], getAddressByPostcodeResponse[1][0]]); + expect(body).toStrictEqual(getAddressByPostcodeMultipleResponse); }); it('returns a empty 200 response if Ordnance Survey API returns a 200 without results', async () => { diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index efabd55c..69320761 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -52,6 +52,8 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator response[0]); + const getAddressOrdnanceSurveyResponse: GetAddressOrdnanceSurveyResponse[] = values.map((v) => ({ header: { uri: 'test', @@ -107,7 +109,7 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Mon, 15 Apr 2024 10:42:52 +0100 Subject: [PATCH 14/56] feat(DTFS2-7052): fix address line 1 formating --- src/modules/geospatial/geospatial.service.test.ts | 11 +++++++++++ src/modules/geospatial/geospatial.service.ts | 5 +++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index ec3165dd..7853afcf 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -63,5 +63,16 @@ describe('CustomerService', () => { expect(response).toEqual([]); }); + + it('returns addressLine1 formatted correctly even if middle value is missing', async () => { + const [modifiedOrdnanceSurveyResponse] = getAddressOrdnanceSurveyResponse; + modifiedOrdnanceSurveyResponse.results[0].DPA.BUILDING_NUMBER = null; + const address = modifiedOrdnanceSurveyResponse.results[0].DPA; + when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(modifiedOrdnanceSurveyResponse); + + const response = await service.getAddressesByPostcode(postcode); + + expect(response[0].addressLine1).toBe(`${address.BUILDING_NAME} ${address.THOROUGHFARE_NAME}`); + }); }); }); diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index b3cb515d..d0385b92 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -18,11 +18,12 @@ export class GeospatialService { } response.results.forEach((item) => { - // Ordnance survey sends duplicated results with the welsh version too via 'CY' + // Item can have key DPA or LPI, get data dynamicaly, even if we expect key to always be DPA. const item_data = item[Object.keys(item)[0]]; addresses.push({ organisationName: item_data.ORGANISATION_NAME || null, - addressLine1: `${item_data.BUILDING_NAME || ''} ${item_data.BUILDING_NUMBER || ''} ${item_data.THOROUGHFARE_NAME || ''}`.trim(), + // Filter out empty values and join values with single space. + addressLine1: [item_data.BUILDING_NAME, item_data.BUILDING_NUMBER, item_data.THOROUGHFARE_NAME].filter(Boolean).join(' '), addressLine2: item_data.DEPENDENT_LOCALITY || null, addressLine3: null, locality: item_data.POST_TOWN || null, From 4c503caa0895a0c1b8ba5214dd5aeeeeb57f11a1 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 15 Apr 2024 11:55:39 +0100 Subject: [PATCH 15/56] feat(DTFS2-7052): spelling fix --- src/modules/geospatial/geospatial.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index d0385b92..2e07562b 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -18,7 +18,7 @@ export class GeospatialService { } response.results.forEach((item) => { - // Item can have key DPA or LPI, get data dynamicaly, even if we expect key to always be DPA. + // Item can have key DPA or LPI, get data dynamically, even if we expect key to always be DPA. const item_data = item[Object.keys(item)[0]]; addresses.push({ organisationName: item_data.ORGANISATION_NAME || null, From 252b5a132a04e44df1cc4a66f27f5ff16af67207 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 18 Apr 2024 15:26:41 +0100 Subject: [PATCH 16/56] feat(DTFS2-7052): renaming enums/geospatial.ts to enums/geospatialCountries.ts --- src/constants/enums.ts | 4 ++-- src/constants/enums/{geospatial.ts => geospatialCountries.ts} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/constants/enums/{geospatial.ts => geospatialCountries.ts} (100%) diff --git a/src/constants/enums.ts b/src/constants/enums.ts index dc997052..a6a38f2d 100644 --- a/src/constants/enums.ts +++ b/src/constants/enums.ts @@ -1,9 +1,9 @@ import * as FALLBACK_TO_LEGACY_DATA from './enums/fallbackToLegacyData'; -import * as GEOSPATIAL from './enums/geospatial'; +import * as GEOSPATIAL_COUNTRIES from './enums/geospatialCountries'; import * as PRODUCTS from './enums/products'; export const ENUMS = { PRODUCTS: PRODUCTS.QueryParamProductsEnum, FALLBACK_TO_LEGACY_DATA: FALLBACK_TO_LEGACY_DATA.FallbackToLegacyDataEnum, - GEOSPATIAL_COUNTRIES: GEOSPATIAL.GeospatialCountriesEnum, + GEOSPATIAL_COUNTRIES: GEOSPATIAL_COUNTRIES.GeospatialCountriesEnum, }; diff --git a/src/constants/enums/geospatial.ts b/src/constants/enums/geospatialCountries.ts similarity index 100% rename from src/constants/enums/geospatial.ts rename to src/constants/enums/geospatialCountries.ts From f33edc51178d3f6ba07baf7415c1a5c53d9fb4ab Mon Sep 17 00:00:00 2001 From: Audrius Date: Tue, 23 Apr 2024 16:31:02 +0100 Subject: [PATCH 17/56] Update src/modules/geospatial/geospatial.controller.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index d60c0a83..0dd22b21 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -41,7 +41,7 @@ describe('GeospatialController', () => { expect(response).toEqual(getAddressByPostcodeResponse[0]); }); - it('returns multiple addressess for postcode', async () => { + it('returns multiple addresses for the postcode when the service returns multiple addresses', async () => { when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressByPostcodeMultipleResponse); const response = await controller.getAddressesByPostcode({ postcode }); From b67337694a3c93252e0accf15c6033d5f93455c3 Mon Sep 17 00:00:00 2001 From: Audrius Date: Tue, 23 Apr 2024 16:31:13 +0100 Subject: [PATCH 18/56] Update src/modules/geospatial/geospatial.controller.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index 0dd22b21..6037b3a2 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -50,7 +50,7 @@ describe('GeospatialController', () => { expect(response).toEqual(getAddressByPostcodeMultipleResponse); }); - it('returns empty response for postcode', async () => { + it('returns an empty response for the postcode when the service returns an empty response', async () => { when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce([]); const response = await controller.getAddressesByPostcode({ postcode }); From fb2d4bc8699aa993a596f0efb21884afdd3e7f46 Mon Sep 17 00:00:00 2001 From: Audrius Date: Tue, 23 Apr 2024 16:31:24 +0100 Subject: [PATCH 19/56] Update src/modules/geospatial/geospatial.controller.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index 6037b3a2..45e3dfb7 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -46,7 +46,7 @@ describe('GeospatialController', () => { const response = await controller.getAddressesByPostcode({ postcode }); - expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalled(); + expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalledTimes(1); expect(response).toEqual(getAddressByPostcodeMultipleResponse); }); From b7a727cd0b1ab4b2f8500a5ccd17353352636215 Mon Sep 17 00:00:00 2001 From: Audrius Date: Tue, 23 Apr 2024 16:31:34 +0100 Subject: [PATCH 20/56] Update src/modules/geospatial/geospatial.controller.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index 45e3dfb7..700914e2 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -55,7 +55,7 @@ describe('GeospatialController', () => { const response = await controller.getAddressesByPostcode({ postcode }); - expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalled(); + expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalledTimes(1); expect(response).toEqual([]); }); }); From 841268f77775a3dadca7178aa0a54d17ec62055f Mon Sep 17 00:00:00 2001 From: Audrius Date: Tue, 23 Apr 2024 16:31:44 +0100 Subject: [PATCH 21/56] Update src/modules/geospatial/geospatial.service.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index 7853afcf..4f1ab21a 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -8,7 +8,7 @@ import { GeospatialService } from './geospatial.service'; jest.mock('@ukef/modules/informatica/informatica.service'); -describe('CustomerService', () => { +describe('GeospatialService', () => { const valueGenerator = new RandomValueGenerator(); let service: GeospatialService; From 7f1110df012953f6ce05d86c8ca3dc446314a0f5 Mon Sep 17 00:00:00 2001 From: Audrius Date: Tue, 23 Apr 2024 16:58:41 +0100 Subject: [PATCH 22/56] Update src/modules/geospatial/geospatial.service.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index 4f1ab21a..2b34b577 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -40,7 +40,7 @@ describe('GeospatialService', () => { }); const postcode = getAddressByPostcodeResponse[0][0].postalCode; - it('returns address from the backend service', async () => { + it('returns a single address from the backend service', async () => { when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyResponse[0]); const response = await service.getAddressesByPostcode(postcode); From ff5ac7b19b50398c0c4662ca9886987e460dc783 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Tue, 23 Apr 2024 17:11:00 +0100 Subject: [PATCH 23/56] feat(DTFS2-7052): improve address test data --- test/support/generator/get-geospatial-addresses-generator.ts | 4 ++-- test/support/generator/random-value-generator.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index 69320761..c0ed8415 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -14,10 +14,10 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Wed, 24 Apr 2024 15:28:57 +0100 Subject: [PATCH 24/56] feat(DTFS2-7052): applying Oscars suggestions on my PR --- ...-addresses-ordnance-survey-response.dto.ts | 10 +-- .../ordnance-survey/known-errors.ts | 13 --- .../ordnance-survey.service.test.ts | 83 +++++++++---------- .../ordnance-survey.service.ts | 18 ++-- ...rap-ordnance-survey-http-error-callback.ts | 32 ------- ...=> get-addresses-by-postcode-query.dto.ts} | 2 +- .../geospatial/geospatial.controller.ts | 4 +- src/modules/geospatial/geospatial.service.ts | 4 +- .../get-geospatial-addresses-generator.ts | 48 +++++------ 9 files changed, 83 insertions(+), 131 deletions(-) delete mode 100644 src/helper-modules/ordnance-survey/known-errors.ts delete mode 100644 src/helper-modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts rename src/modules/geospatial/dto/{get-address-by-postcode-query.dto.ts => get-addresses-by-postcode-query.dto.ts} (90%) diff --git a/src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts b/src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts index f1c5b1f5..e500d8d9 100644 --- a/src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts +++ b/src/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto.ts @@ -1,4 +1,4 @@ -export type GetAddressOrdnanceSurveyResponse = { +export type GetAddressesOrdnanceSurveyResponse = { header: { uri: string; query: string; @@ -12,14 +12,14 @@ export type GetAddressOrdnanceSurveyResponse = { lastupdate: string; output_srs: string; }; - results?: GetAddressOrdnanceSurveyResponseItem[]; + results?: GetAddressesOrdnanceSurveyResponseItem[]; }; -interface GetAddressOrdnanceSurveyResponseItem { - DPA: GetAddressOrdnanceSurveyResponseAddress; +interface GetAddressesOrdnanceSurveyResponseItem { + DPA: GetAddressesOrdnanceSurveyResponseAddress; } -interface GetAddressOrdnanceSurveyResponseAddress { +interface GetAddressesOrdnanceSurveyResponseAddress { UPRN: string; UDPRN: string; ADDRESS: string; diff --git a/src/helper-modules/ordnance-survey/known-errors.ts b/src/helper-modules/ordnance-survey/known-errors.ts deleted file mode 100644 index 48c9d029..00000000 --- a/src/helper-modules/ordnance-survey/known-errors.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { NotFoundException } from '@nestjs/common'; -import { AxiosError } from 'axios'; - -export type KnownErrors = KnownError[]; - -type KnownError = { caseInsensitiveSubstringToFind: string; throwError: (error: AxiosError) => never }; - -export const getAddressNotFoundKnownOrdnanceSurveyError = (): KnownError => ({ - caseInsensitiveSubstringToFind: 'Address not found', - throwError: (error) => { - throw new NotFoundException('Address not found.', error); - }, -}); diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index e3cfceca..611cc5b1 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -4,8 +4,8 @@ import { RandomValueGenerator } from '@ukef-test/support/generator/random-value- import { AxiosError } from 'axios'; import { when } from 'jest-when'; import { of, throwError } from 'rxjs'; -import expectedResponse = require('./examples/example-response-for-search-places-v1-postcode.json'); -import noResultsResponse = require('./examples/example-response-for-search-places-v1-postcode-no-results.json'); +import expectedResponseData = require('./examples/example-response-for-search-places-v1-postcode.json'); +import noResultsResponseData = require('./examples/example-response-for-search-places-v1-postcode-no-results.json'); import { GEOSPATIAL } from '@ukef/constants'; @@ -23,6 +23,14 @@ describe('OrdnanceSurveyService', () => { const testKey = valueGenerator.string({ length: 10 }); const basePath = '/search/places/v1/postcode'; + const expectedResponse = of({ + data: expectedResponseData, + status: 200, + statusText: 'OK', + config: undefined, + headers: undefined, + }); + beforeEach(() => { const httpService = new HttpService(); const configService = new ConfigService(); @@ -40,26 +48,11 @@ describe('OrdnanceSurveyService', () => { const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; - it('sends a GET to the Ordnance Survey API /search endpoint with the specified request', async () => { - when(httpServiceGet) - .calledWith(...expectedHttpServiceGetArgs) - .mockReturnValueOnce( - of({ - data: expectedResponse, - status: 200, - statusText: 'OK', - config: undefined, - headers: undefined, - }), - ); - - await service.getAddressesByPostcode(testPostcode); - - expect(httpServiceGet).toHaveBeenCalledTimes(1); - expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); - }); - - it.each([ + describe.each([ + { + postcode: testPostcode, + expectedUrlQueryPart: `?postcode=${encodeURIComponent(testPostcode)}`, + }, { postcode: 'W1A 1AA', expectedUrlQueryPart: `?postcode=W1A%201AA`, @@ -68,34 +61,40 @@ describe('OrdnanceSurveyService', () => { postcode: 'W1A1AA', expectedUrlQueryPart: '?postcode=W1A1AA', }, - ])('call Ordnance Survey API with correct and safe query parameters "$expectedUrlQueryPart"', async ({ postcode, expectedUrlQueryPart }) => { - const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; - const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; + ])('test postcode $postcode', ({ postcode, expectedUrlQueryPart }) => { + it('call Ordnance Survey with the correct arguments', async () => { + const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; + const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; - when(httpServiceGet) - .calledWith(...expectedHttpServiceGetArgs) - .mockReturnValueOnce( - of({ - data: expectedResponse, - status: 200, - statusText: 'OK', - config: undefined, - headers: undefined, - }), - ); + when(httpServiceGet) + .calledWith(...expectedHttpServiceGetArgs) + .mockReturnValueOnce(expectedResponse); + await service.getAddressesByPostcode(postcode); - await service.getAddressesByPostcode(postcode); + expect(httpServiceGet).toHaveBeenCalledTimes(1); + expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); + }); - expect(httpServiceGet).toHaveBeenCalledTimes(1); - expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); + it('call Ordnance Survey returns expectedResponse', async () => { + const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; + const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; + + when(httpServiceGet) + .calledWith(...expectedHttpServiceGetArgs) + .mockReturnValueOnce(expectedResponse); + + const response = await service.getAddressesByPostcode(postcode); + + expect(response).toBe(expectedResponseData); + }); }); - it('no results - returns 200 without results', async () => { + it('returns a 200 response without results when Ordnance Survey returns no results', async () => { when(httpServiceGet) .calledWith(...expectedHttpServiceGetArgs) .mockReturnValueOnce( of({ - data: noResultsResponse, + data: noResultsResponseData, status: 200, statusText: 'OK', config: undefined, @@ -107,7 +106,7 @@ describe('OrdnanceSurveyService', () => { expect(httpServiceGet).toHaveBeenCalledTimes(1); expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); - expect(results).toBe(noResultsResponse); + expect(results).toBe(noResultsResponseData); }); it('throws an OrdnanceSurveyException if the request to Ordnance Survey fails', async () => { diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts index a079baab..f8ad1a78 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -5,9 +5,8 @@ import { KEY as ORDNANCE_SURVEY_CONFIG_KEY, OrdnanceSurveyConfig } from '@ukef/c import { GEOSPATIAL } from '@ukef/constants'; import { HttpClient } from '@ukef/modules/http/http.client'; -import { GetAddressOrdnanceSurveyResponse } from './dto/get-addresses-ordnance-survey-response.dto'; -// import { getCustomersNotFoundKnownOrdnanceSurveyError } from './known-errors'; -import { createWrapOrdnanceSurveyHttpGetErrorCallback } from './wrap-ordnance-survey-http-error-callback'; +import { GetAddressesOrdnanceSurveyResponse } from './dto/get-addresses-ordnance-survey-response.dto'; +import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; @Injectable() export class OrdnanceSurveyService { @@ -20,16 +19,15 @@ export class OrdnanceSurveyService { this.key = key; } - async getAddressesByPostcode(postcode): Promise { + async getAddressesByPostcode(postcode: string): Promise { const path = `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(this.key)}`; - const { data } = await this.httpClient.get({ + const { data } = await this.httpClient.get({ path, headers: { 'Content-Type': 'application/json' }, - onError: createWrapOrdnanceSurveyHttpGetErrorCallback({ - messageForUnknownError: `Failed to get response from Ordnance Survey API.`, - knownErrors: [], - // knownErrors: [getCustomersNotFoundKnownOrdnanceSurveyError()], // TODO: should we change 200 no results to 404? - }), + onError: (error: Error) => { + console.error('Http call error happened, error %o', error); + throw new OrdnanceSurveyException('Failed to get response from Ordnance Survey API.', error); + }, }); return data; } diff --git a/src/helper-modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts b/src/helper-modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts deleted file mode 100644 index cf1e4c1a..00000000 --- a/src/helper-modules/ordnance-survey/wrap-ordnance-survey-http-error-callback.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { AxiosError } from 'axios'; -import { ObservableInput, throwError } from 'rxjs'; - -import { OrdnanceSurveyException } from './exception/ordnance-survey.exception'; -import { KnownErrors } from './known-errors'; - -type AcbsHttpErrorCallback = (error: Error) => ObservableInput; - -export const createWrapOrdnanceSurveyHttpGetErrorCallback = - ({ messageForUnknownError, knownErrors }: { messageForUnknownError: string; knownErrors: KnownErrors }): AcbsHttpErrorCallback => - (error: Error) => { - let errorString; - if (error instanceof AxiosError && error.response) { - if (typeof error.response.data === 'object') { - errorString = JSON.stringify(error.response.data); - } - if (typeof error.response.data === 'string') { - errorString = error.response.data; - } - if (errorString) { - const errorStringInLowerCase = errorString.toLowerCase(); - - knownErrors.forEach(({ caseInsensitiveSubstringToFind, throwError }) => { - if (errorStringInLowerCase.includes(caseInsensitiveSubstringToFind.toLowerCase())) { - return throwError(error); - } - }); - } - } - - return throwError(() => new OrdnanceSurveyException(messageForUnknownError, error)); - }; diff --git a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts similarity index 90% rename from src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts rename to src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts index 6202fdd1..b344a25b 100644 --- a/src/modules/geospatial/dto/get-address-by-postcode-query.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts @@ -4,7 +4,7 @@ import { Matches, MaxLength, MinLength } from 'class-validator'; const UK_POSTCODE = /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; -export class GetAddressByPostcodeQueryDto { +export class GetAddressesByPostcodeQueryDto { @ApiProperty({ example: GEOSPATIAL.EXAMPLES.POSTCODE, description: 'Postcode to search for', diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 5b7fe670..95813d93 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -1,7 +1,7 @@ import { Controller, Get, Query } from '@nestjs/common'; import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; -import { GetAddressByPostcodeQueryDto } from './dto/get-address-by-postcode-query.dto'; +import { GetAddressesByPostcodeQueryDto } from './dto/get-addresses-by-postcode-query.dto'; import { GetAddressesResponse, GetAddressesResponseItem } from './dto/get-addresses-response.dto'; import { GeospatialService } from './geospatial.service'; @@ -23,7 +23,7 @@ export class GeospatialController { @ApiNotFoundResponse({ description: 'Customer not found.', }) - getAddressesByPostcode(@Query() query: GetAddressByPostcodeQueryDto): Promise { + getAddressesByPostcode(@Query() query: GetAddressesByPostcodeQueryDto): Promise { return this.geospatialService.getAddressesByPostcode(query.postcode); } } diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index 2e07562b..b566e7f0 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { ENUMS } from '@ukef/constants'; -import { GetAddressOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; +import { GetAddressesOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; import { GetAddressesResponse } from './dto/get-addresses-response.dto'; @@ -11,7 +11,7 @@ export class GeospatialService { async getAddressesByPostcode(postcode: string): Promise { const addresses = []; - const response: GetAddressOrdnanceSurveyResponse = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); + const response: GetAddressesOrdnanceSurveyResponse = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); if (!response?.results) { return []; diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index c0ed8415..6a8c8e22 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -1,7 +1,7 @@ import { ENUMS, GEOSPATIAL } from '@ukef/constants'; -import { GetAddressOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; +import { GetAddressesOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; import { OrdnanceSurveyAuthErrorResponse } from '@ukef/helper-modules/ordnance-survey/dto/ordnance-survey-auth-error-response.dto'; -import { GetAddressByPostcodeQueryDto } from '@ukef/modules/geospatial/dto/get-address-by-postcode-query.dto'; +import { GetAddressesByPostcodeQueryDto } from '@ukef/modules/geospatial/dto/get-addresses-by-postcode-query.dto'; import { GetAddressesResponse } from '@ukef/modules/geospatial/dto/get-addresses-response.dto'; import { AbstractGenerator } from './abstract-generator'; @@ -28,19 +28,19 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator ({ postcode: postcode || v.POSTCODE }) as GetAddressByPostcodeQueryDto); + const requests: GetAddressesByPostcodeQueryDto[] = values.map((v) => ({ postcode: postcode || v.POSTCODE }) as GetAddressesByPostcodeQueryDto); - const ordnanceSurveyPath: string[] = values.map((v) => { + const ordnanceSurveyPaths: string[] = values.map((v) => { const usePostcode = postcode || v.POSTCODE; return `/search/places/v1/postcode?postcode=${encodeURIComponent(usePostcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(useKey)}`; }); - const mdmPath: string[] = values.map((v) => { + const mdmPaths: string[] = values.map((v) => { const usePostcode = postcode || v.POSTCODE; return `/api/v1/geospatial/addresses/postcode?postcode=${usePostcode}`; }); - const getAddressByPostcodeResponse: GetAddressesResponse[] = values.map((v) => [ + const getAddressesByPostcodeResponse: GetAddressesResponse[] = values.map((v) => [ { organisationName: v.ORGANISATION_NAME, addressLine1: `${v.BUILDING_NAME} ${v.BUILDING_NUMBER} ${v.THOROUGHFARE_NAME}`, @@ -52,9 +52,9 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator response[0]); + const getAddressesByPostcodeMultipleResponse = getAddressesByPostcodeResponse.map((response) => response[0]); - const getAddressOrdnanceSurveyResponse: GetAddressOrdnanceSurveyResponse[] = values.map((v) => ({ + const getAddressesOrdnanceSurveyResponse: GetAddressesOrdnanceSurveyResponse[] = values.map((v) => ({ header: { uri: 'test', query: 'test', @@ -109,7 +109,7 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator ({ + const getAddressesOrdnanceSurveyEmptyResponse: GetAddressesOrdnanceSurveyResponse = { header: { uri: 'test', query: 'test', @@ -176,9 +176,9 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Thu, 25 Apr 2024 09:36:52 +0100 Subject: [PATCH 25/56] feat(DTFS2-7052): moving uk postcode regex to constants and doc improvements --- src/constants/geospatial.constant.ts | 4 ++++ .../geospatial/dto/get-addresses-by-postcode-query.dto.ts | 7 ++++--- test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap | 4 ++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/constants/geospatial.constant.ts b/src/constants/geospatial.constant.ts index 08bd74c2..82c471db 100644 --- a/src/constants/geospatial.constant.ts +++ b/src/constants/geospatial.constant.ts @@ -6,4 +6,8 @@ export const GEOSPATIAL = { EXAMPLES: { POSTCODE: 'SW1A 2AQ', }, + REGEX: { + // UK postcode regex is from DTFS project and slightly optimised by lint. + UK_POSTCODE: /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/, + }, }; diff --git a/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts index b344a25b..26f62be0 100644 --- a/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts @@ -2,15 +2,16 @@ import { ApiProperty } from '@nestjs/swagger'; import { GEOSPATIAL } from '@ukef/constants'; import { Matches, MaxLength, MinLength } from 'class-validator'; -const UK_POSTCODE = /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/; - export class GetAddressesByPostcodeQueryDto { @ApiProperty({ example: GEOSPATIAL.EXAMPLES.POSTCODE, description: 'Postcode to search for', + minLength: 5, + maxLength: 8, + pattern: GEOSPATIAL.REGEX.UK_POSTCODE.source, }) @MinLength(5) @MaxLength(8) - @Matches(UK_POSTCODE) + @Matches(GEOSPATIAL.REGEX.UK_POSTCODE) public postcode: string; } diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index c69ff11b..d08cd5fe 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -500,6 +500,10 @@ paths: example: SW1A 2AQ description: Postcode to search for schema: + minLength: 5 + maxLength: 8 + pattern: >- + ^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$ type: string responses: '200': From 5a0ee9342ee2d8505e0e8c08e26b8df67ce37941 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 09:38:06 +0100 Subject: [PATCH 26/56] feat(DTFS2-7052): comments copy and variable name improvements --- src/helper-modules/ordnance-survey/ordnance-survey.service.ts | 1 - src/modules/geospatial/geospatial.service.ts | 2 +- test/support/generator/get-geospatial-addresses-generator.ts | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts index f8ad1a78..8da5ee13 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.ts @@ -25,7 +25,6 @@ export class OrdnanceSurveyService { path, headers: { 'Content-Type': 'application/json' }, onError: (error: Error) => { - console.error('Http call error happened, error %o', error); throw new OrdnanceSurveyException('Failed to get response from Ordnance Survey API.', error); }, }); diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index b566e7f0..cf2199a8 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -18,7 +18,7 @@ export class GeospatialService { } response.results.forEach((item) => { - // Item can have key DPA or LPI, get data dynamically, even if we expect key to always be DPA. + // Item can have key DPA or LPI, so we get data dynamically, even if we expect key to always be DPA. const item_data = item[Object.keys(item)[0]]; addresses.push({ organisationName: item_data.ORGANISATION_NAME || null, diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index 6a8c8e22..51522d9f 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -109,7 +109,7 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Thu, 25 Apr 2024 09:43:10 +0100 Subject: [PATCH 27/56] feat(DTFS2-7052): typescript type improvement in api-test helper --- test/support/api.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/support/api.ts b/test/support/api.ts index f86625d2..6a077403 100644 --- a/test/support/api.ts +++ b/test/support/api.ts @@ -1,6 +1,7 @@ import { AUTH } from '@ukef/constants'; import { ENVIRONMENT_VARIABLES } from '@ukef-test/support/environment-variables'; import request from 'supertest'; +import TestAgent from 'supertest/lib/agent'; import { App } from './app'; @@ -33,7 +34,7 @@ export class Api { return this.app.destroy(); } - private request(): any { + private request(): TestAgent { return request(this.app.getHttpServer()); } From de7a0e59450dc7f0f4ea57bebd8251f560a5b36b Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 10:13:51 +0100 Subject: [PATCH 28/56] feat(DTFS2-7052): moving address examples to constants --- src/constants/geospatial.constant.ts | 3 +++ src/modules/geospatial/dto/get-addresses-response.dto.ts | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/constants/geospatial.constant.ts b/src/constants/geospatial.constant.ts index 82c471db..567b89d2 100644 --- a/src/constants/geospatial.constant.ts +++ b/src/constants/geospatial.constant.ts @@ -5,6 +5,9 @@ export const GEOSPATIAL = { }, EXAMPLES: { POSTCODE: 'SW1A 2AQ', + ORGANISATION_NAME: 'CHURCHILL MUSEUM & CABINET WAR ROOMS', + ADDRESS_LINE_1: 'CLIVE STEPS KING CHARLES STREET', + LOCALITY: 'LONDON', }, REGEX: { // UK postcode regex is from DTFS project and slightly optimised by lint. diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index b458bf19..4780c542 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -6,13 +6,13 @@ export type GetAddressesResponse = GetAddressesResponseItem[]; export class GetAddressesResponseItem { @ApiProperty({ description: 'Organisation name if available', - example: 'CHURCHILL MUSEUM & CABINET WAR ROOMS', + example: GEOSPATIAL.EXAMPLES.ORGANISATION_NAME, }) readonly organisationName: string | null; @ApiProperty({ description: 'Address line 1', - example: 'CLIVE STEPS KING CHARLES STREET', + example: GEOSPATIAL.EXAMPLES.ADDRESS_LINE_1, }) readonly addressLine1: string; @@ -30,7 +30,7 @@ export class GetAddressesResponseItem { @ApiProperty({ description: 'Locality, Town', - example: 'LONDON', + example: GEOSPATIAL.EXAMPLES.LOCALITY, }) readonly locality: string | null; From c7ac787dba058ab17b95865681d2b9afe7a4e005 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 10:16:25 +0100 Subject: [PATCH 29/56] feat(DTFS2-7052): updating spec snapshot --- test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index d08cd5fe..ee1a49e7 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -1146,7 +1146,7 @@ components: addressLine1: type: string description: Address line 1 - example: CLIVE STEPS KING CHARLES STREET + example: CLIVE STEPS KING CHARLES STREET addressLine2: type: string description: Address line 2 From 14ea1e6e2e7893bb136e352f228d73a0ac54b1b5 Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:25:06 +0100 Subject: [PATCH 30/56] Update src/modules/geospatial/dto/get-addresses-response.dto.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/dto/get-addresses-response.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index 4780c542..1fb6c90c 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -19,6 +19,7 @@ export class GetAddressesResponseItem { @ApiProperty({ description: 'Address line 2', example: null, + nullable: true, }) readonly addressLine2: string | null; From 1c0bf2c4135eca7474894f1edb4ec929ce482d53 Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:26:04 +0100 Subject: [PATCH 31/56] Update src/modules/geospatial/dto/get-addresses-response.dto.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/dto/get-addresses-response.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index 1fb6c90c..fbdf2344 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -26,6 +26,7 @@ export class GetAddressesResponseItem { @ApiProperty({ description: 'Address line 3', example: null, + nullable: true, }) readonly addressLine3: string | null; From 129b364a0913632a98072d2047ed410659a81642 Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:26:58 +0100 Subject: [PATCH 32/56] Update src/modules/geospatial/dto/get-addresses-response.dto.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/dto/get-addresses-response.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index fbdf2344..cace3bf8 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -39,6 +39,7 @@ export class GetAddressesResponseItem { @ApiProperty({ description: 'Postcode', example: GEOSPATIAL.EXAMPLES.POSTCODE, + nullable: true, }) readonly postalCode: string | null; From 273300312e40e66a634c42590cc0f370fb0c527b Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:27:32 +0100 Subject: [PATCH 33/56] Update src/modules/geospatial/dto/get-addresses-response.dto.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/dto/get-addresses-response.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index cace3bf8..fce2bcdd 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -47,6 +47,7 @@ export class GetAddressesResponseItem { description: 'Country of address record', example: ENUMS.GEOSPATIAL_COUNTRIES.E, enum: ENUMS.GEOSPATIAL_COUNTRIES, + nullable: true, }) readonly country: string | null; } From fa73657434c73236ae9efa93036283cc110b4c86 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 10:28:57 +0100 Subject: [PATCH 34/56] feat(DTFS2-7052): updating api spec definition --- src/modules/geospatial/dto/get-addresses-response.dto.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index fce2bcdd..7bd22301 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -5,8 +5,9 @@ export type GetAddressesResponse = GetAddressesResponseItem[]; export class GetAddressesResponseItem { @ApiProperty({ - description: 'Organisation name if available', + description: 'Organisation name, if available', example: GEOSPATIAL.EXAMPLES.ORGANISATION_NAME, + nullable: true, }) readonly organisationName: string | null; From 3e215d726496ffb206c1e1b954efc9c27c4ec685 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 10:30:28 +0100 Subject: [PATCH 35/56] feat(DTFS2-7052): updating api spec snapshot --- test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index ee1a49e7..c6792f2a 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -1141,8 +1141,9 @@ components: properties: organisationName: type: string - description: Organisation name if available + description: Organisation name, if available example: CHURCHILL MUSEUM & CABINET WAR ROOMS + nullable: true addressLine1: type: string description: Address line 1 @@ -1151,10 +1152,12 @@ components: type: string description: Address line 2 example: null + nullable: true addressLine3: type: string description: Address line 3 example: null + nullable: true locality: type: string description: Locality, Town @@ -1163,6 +1166,7 @@ components: type: string description: Postcode example: SW1A 2AQ + nullable: true country: type: string description: Country of address record @@ -1172,6 +1176,7 @@ components: - Scotland - Wales - Northern Ireland + nullable: true required: - organisationName - addressLine1 From 70e5861a5b2f63f0c091c906942e6b68e750dda7 Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:34:22 +0100 Subject: [PATCH 36/56] Update src/modules/geospatial/geospatial.controller.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 95813d93..6e015641 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -13,7 +13,8 @@ export class GeospatialController { @Get('addresses/postcode') @ApiOperation({ summary: - "A search based on a property's postcode. Will accept a full valid postcode. Returns addresses from Ordnance survey Delivery Point Address (DPA) system.", + "A search based on a property's postcode. Will accept a full valid postcode. Returns addresses from Ordnance Survey Delivery Point Address (DPA) system.", +`` }) @ApiResponse({ status: 200, From 021bdd4ffd8583e0547a388e3ecc65bb69728abe Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:35:05 +0100 Subject: [PATCH 37/56] Update src/modules/geospatial/geospatial.controller.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 6e015641..9dba9e97 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -22,7 +22,7 @@ export class GeospatialController { type: [GetAddressesResponseItem], }) @ApiNotFoundResponse({ - description: 'Customer not found.', + description: 'Postcode not found.', }) getAddressesByPostcode(@Query() query: GetAddressesByPostcodeQueryDto): Promise { return this.geospatialService.getAddressesByPostcode(query.postcode); From d5468340525702a8dadc4625a05e1408941f6d2b Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:35:42 +0100 Subject: [PATCH 38/56] Update src/modules/geospatial/geospatial.controller.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index 700914e2..9ff0b25e 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -32,7 +32,7 @@ describe('GeospatialController', () => { describe('getAddressesByPostcode()', () => { const postcode = GEOSPATIAL.EXAMPLES.POSTCODE; - it('returns address for postcode', async () => { + it('returns a single address for the postcode when the service returns a single address', async () => { when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressByPostcodeResponse[0]); const response = await controller.getAddressesByPostcode({ postcode }); From 5cc241295bed81b5a16f158fc68bdda8383b919d Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:37:02 +0100 Subject: [PATCH 39/56] Update src/modules/geospatial/geospatial.controller.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.controller.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index 9ff0b25e..aca862af 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -37,7 +37,7 @@ describe('GeospatialController', () => { const response = await controller.getAddressesByPostcode({ postcode }); - expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalled(); + expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalledTimes(1); expect(response).toEqual(getAddressByPostcodeResponse[0]); }); From ad617e22d5928fd4b9dc2d2272565ed27c9867dc Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:39:58 +0100 Subject: [PATCH 40/56] Update test/geospatial/get-address-by-postcode.api-test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- test/geospatial/get-address-by-postcode.api-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts index 64f0283b..ed416c41 100644 --- a/test/geospatial/get-address-by-postcode.api-test.ts +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -44,7 +44,7 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { // MDM auth tests withClientAuthenticationTests({ givenTheRequestWouldOtherwiseSucceed: () => { - requestToGetAddressesByPostcode(mdmPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); }, makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPath[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), }); From 67d682e53fdfa470c60a2154550ca95a7092e20e Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:43:22 +0100 Subject: [PATCH 41/56] Update src/modules/geospatial/geospatial.service.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- src/modules/geospatial/geospatial.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index 2b34b577..44355a66 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -65,7 +65,7 @@ describe('GeospatialService', () => { }); it('returns addressLine1 formatted correctly even if middle value is missing', async () => { - const [modifiedOrdnanceSurveyResponse] = getAddressOrdnanceSurveyResponse; + const [modifiedOrdnanceSurveyResponse] = structuredClone(getAddressOrdnanceSurveyResponse); modifiedOrdnanceSurveyResponse.results[0].DPA.BUILDING_NUMBER = null; const address = modifiedOrdnanceSurveyResponse.results[0].DPA; when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(modifiedOrdnanceSurveyResponse); From 708533badb0ee88754e50b07c8af7241cea831d4 Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 10:45:25 +0100 Subject: [PATCH 42/56] Update test/geospatial/get-address-by-postcode.api-test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- test/geospatial/get-address-by-postcode.api-test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts index ed416c41..081fadb7 100644 --- a/test/geospatial/get-address-by-postcode.api-test.ts +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -67,7 +67,7 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { expect(body).toStrictEqual(getAddressByPostcodeMultipleResponse); }); - it('returns a empty 200 response if Ordnance Survey API returns a 200 without results', async () => { + it('returns an empty 200 response if Ordnance Survey API returns a 200 without results', async () => { requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyEmptyResponse[0]); const { status, body } = await api.get(mdmPath[0]); From 7d15b07ef4126f99ffcf6189deac2b2391633edd Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 10:49:50 +0100 Subject: [PATCH 43/56] feat(DTFS2-7052): actioning PR comments --- .../geospatial/dto/get-addresses-response.dto.ts | 3 ++- src/modules/geospatial/geospatial.service.test.ts | 14 +++++++------- src/modules/mdm.module.ts | 3 --- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index 7bd22301..87e997a1 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -32,8 +32,9 @@ export class GetAddressesResponseItem { readonly addressLine3: string | null; @ApiProperty({ - description: 'Locality, Town', + description: 'Locality or town', example: GEOSPATIAL.EXAMPLES.LOCALITY, + nullable: true, }) readonly locality: string | null; diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index 2b34b577..a656837d 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -13,16 +13,16 @@ describe('GeospatialService', () => { let service: GeospatialService; let configServiceGet: jest.Mock; - let informaticaServiceGetAddressesByPostcode: jest.Mock; + let ordnanceSurveyServiceGetAddressesByPostcode: jest.Mock; beforeEach(() => { const configService = new ConfigService(); configServiceGet = jest.fn().mockReturnValue({ key: valueGenerator.word() }); configService.get = configServiceGet; - informaticaServiceGetAddressesByPostcode = jest.fn(); + ordnanceSurveyServiceGetAddressesByPostcode = jest.fn(); const ordnanceSurveyService = new OrdnanceSurveyService(null, configService); - ordnanceSurveyService.getAddressesByPostcode = informaticaServiceGetAddressesByPostcode; + ordnanceSurveyService.getAddressesByPostcode = ordnanceSurveyServiceGetAddressesByPostcode; resetAllWhenMocks(); service = new GeospatialService(ordnanceSurveyService); @@ -41,7 +41,7 @@ describe('GeospatialService', () => { const postcode = getAddressByPostcodeResponse[0][0].postalCode; it('returns a single address from the backend service', async () => { - when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyResponse[0]); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyResponse[0]); const response = await service.getAddressesByPostcode(postcode); @@ -49,7 +49,7 @@ describe('GeospatialService', () => { }); it('returns multiple addressess from the backend service', async () => { - when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyMultipleResponse); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyMultipleResponse); const response = await service.getAddressesByPostcode(postcode); @@ -57,7 +57,7 @@ describe('GeospatialService', () => { }); it('can handle empty backend response', async () => { - when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyEmptyResponse[0]); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyEmptyResponse[0]); const response = await service.getAddressesByPostcode(postcode); @@ -68,7 +68,7 @@ describe('GeospatialService', () => { const [modifiedOrdnanceSurveyResponse] = getAddressOrdnanceSurveyResponse; modifiedOrdnanceSurveyResponse.results[0].DPA.BUILDING_NUMBER = null; const address = modifiedOrdnanceSurveyResponse.results[0].DPA; - when(informaticaServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(modifiedOrdnanceSurveyResponse); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(modifiedOrdnanceSurveyResponse); const response = await service.getAddressesByPostcode(postcode); diff --git a/src/modules/mdm.module.ts b/src/modules/mdm.module.ts index 9d3b7bfb..790a1510 100644 --- a/src/modules/mdm.module.ts +++ b/src/modules/mdm.module.ts @@ -1,7 +1,6 @@ import { Module } from '@nestjs/common'; import { AuthModule } from '@ukef/auth/auth.module'; import { DatabaseModule } from '@ukef/database/database.module'; -import { OrdnanceSurveyModule } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.module'; import { CurrenciesModule } from '@ukef/modules/currencies/currencies.module'; import { CustomersModule } from '@ukef/modules/customers/customers.module'; import { ExposurePeriodModule } from '@ukef/modules/exposure-period/exposure-period.module'; @@ -28,7 +27,6 @@ import { YieldRatesModule } from '@ukef/modules/yield-rates/yield-rates.module'; PremiumSchedulesModule, SectorIndustriesModule, YieldRatesModule, - OrdnanceSurveyModule, GeospatialModule, ], exports: [ @@ -44,7 +42,6 @@ import { YieldRatesModule } from '@ukef/modules/yield-rates/yield-rates.module'; PremiumSchedulesModule, SectorIndustriesModule, YieldRatesModule, - OrdnanceSurveyModule, GeospatialModule, ], }) From 15743c043b478d660097194f54c396eebe2c352f Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 11:28:16 +0100 Subject: [PATCH 44/56] feat(DTFS2-7052): updating API spec --- test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index c6792f2a..3bcf1ea2 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -491,7 +491,7 @@ paths: operationId: GeospatialController_getAddressesByPostcode summary: >- A search based on a property's postcode. Will accept a full valid - postcode. Returns addresses from Ordnance survey Delivery Point Address + postcode. Returns addresses from Ordnance Survey Delivery Point Address (DPA) system. parameters: - name: postcode @@ -515,7 +515,7 @@ paths: items: $ref: '#/components/schemas/GetAddressesResponseItem' '404': - description: Customer not found. + description: Postcode not found. tags: - geospatial info: @@ -1160,8 +1160,9 @@ components: nullable: true locality: type: string - description: Locality, Town + description: Locality or town example: LONDON + nullable: true postalCode: type: string description: Postcode From c020867afb451723a8f7d361cb33ef54566355ad Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 12:06:48 +0100 Subject: [PATCH 45/56] feat(DTFS2-7052): changing variables to use plural --- .../geospatial/geospatial.controller.test.ts | 10 ++-- .../geospatial/geospatial.service.test.ts | 24 ++++----- .../get-address-by-postcode.api-test.ts | 50 +++++++++---------- .../get-geospatial-addresses-generator.ts | 28 +++++------ 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index aca862af..d125cf04 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -12,7 +12,7 @@ describe('GeospatialController', () => { let controller: GeospatialController; const valueGenerator = new RandomValueGenerator(); - const { getAddressByPostcodeResponse, getAddressByPostcodeMultipleResponse } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ + const { getAddressesByPostcodeResponse, getAddressesByPostcodeMultipleResponse } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ numberToGenerate: 2, }); @@ -33,21 +33,21 @@ describe('GeospatialController', () => { const postcode = GEOSPATIAL.EXAMPLES.POSTCODE; it('returns a single address for the postcode when the service returns a single address', async () => { - when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressByPostcodeResponse[0]); + when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesByPostcodeResponse[0]); const response = await controller.getAddressesByPostcode({ postcode }); expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalledTimes(1); - expect(response).toEqual(getAddressByPostcodeResponse[0]); + expect(response).toEqual(getAddressesByPostcodeResponse[0]); }); it('returns multiple addresses for the postcode when the service returns multiple addresses', async () => { - when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressByPostcodeMultipleResponse); + when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesByPostcodeMultipleResponse); const response = await controller.getAddressesByPostcode({ postcode }); expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalledTimes(1); - expect(response).toEqual(getAddressByPostcodeMultipleResponse); + expect(response).toEqual(getAddressesByPostcodeMultipleResponse); }); it('returns an empty response for the postcode when the service returns an empty response', async () => { diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index 1cd89fdb..1718118f 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -30,34 +30,34 @@ describe('GeospatialService', () => { describe('getAddressesByPostcode', () => { const { - getAddressByPostcodeResponse, - getAddressByPostcodeMultipleResponse, - getAddressOrdnanceSurveyResponse, - getAddressOrdnanceSurveyMultipleResponse, - getAddressOrdnanceSurveyEmptyResponse, + getAddressesByPostcodeResponse, + getAddressesByPostcodeMultipleResponse, + getAddressesOrdnanceSurveyResponse, + getAddressesOrdnanceSurveyMultipleMatchingAddressesResponse, + getAddressesOrdnanceSurveyEmptyResponse, } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ numberToGenerate: 2, }); - const postcode = getAddressByPostcodeResponse[0][0].postalCode; + const postcode = getAddressesByPostcodeResponse[0][0].postalCode; it('returns a single address from the backend service', async () => { - when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyResponse[0]); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesOrdnanceSurveyResponse[0]); const response = await service.getAddressesByPostcode(postcode); - expect(response).toEqual(getAddressByPostcodeResponse[0]); + expect(response).toEqual(getAddressesByPostcodeResponse[0]); }); it('returns multiple addressess from the backend service', async () => { - when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyMultipleResponse); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesOrdnanceSurveyMultipleMatchingAddressesResponse); const response = await service.getAddressesByPostcode(postcode); - expect(response).toEqual(getAddressByPostcodeMultipleResponse); + expect(response).toEqual(getAddressesByPostcodeMultipleResponse); }); it('can handle empty backend response', async () => { - when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressOrdnanceSurveyEmptyResponse[0]); + when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesOrdnanceSurveyEmptyResponse[0]); const response = await service.getAddressesByPostcode(postcode); @@ -65,7 +65,7 @@ describe('GeospatialService', () => { }); it('returns addressLine1 formatted correctly even if middle value is missing', async () => { - const [modifiedOrdnanceSurveyResponse] = structuredClone(getAddressOrdnanceSurveyResponse); + const [modifiedOrdnanceSurveyResponse] = structuredClone(getAddressesOrdnanceSurveyResponse); modifiedOrdnanceSurveyResponse.results[0].DPA.BUILDING_NUMBER = null; const address = modifiedOrdnanceSurveyResponse.results[0].DPA; when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(modifiedOrdnanceSurveyResponse); diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts index 081fadb7..37002809 100644 --- a/test/geospatial/get-address-by-postcode.api-test.ts +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -12,13 +12,13 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { let api: Api; const { - ordnanceSurveyPath, - mdmPath, - getAddressByPostcodeResponse, - getAddressByPostcodeMultipleResponse, - getAddressOrdnanceSurveyResponse, - getAddressOrdnanceSurveyEmptyResponse, - getAddressOrdnanceSurveyMultipleResponse, + ordnanceSurveyPaths, + mdmPaths, + getAddressesByPostcodeResponse, + getAddressesByPostcodeMultipleResponse, + getAddressesOrdnanceSurveyResponse, + getAddressesOrdnanceSurveyEmptyResponse, + getAddressesOrdnanceSurveyMultipleMatchingAddressesResponse, ordnanceSurveyAuthErrorResponse, } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ postcode: GEOSPATIAL.EXAMPLES.POSTCODE, @@ -44,42 +44,42 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { // MDM auth tests withClientAuthenticationTests({ givenTheRequestWouldOtherwiseSucceed: () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(200, getAddressesOrdnanceSurveyResponse[0]); }, - makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPath[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), + makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPaths[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), }); it('returns a 200 response with the address if it is returned by Ordnance Survey API', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyResponse[0]); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(200, getAddressesOrdnanceSurveyResponse[0]); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(200); - expect(body).toStrictEqual(getAddressByPostcodeResponse[0]); + expect(body).toStrictEqual(getAddressesByPostcodeResponse[0]); }); it('returns a 200 response with the addresses if they are returned by Ordnance Survey API', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyMultipleResponse); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(200, getAddressesOrdnanceSurveyMultipleMatchingAddressesResponse); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(200); - expect(body).toStrictEqual(getAddressByPostcodeMultipleResponse); + expect(body).toStrictEqual(getAddressesByPostcodeMultipleResponse); }); it('returns an empty 200 response if Ordnance Survey API returns a 200 without results', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(200, getAddressOrdnanceSurveyEmptyResponse[0]); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(200, getAddressesOrdnanceSurveyEmptyResponse[0]); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(200); expect(body).toStrictEqual([]); }); it('returns a 500 response if Ordnance Survey API returns a status code 401', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(401); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(401); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(500); expect(body).toStrictEqual({ @@ -89,9 +89,9 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { }); it('returns a 500 response if Ordnance Survey API returns a status code 404', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(404); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(404); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(500); expect(body).toStrictEqual({ @@ -101,9 +101,9 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { }); it('returns a 500 response if Ordnance Survey API times out', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).delay(TIME_EXCEEDING_ORDNANCE_SURVEY_TIMEOUT).reply(200, getAddressOrdnanceSurveyResponse[0]); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).delay(TIME_EXCEEDING_ORDNANCE_SURVEY_TIMEOUT).reply(200, getAddressesOrdnanceSurveyResponse[0]); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(500); expect(body).toStrictEqual({ @@ -113,9 +113,9 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { }); it('returns a 500 response if Ordnance Survey API returns error', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPath[0]).reply(401, ordnanceSurveyAuthErrorResponse); + requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(401, ordnanceSurveyAuthErrorResponse); - const { status, body } = await api.get(mdmPath[0]); + const { status, body } = await api.get(mdmPaths[0]); expect(status).toBe(500); expect(body).toStrictEqual({ diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index 51522d9f..02102b34 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -189,13 +189,13 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Thu, 25 Apr 2024 14:43:31 +0100 Subject: [PATCH 46/56] Update test/support/generator/get-geospatial-addresses-generator.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- test/support/generator/get-geospatial-addresses-generator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index 02102b34..347cb262 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -14,10 +14,10 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Thu, 25 Apr 2024 14:44:54 +0100 Subject: [PATCH 47/56] Update src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- .../ordnance-survey/ordnance-survey.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index 611cc5b1..b4f0d769 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -62,7 +62,7 @@ describe('OrdnanceSurveyService', () => { expectedUrlQueryPart: '?postcode=W1A1AA', }, ])('test postcode $postcode', ({ postcode, expectedUrlQueryPart }) => { - it('call Ordnance Survey with the correct arguments', async () => { + it('calls Ordnance Survey with the correct arguments', async () => { const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; From 370c3422dd404039c5c5f94169508a986169c47d Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 14:45:29 +0100 Subject: [PATCH 48/56] Update src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- .../ordnance-survey/ordnance-survey.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index b4f0d769..4202d607 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -89,7 +89,7 @@ describe('OrdnanceSurveyService', () => { }); }); - it('returns a 200 response without results when Ordnance Survey returns no results', async () => { + it('returns no results without erroring when Ordnance Survey returns a 200 without results', async () => { when(httpServiceGet) .calledWith(...expectedHttpServiceGetArgs) .mockReturnValueOnce( From 90eb4d385cf2988b48d3cce89dc7ea4099593b0c Mon Sep 17 00:00:00 2001 From: Audrius Date: Thu, 25 Apr 2024 14:45:44 +0100 Subject: [PATCH 49/56] Update src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts Co-authored-by: oscar-richardson-softwire <116292912+oscar-richardson-softwire@users.noreply.github.com> --- .../ordnance-survey/ordnance-survey.service.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index 4202d607..2bc641f9 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -75,7 +75,7 @@ describe('OrdnanceSurveyService', () => { expect(httpServiceGet).toHaveBeenCalledWith(...expectedHttpServiceGetArgs); }); - it('call Ordnance Survey returns expectedResponse', async () => { + it('returns the results when Ordnance Survey returns a 200 with results', async () => { const expectedPath = `${basePath}${expectedUrlQueryPart}&lr=EN&key=${encodeURIComponent(testKey)}`; const expectedHttpServiceGetArgs: [string, object] = [expectedPath, { headers: { 'Content-Type': 'application/json' } }]; From 3ca57f0cfdbddf1ac1285164b0aa2c214e04a429 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Thu, 25 Apr 2024 15:12:18 +0100 Subject: [PATCH 50/56] feat(DTFS2-7049): adding new env variables to docker-compose.yml --- docker-compose.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 159be608..b662d6e1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -33,6 +33,10 @@ services: APIM_INFORMATICA_PASSWORD: APIM_INFORMATICA_MAX_REDIRECTS: APIM_INFORMATICA_TIMEOUT: + ORDNANCE_SURVEY_URL: + ORDNANCE_SURVEY_KEY: + ORDNANCE_SURVEY_MAX_REDIRECTS: + ORDNANCE_SURVEY_TIMEOUT: API_KEY: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:${PORT}"] From 32aa1ef3e41f4cf5e56ae1952b710d4e8a4fc1da Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 29 Apr 2024 14:04:57 +0100 Subject: [PATCH 51/56] feat(DTFS2-7052): removing unused class GetSearchPostcodeOrdnanceSurveyQueryDto --- .../dto/get-search-postcode-ordnance-survey-query.dto.ts | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 src/helper-modules/ordnance-survey/dto/get-search-postcode-ordnance-survey-query.dto.ts diff --git a/src/helper-modules/ordnance-survey/dto/get-search-postcode-ordnance-survey-query.dto.ts b/src/helper-modules/ordnance-survey/dto/get-search-postcode-ordnance-survey-query.dto.ts deleted file mode 100644 index 8f8ea0f2..00000000 --- a/src/helper-modules/ordnance-survey/dto/get-search-postcode-ordnance-survey-query.dto.ts +++ /dev/null @@ -1,3 +0,0 @@ -export class GetSearchPostcodeOrdnanceSurveyQueryDto { - public postcode: string; -} From 38939db77917c9679311e6a793bd339b5f817a26 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 13 May 2024 09:23:01 +0100 Subject: [PATCH 52/56] feat(DTFS2-7052): code style improvements based on PR feedback --- .env.sample | 4 ++-- src/config/informatica.config.test.ts | 2 +- src/config/informatica.config.ts | 2 +- src/config/ordnance-survey.config.test.ts | 2 +- src/config/ordnance-survey.config.ts | 2 +- src/constants/enums/geospatialCountries.ts | 2 +- src/constants/geospatial.constant.ts | 1 + src/helper-modules/ordnance-survey/ordnance-survey.module.ts | 4 ++-- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/.env.sample b/.env.sample index 90bced05..536e7f69 100644 --- a/.env.sample +++ b/.env.sample @@ -38,11 +38,11 @@ APIM_INFORMATICA_URL= APIM_INFORMATICA_USERNAME= APIM_INFORMATICA_PASSWORD= APIM_INFORMATICA_MAX_REDIRECTS= -APIM_INFORMATICA_TIMEOUT= +APIM_INFORMATICA_TIMEOUT= # in milliseconds # ORDNANCE SURVEY # Use .uk domain, instead of .co.uk ORDNANCE_SURVEY_URL= ORDNANCE_SURVEY_KEY= ORDNANCE_SURVEY_MAX_REDIRECTS= -ORDNANCE_SURVEY_TIMEOUT= +ORDNANCE_SURVEY_TIMEOUT= # in milliseconds diff --git a/src/config/informatica.config.test.ts b/src/config/informatica.config.test.ts index 97cf8d24..84a59cad 100644 --- a/src/config/informatica.config.test.ts +++ b/src/config/informatica.config.test.ts @@ -31,7 +31,7 @@ describe('informaticaConfig', () => { { configPropertyName: 'timeout', environmentVariableName: 'APIM_INFORMATICA_TIMEOUT', - defaultConfigValue: 30000, + defaultConfigValue: 30000, // in milliseconds }, ]; diff --git a/src/config/informatica.config.ts b/src/config/informatica.config.ts index fdf9dc67..6860bddb 100644 --- a/src/config/informatica.config.ts +++ b/src/config/informatica.config.ts @@ -18,6 +18,6 @@ export default registerAs( username: process.env.APIM_INFORMATICA_USERNAME, password: process.env.APIM_INFORMATICA_PASSWORD, maxRedirects: getIntConfig(process.env.APIM_INFORMATICA_MAX_REDIRECTS, 5), - timeout: getIntConfig(process.env.APIM_INFORMATICA_TIMEOUT, 30000), + timeout: getIntConfig(process.env.APIM_INFORMATICA_TIMEOUT, 30000), // in milliseconds }), ); diff --git a/src/config/ordnance-survey.config.test.ts b/src/config/ordnance-survey.config.test.ts index 5b22020e..f077012d 100644 --- a/src/config/ordnance-survey.config.test.ts +++ b/src/config/ordnance-survey.config.test.ts @@ -27,7 +27,7 @@ describe('ordnanceSurveyConfig', () => { { configPropertyName: 'timeout', environmentVariableName: 'ORDNANCE_SURVEY_TIMEOUT', - defaultConfigValue: 30000, + defaultConfigValue: 30000, // in milliseconds }, ]; diff --git a/src/config/ordnance-survey.config.ts b/src/config/ordnance-survey.config.ts index e30acf8b..13da5637 100644 --- a/src/config/ordnance-survey.config.ts +++ b/src/config/ordnance-survey.config.ts @@ -16,6 +16,6 @@ export default registerAs( baseUrl: process.env.ORDNANCE_SURVEY_URL, key: process.env.ORDNANCE_SURVEY_KEY, maxRedirects: getIntConfig(process.env.ORDNANCE_SURVEY_MAX_REDIRECTS, 5), - timeout: getIntConfig(process.env.ORDNANCE_SURVEY_TIMEOUT, 30000), + timeout: getIntConfig(process.env.ORDNANCE_SURVEY_TIMEOUT, 30000), // in milliseconds }), ); diff --git a/src/constants/enums/geospatialCountries.ts b/src/constants/enums/geospatialCountries.ts index f181289d..d6a4df1f 100644 --- a/src/constants/enums/geospatialCountries.ts +++ b/src/constants/enums/geospatialCountries.ts @@ -1,6 +1,6 @@ export enum GeospatialCountriesEnum { E = 'England', + N = 'Northern Ireland', S = 'Scotland', W = 'Wales', - N = 'Northern Ireland', } diff --git a/src/constants/geospatial.constant.ts b/src/constants/geospatial.constant.ts index 567b89d2..d4d3102f 100644 --- a/src/constants/geospatial.constant.ts +++ b/src/constants/geospatial.constant.ts @@ -11,6 +11,7 @@ export const GEOSPATIAL = { }, REGEX: { // UK postcode regex is from DTFS project and slightly optimised by lint. + // https://github.com/UK-Export-Finance/dtfs2/blob/main/portal-api/src/constants/regex.js UK_POSTCODE: /^[A-Za-z]{1,2}[\dRr][\dA-Za-z]?\s?\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/, }, }; diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.module.ts b/src/helper-modules/ordnance-survey/ordnance-survey.module.ts index 2afb21df..dc5f11ce 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.module.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.module.ts @@ -11,9 +11,9 @@ import { OrdnanceSurveyService } from './ordnance-survey.service'; imports: [ConfigModule], inject: [ConfigService], useFactory: (configService: ConfigService) => { - const { baseUrl, maxRedirects, timeout } = configService.get(ORDNANCE_SURVEY_CONFIG_KEY); + const { baseUrl: baseURL, maxRedirects, timeout } = configService.get(ORDNANCE_SURVEY_CONFIG_KEY); return { - baseURL: baseUrl, + baseURL, maxRedirects, timeout, }; From 33c9e65961e67fdff36c854a7ae9f78c3c1ccd0c Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 13 May 2024 11:30:48 +0100 Subject: [PATCH 53/56] feat(DTFS2-7052): change GET /geospatial/addresses/postcode?postcode= empty response from 200 to 404 --- src/constants/geospatial.constant.ts | 5 +- .../ordnance-survey.service.test.ts | 2 +- .../get-addresses-by-postcode-query.dto.ts | 5 +- .../dto/get-addresses-response.dto.ts | 2 +- .../geospatial/geospatial.controller.test.ts | 14 +++-- .../geospatial/geospatial.controller.ts | 2 +- .../geospatial/geospatial.service.test.ts | 8 ++- src/modules/geospatial/geospatial.service.ts | 6 +- .../get-docs-yaml.api-test.ts.snap | 4 +- .../exposure-period.api-test.ts | 7 +++ .../get-address-by-postcode.api-test.ts | 60 ++++++++++++++++--- .../get-geospatial-addresses-generator.ts | 4 +- 12 files changed, 91 insertions(+), 28 deletions(-) diff --git a/src/constants/geospatial.constant.ts b/src/constants/geospatial.constant.ts index d4d3102f..f3accec2 100644 --- a/src/constants/geospatial.constant.ts +++ b/src/constants/geospatial.constant.ts @@ -4,7 +4,10 @@ export const GEOSPATIAL = { DATASET: 'DPA', }, EXAMPLES: { - POSTCODE: 'SW1A 2AQ', + ENGLISH_POSTCODE: 'SW1A 2AQ', + NORTHERN_IRELAND_POSTCODE: 'BT7 3GG', + WALES_POSTCODE: 'SY23 3AR', + SCOTLAND_POSTCODE: 'EH1 1JF', ORGANISATION_NAME: 'CHURCHILL MUSEUM & CABINET WAR ROOMS', ADDRESS_LINE_1: 'CLIVE STEPS KING CHARLES STREET', LOCALITY: 'LONDON', diff --git a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts index 2bc641f9..fe3a1dbc 100644 --- a/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts +++ b/src/helper-modules/ordnance-survey/ordnance-survey.service.test.ts @@ -19,7 +19,7 @@ describe('OrdnanceSurveyService', () => { let configServiceGet: jest.Mock; let service: OrdnanceSurveyService; - const testPostcode = GEOSPATIAL.EXAMPLES.POSTCODE; + const testPostcode = GEOSPATIAL.EXAMPLES.ENGLISH_POSTCODE; const testKey = valueGenerator.string({ length: 10 }); const basePath = '/search/places/v1/postcode'; diff --git a/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts b/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts index 26f62be0..55c06260 100644 --- a/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-by-postcode-query.dto.ts @@ -1,15 +1,16 @@ import { ApiProperty } from '@nestjs/swagger'; import { GEOSPATIAL } from '@ukef/constants'; -import { Matches, MaxLength, MinLength } from 'class-validator'; +import { IsString, Matches, MaxLength, MinLength } from 'class-validator'; export class GetAddressesByPostcodeQueryDto { @ApiProperty({ - example: GEOSPATIAL.EXAMPLES.POSTCODE, + example: GEOSPATIAL.EXAMPLES.ENGLISH_POSTCODE, description: 'Postcode to search for', minLength: 5, maxLength: 8, pattern: GEOSPATIAL.REGEX.UK_POSTCODE.source, }) + @IsString() @MinLength(5) @MaxLength(8) @Matches(GEOSPATIAL.REGEX.UK_POSTCODE) diff --git a/src/modules/geospatial/dto/get-addresses-response.dto.ts b/src/modules/geospatial/dto/get-addresses-response.dto.ts index 87e997a1..0947e056 100644 --- a/src/modules/geospatial/dto/get-addresses-response.dto.ts +++ b/src/modules/geospatial/dto/get-addresses-response.dto.ts @@ -40,7 +40,7 @@ export class GetAddressesResponseItem { @ApiProperty({ description: 'Postcode', - example: GEOSPATIAL.EXAMPLES.POSTCODE, + example: GEOSPATIAL.EXAMPLES.ENGLISH_POSTCODE, nullable: true, }) readonly postalCode: string | null; diff --git a/src/modules/geospatial/geospatial.controller.test.ts b/src/modules/geospatial/geospatial.controller.test.ts index d125cf04..0d951cbf 100644 --- a/src/modules/geospatial/geospatial.controller.test.ts +++ b/src/modules/geospatial/geospatial.controller.test.ts @@ -1,3 +1,4 @@ +import { NotFoundException } from '@nestjs/common'; import { GEOSPATIAL } from '@ukef/constants'; import { GetGeospatialAddressesGenerator } from '@ukef-test/support/generator/get-geospatial-addresses-generator'; import { RandomValueGenerator } from '@ukef-test/support/generator/random-value-generator'; @@ -30,7 +31,7 @@ describe('GeospatialController', () => { }); describe('getAddressesByPostcode()', () => { - const postcode = GEOSPATIAL.EXAMPLES.POSTCODE; + const postcode = GEOSPATIAL.EXAMPLES.ENGLISH_POSTCODE; it('returns a single address for the postcode when the service returns a single address', async () => { when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesByPostcodeResponse[0]); @@ -50,13 +51,16 @@ describe('GeospatialController', () => { expect(response).toEqual(getAddressesByPostcodeMultipleResponse); }); - it('returns an empty response for the postcode when the service returns an empty response', async () => { - when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce([]); + it('passes NotFoundException when it is thrown by geospatialService', async () => { + const errorMessage = valueGenerator.sentence(); + when(geospatialServiceGetAddressesByPostcode).calledWith(postcode).mockRejectedValueOnce(new NotFoundException(errorMessage)); - const response = await controller.getAddressesByPostcode({ postcode }); + const responsePromise = controller.getAddressesByPostcode({ postcode }); expect(geospatialServiceGetAddressesByPostcode).toHaveBeenCalledTimes(1); - expect(response).toEqual([]); + + await expect(responsePromise).rejects.toBeInstanceOf(NotFoundException); + await expect(responsePromise).rejects.toThrow(errorMessage); }); }); }); diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 7ded6c31..8fe5b2c0 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -21,7 +21,7 @@ export class GeospatialController { type: [GetAddressesResponseItem], }) @ApiNotFoundResponse({ - description: 'Postcode not found.', + description: 'No addresses found', }) getAddressesByPostcode(@Query() query: GetAddressesByPostcodeQueryDto): Promise { return this.geospatialService.getAddressesByPostcode(query.postcode); diff --git a/src/modules/geospatial/geospatial.service.test.ts b/src/modules/geospatial/geospatial.service.test.ts index 1718118f..67c34630 100644 --- a/src/modules/geospatial/geospatial.service.test.ts +++ b/src/modules/geospatial/geospatial.service.test.ts @@ -1,3 +1,4 @@ +import { NotFoundException } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; import { GetGeospatialAddressesGenerator } from '@ukef-test/support/generator/get-geospatial-addresses-generator'; @@ -56,12 +57,13 @@ describe('GeospatialService', () => { expect(response).toEqual(getAddressesByPostcodeMultipleResponse); }); - it('can handle empty backend response', async () => { + it('throws NotFoundException in case of empty backend response', async () => { when(ordnanceSurveyServiceGetAddressesByPostcode).calledWith(postcode).mockResolvedValueOnce(getAddressesOrdnanceSurveyEmptyResponse[0]); - const response = await service.getAddressesByPostcode(postcode); + const responsePromise = service.getAddressesByPostcode(postcode); - expect(response).toEqual([]); + await expect(responsePromise).rejects.toBeInstanceOf(NotFoundException); + await expect(responsePromise).rejects.toThrow('No addresses found'); }); it('returns addressLine1 formatted correctly even if middle value is missing', async () => { diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index cf2199a8..ff4cfc9e 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, NotFoundException } from '@nestjs/common'; import { ENUMS } from '@ukef/constants'; import { GetAddressesOrdnanceSurveyResponse } from '@ukef/helper-modules/ordnance-survey/dto/get-addresses-ordnance-survey-response.dto'; import { OrdnanceSurveyService } from '@ukef/helper-modules/ordnance-survey/ordnance-survey.service'; @@ -13,8 +13,8 @@ export class GeospatialService { const addresses = []; const response: GetAddressesOrdnanceSurveyResponse = await this.ordnanceSurveyService.getAddressesByPostcode(postcode); - if (!response?.results) { - return []; + if (!response?.results?.length) { + throw new NotFoundException('No addresses found'); } response.results.forEach((item) => { diff --git a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap index 3bcf1ea2..73ac0a10 100644 --- a/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap +++ b/test/docs/__snapshots__/get-docs-yaml.api-test.ts.snap @@ -515,7 +515,7 @@ paths: items: $ref: '#/components/schemas/GetAddressesResponseItem' '404': - description: Postcode not found. + description: No addresses found tags: - geospatial info: @@ -1174,9 +1174,9 @@ components: example: England enum: - England + - Northern Ireland - Scotland - Wales - - Northern Ireland nullable: true required: - organisationName diff --git a/test/exposure-period/exposure-period.api-test.ts b/test/exposure-period/exposure-period.api-test.ts index 0781ea76..74ec9e40 100644 --- a/test/exposure-period/exposure-period.api-test.ts +++ b/test/exposure-period/exposure-period.api-test.ts @@ -137,4 +137,11 @@ describe('Exposure period', () => { expect(status).toBe(400); expect(body.message).toContain('productgroup must be one of the following values: EW, BS'); }); + + it('returns a 404 response if URL is missing /api/v1 at the beginning', async () => { + const url = '/exposure-period?startdate=2017-03-05&enddate=2017-04-05&productgroup=new'; + const { status, body } = await api.get(url); + expect(status).toBe(404); + expect(body.message).toContain(`Cannot GET ${url}`); + }); }); diff --git a/test/geospatial/get-address-by-postcode.api-test.ts b/test/geospatial/get-address-by-postcode.api-test.ts index 37002809..733054bc 100644 --- a/test/geospatial/get-address-by-postcode.api-test.ts +++ b/test/geospatial/get-address-by-postcode.api-test.ts @@ -13,6 +13,7 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { const { ordnanceSurveyPaths, + ordnanceSurveyKey, mdmPaths, getAddressesByPostcodeResponse, getAddressesByPostcodeMultipleResponse, @@ -21,12 +22,14 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { getAddressesOrdnanceSurveyMultipleMatchingAddressesResponse, ordnanceSurveyAuthErrorResponse, } = new GetGeospatialAddressesGenerator(valueGenerator).generate({ - postcode: GEOSPATIAL.EXAMPLES.POSTCODE, + postcode: GEOSPATIAL.EXAMPLES.ENGLISH_POSTCODE, key: ENVIRONMENT_VARIABLES.ORDNANCE_SURVEY_KEY, numberToGenerate: 2, }); - const getMdmUrl = (postcode: string) => `/api/v1/geospatial/addresses/postcode?postcode=${encodeURIComponent(postcode)}`; + const getMdmUrl = (postcode: any) => `/api/v1/geospatial/addresses/postcode?postcode=${encodeURIComponent(postcode)}`; + const getOsUrl = (postcode: any) => + `/search/places/v1/postcode?postcode=${encodeURIComponent(postcode)}&lr=${GEOSPATIAL.DEFAULT.RESULT_LANGUAGE}&key=${encodeURIComponent(ordnanceSurveyKey)}`; beforeAll(async () => { api = await Api.create(); @@ -49,10 +52,27 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { makeRequestWithoutAuth: (incorrectAuth?: IncorrectAuthArg) => api.getWithoutAuth(mdmPaths[0], incorrectAuth?.headerName, incorrectAuth?.headerValue), }); - it('returns a 200 response with the address if it is returned by Ordnance Survey API', async () => { - requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(200, getAddressesOrdnanceSurveyResponse[0]); + it.each([ + { + postcode: GEOSPATIAL.EXAMPLES.ENGLISH_POSTCODE, + description: 'for English postcode', + }, + { + postcode: GEOSPATIAL.EXAMPLES.NORTHERN_IRELAND_POSTCODE, + description: 'for Northern Ireland postcode', + }, + { + postcode: GEOSPATIAL.EXAMPLES.SCOTLAND_POSTCODE, + description: 'for Scotish postcode', + }, + { + postcode: GEOSPATIAL.EXAMPLES.WALES_POSTCODE, + description: 'for Wales postcode', + }, + ])('returns a 200 response $description', async ({ postcode }) => { + requestToGetAddressesByPostcode(getOsUrl(postcode)).reply(200, getAddressesOrdnanceSurveyResponse[0]); - const { status, body } = await api.get(mdmPaths[0]); + const { status, body } = await api.get(getMdmUrl(postcode)); expect(status).toBe(200); expect(body).toStrictEqual(getAddressesByPostcodeResponse[0]); @@ -67,13 +87,17 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { expect(body).toStrictEqual(getAddressesByPostcodeMultipleResponse); }); - it('returns an empty 200 response if Ordnance Survey API returns a 200 without results', async () => { + it('returns a 404 response if Ordnance Survey API returns a 200 without results', async () => { requestToGetAddressesByPostcode(ordnanceSurveyPaths[0]).reply(200, getAddressesOrdnanceSurveyEmptyResponse[0]); const { status, body } = await api.get(mdmPaths[0]); - expect(status).toBe(200); - expect(body).toStrictEqual([]); + expect(status).toBe(404); + expect(body).toEqual({ + statusCode: 404, + message: 'No addresses found', + error: 'Not Found', + }); }); it('returns a 500 response if Ordnance Survey API returns a status code 401', async () => { @@ -125,6 +149,26 @@ describe('GET /geospatial/addresses/postcode?postcode=', () => { }); it.each([ + { + postcode: false, + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + { + postcode: 1234567, + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + { + postcode: null, + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + { + postcode: {}, + expectedError: 'postcode must match /^[A-Za-z]{1,2}[\\dRr][\\dA-Za-z]?\\s?\\d[ABD-HJLNP-UW-Zabd-hjlnp-uw-z]{2}$/ regular expression', + }, + { + postcode: '', + expectedError: 'postcode must be longer than or equal to 5 characters', + }, { postcode: valueGenerator.string({ length: 4 }), expectedError: 'postcode must be longer than or equal to 5 characters', diff --git a/test/support/generator/get-geospatial-addresses-generator.ts b/test/support/generator/get-geospatial-addresses-generator.ts index 347cb262..45bc5e73 100644 --- a/test/support/generator/get-geospatial-addresses-generator.ts +++ b/test/support/generator/get-geospatial-addresses-generator.ts @@ -26,7 +26,7 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator ({ postcode: postcode || v.POSTCODE }) as GetAddressesByPostcodeQueryDto); @@ -191,6 +191,7 @@ export class GetGeospatialAddressesGenerator extends AbstractGenerator Date: Mon, 13 May 2024 12:10:44 +0100 Subject: [PATCH 54/56] feat(DTFS2-7052): changed numeric status code 200 to HttpStatus.OK, but just in controller --- src/modules/geospatial/geospatial.controller.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/geospatial/geospatial.controller.ts b/src/modules/geospatial/geospatial.controller.ts index 8fe5b2c0..5cf5e010 100644 --- a/src/modules/geospatial/geospatial.controller.ts +++ b/src/modules/geospatial/geospatial.controller.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Query } from '@nestjs/common'; +import { Controller, Get, HttpStatus, Query } from '@nestjs/common'; import { ApiNotFoundResponse, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger'; import { GetAddressesByPostcodeQueryDto } from './dto/get-addresses-by-postcode-query.dto'; @@ -16,7 +16,7 @@ export class GeospatialController { "A search based on a property's postcode. Will accept a full valid postcode. Returns addresses from Ordnance Survey Delivery Point Address (DPA) system.", }) @ApiResponse({ - status: 200, + status: HttpStatus.OK, description: 'Returns simplified addresses that are ready to show to users.', type: [GetAddressesResponseItem], }) From 18fdf4a7bdfa77cc84a33f4da43b4c6cbab5f86b Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 13 May 2024 12:56:12 +0100 Subject: [PATCH 55/56] feat(DTFS2-7052): changed documentation for .env setting ORDNANCE_SURVEY_URL --- .env.sample | 3 +-- README.md | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.env.sample b/.env.sample index 536e7f69..af236dee 100644 --- a/.env.sample +++ b/.env.sample @@ -41,8 +41,7 @@ APIM_INFORMATICA_MAX_REDIRECTS= APIM_INFORMATICA_TIMEOUT= # in milliseconds # ORDNANCE SURVEY -# Use .uk domain, instead of .co.uk -ORDNANCE_SURVEY_URL= +ORDNANCE_SURVEY_URL=https://api.os.uk ORDNANCE_SURVEY_KEY= ORDNANCE_SURVEY_MAX_REDIRECTS= ORDNANCE_SURVEY_TIMEOUT= # in milliseconds diff --git a/README.md b/README.md index 0f7e3edc..8dbe732c 100644 --- a/README.md +++ b/README.md @@ -155,3 +155,7 @@ The most important prefixes you should have in mind are: 1. `fix:` which represents bug fixes, and correlates to a [SemVer](https://semver.org/) **patch**. 2. `feat:` which represents a new feature, and correlates to a [SemVer](https://semver.org/) **minor**. 3. `feat!:`, `fix!:` or `refactor!:`, etc., which represent a breaking change (indicated by the `!`) and will result in a [SemVer](https://semver.org/) **major**. + +### Special notes for .env settings + +- ORDNANCE_SURVEY_URL - Domain [https://api.os.co.uk](https://api.os.co.uk) redirects to [https://api.os.uk](https://api.os.uk), so please use [https://api.os.uk](https://api.os.uk). From 0da25c3304cf9491236dbf169092d68972ba1815 Mon Sep 17 00:00:00 2001 From: Audrius Vaitonis Date: Mon, 13 May 2024 13:14:42 +0100 Subject: [PATCH 56/56] feat(DTFS2-7052): tidying up map function --- src/modules/geospatial/geospatial.service.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/geospatial/geospatial.service.ts b/src/modules/geospatial/geospatial.service.ts index ff4cfc9e..492cebd2 100644 --- a/src/modules/geospatial/geospatial.service.ts +++ b/src/modules/geospatial/geospatial.service.ts @@ -20,10 +20,11 @@ export class GeospatialService { response.results.forEach((item) => { // Item can have key DPA or LPI, so we get data dynamically, even if we expect key to always be DPA. const item_data = item[Object.keys(item)[0]]; + // Filter out empty values and join values with single space. + const addressLine1 = [item_data.BUILDING_NAME, item_data.BUILDING_NUMBER, item_data.THOROUGHFARE_NAME].filter(Boolean).join(' '); addresses.push({ organisationName: item_data.ORGANISATION_NAME || null, - // Filter out empty values and join values with single space. - addressLine1: [item_data.BUILDING_NAME, item_data.BUILDING_NUMBER, item_data.THOROUGHFARE_NAME].filter(Boolean).join(' '), + addressLine1, addressLine2: item_data.DEPENDENT_LOCALITY || null, addressLine3: null, locality: item_data.POST_TOWN || null,