diff --git a/.eslintrc.js b/.eslintrc.js index 5ec21e0..4a466f3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,32 +1,19 @@ +/* eslint-env node */ + module.exports = { - env: { - browser: false, - commonjs: true, - es2021: true, - node: true - }, - extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'prettier' - ], - parserOptions: { - ecmaVersion: 'latest' - }, - plugins: ['@typescript-eslint'], - rules: { - '@typescript-eslint/no-non-null-assertion': 0, - '@typescript-eslint/ban-types': 0, - '@typescript-eslint/explicit-module-boundary-types': ['off'], - '@typescript-eslint/no-explicit-any': ['off'] - }, overrides: [ { - files: ['*.js'], + files: ['*.ts'], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + project: `${__dirname}/tsconfig.json` + }, rules: { - '@typescript-eslint/no-var-requires': 'off' + 'max-lines-per-function': ['error', { max: 660, skipBlankLines: true }], + 'max-depth': ['error', 6], + complexity: ['error', 20] } } - ], - ignorePatterns: ['**/build/*'] + ] }; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..54c982d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,26 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'yarn' + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Build + run: yarn build diff --git a/package.json b/package.json index ac85bb2..be4d089 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hyperproof/integration-sdk", - "version": "1.2.0", + "version": "6.0.0-beta", "description": "Hyperproof Integration SDK", "license": "MIT", "repository": { @@ -11,20 +11,22 @@ "types": "lib/index.d.ts", "scripts": { "build": "tsc && copyfiles -u 1 \"src/**/*.d.ts\" lib", - "lint": "./node_modules/eslint/bin/eslint.js src/**/*.ts" + "lint": "eslint 'src/**/*.{js,ts}' --max-warnings 0", + "test": "jest --config=../../packages/jest-config/lib/jest.config.js" }, "engines": { - "node": "^16.19.1 || ^18.17.1" + "node": "^22.0.0" }, "dependencies": { + "@hyperproof/hypersync-models": "6.0.0-beta", "@js-joda/core": "3.2.0", "@pollyjs/adapter-node-http": "6.0.6", "@pollyjs/core": "6.0.6", "@pollyjs/persister-fs": "6.0.6", "abort-controller": "3.0.0", "body-parser": "1.20.3", - "express": "4.21.0", - "form-data": "3.0.0", + "express": "4.21.2", + "form-data": "3.0.4", "html-entities": "2.5.2", "http-errors": "2.0.0", "http-status-codes": "2.3.0", @@ -34,18 +36,24 @@ "node-fetch": "2.7.0", "query-string": "7.1.3", "superagent": "10.1.0", + "uuid": "10.0.0", "xss": "1.0.15" }, "devDependencies": { "@types/express": "^4.17.21", - "@types/node-fetch": "^2.6.11", + "@types/jest": "^29.5.4", + "@types/node-fetch": "^2.6.13", "@types/superagent": "^8.1.9", + "@types/uuid": "^8.3.1", "@typescript-eslint/eslint-plugin": "8.7.0", "@typescript-eslint/parser": "8.7.0", "copyfiles": "^2.4.1", - "eslint": "8.57.1", "eslint-config-prettier": "^8.5.0", + "eslint": "8.57.1", + "jest-junit": "^12.2.0", + "jest": "^29.6.4", "prettier": "^2.6.1", + "ts-jest": "^29.1.1", "ts-node": "8.0.2", "typescript": "5.5.4" }, diff --git a/src/ApiClient.test.ts b/src/ApiClient.test.ts new file mode 100644 index 0000000..9519a02 --- /dev/null +++ b/src/ApiClient.test.ts @@ -0,0 +1,229 @@ +// Import node-fetch module to spy on it +import * as nodeFetch from 'node-fetch'; +import { ApiClient } from './ApiClient'; +import { HttpMethod } from './models'; + +/* eslint-disable max-lines-per-function */ +import { StatusCodes } from 'http-status-codes'; +// Import after mock +import { Response } from 'node-fetch'; + +jest.mock('./hyperproof-api/Logger'); + +// Mock only the default export (fetch function) +const mockFetch = jest.spyOn(nodeFetch, 'default') as jest.MockedFunction< + typeof nodeFetch.default +>; + +class TestApiClient extends ApiClient { + // Expose protected methods for testing + public async testParseResponseBodyJson(response: Response, url: string) { + return this.parseResponseBodyJson(response, url); + } + + public async testGetStatusCodeFromErrorMessage(error?: any) { + return this.getStatusCodeFromErrorMessage(error); + } + + public async testHandleNetworkError(err: any) { + return this.handleNetworkError(err); + } + + public async testHandleFailedResponse(response: Response, apiUrl: string) { + return this.handleFailedResponse(response, apiUrl); + } + + public async testBuildApiUrlAndFetch(params: any) { + return (this as any).buildApiUrlAndFetch(params); + } +} + +describe('ApiClient', () => { + let client: TestApiClient; + + beforeEach(() => { + client = new TestApiClient({}); + }); + + describe('parseResponseBodyJson', () => { + it('should return JSON when response has valid JSON content', async () => { + const response = new Response(JSON.stringify({ key: 'value' }), { + status: StatusCodes.OK + }); + + const result = await client.testParseResponseBodyJson( + response, + 'http://example.com' + ); + expect(result).toEqual({ key: 'value' }); + }); + + it('should return undefined when response is NO_CONTENT', async () => { + const response = new Response(undefined, { + status: StatusCodes.NO_CONTENT + }); + + const result = await client.testParseResponseBodyJson( + response, + 'http://example.com' + ); + expect(result).toBeUndefined(); + }); + + it('should return undefined when response body is empty', async () => { + const response = new Response('', { + status: StatusCodes.OK + }); + + const result = await client.testParseResponseBodyJson( + response, + 'http://example.com' + ); + expect(result).toBeUndefined(); + }); + + it('should throw error when response content is not valid JSON', async () => { + const response = new Response('Not JSON content', { + status: StatusCodes.OK + }); + + await expect( + client.testParseResponseBodyJson(response, 'http://example.com') + ).rejects.toMatchObject({ + status: StatusCodes.INTERNAL_SERVER_ERROR, + message: 'Failed to convert response body to JSON' + }); + }); + }); + + describe('getStatusCodeFromErrorMessage', () => { + it('should return INTERNAL_SERVER_ERROR when error is undefined', async () => { + const result = await client.testGetStatusCodeFromErrorMessage(undefined); + expect(result).toBe(StatusCodes.INTERNAL_SERVER_ERROR); + }); + + it('should return INTERNAL_SERVER_ERROR when error has no code or message', async () => { + const result = await client.testGetStatusCodeFromErrorMessage({}); + expect(result).toBe(StatusCodes.INTERNAL_SERVER_ERROR); + }); + + it('should map ENOTFOUND error to BAD_GATEWAY', async () => { + const error = { + code: 'ENOTFOUND', + message: 'request to https://example.com failed, getaddrinfo ENOTFOUND' + }; + + const result = await client.testGetStatusCodeFromErrorMessage(error); + expect(result).toBe(StatusCodes.BAD_GATEWAY); + }); + + it('should return INTERNAL_SERVER_ERROR when no pattern matches', async () => { + const error = { + code: 'UNKNOWN_ERROR', + message: 'Some unknown error occurred' + }; + + const result = await client.testGetStatusCodeFromErrorMessage(error); + expect(result).toBe(StatusCodes.INTERNAL_SERVER_ERROR); + }); + }); + + describe('handleNetworkError', () => { + it('should preserve status code when error has valid status', async () => { + const error = { + status: StatusCodes.SERVICE_UNAVAILABLE, + message: 'Service unavailable' + }; + + const result = await client.testHandleNetworkError(error); + expect(result.status).toBe(StatusCodes.SERVICE_UNAVAILABLE); + expect(result.message).toBe('Service unavailable'); + }); + + it('should map ENOTFOUND to BAD_GATEWAY', async () => { + const error = { + code: 'ENOTFOUND', + message: + 'request to https://api.example.com failed, getaddrinfo ENOTFOUND' + }; + + const result = await client.testHandleNetworkError(error); + expect(result.status).toBe(StatusCodes.BAD_GATEWAY); + }); + }); + + describe('handleFailedResponse', () => { + it('should throw HttpError with response details', async () => { + const response = new Response('Bad request error', { + status: StatusCodes.BAD_REQUEST + }); + + await expect( + client.testHandleFailedResponse(response, 'http://example.com/api') + ).rejects.toMatchObject({ + status: StatusCodes.BAD_REQUEST + }); + }); + }); + + describe('setBaseUrl', () => { + it('should update base URL', () => { + client.setBaseUrl('https://api.newdomain.com'); + // No error should be thrown + expect(client).toBeDefined(); + }); + }); + + describe('buildApiUrlAndFetch', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should call handleNetworkError when fetch throws an error', async () => { + const networkError = new Error('Network failure'); + mockFetch.mockRejectedValue(networkError); + + const handleNetworkErrorSpy = jest.spyOn( + client as any, + 'handleNetworkError' + ); + + await expect( + client.testBuildApiUrlAndFetch({ + url: 'http://example.com/api', + method: HttpMethod.GET + }) + ).rejects.toMatchObject({ + status: StatusCodes.INTERNAL_SERVER_ERROR + }); + + expect(handleNetworkErrorSpy).toHaveBeenCalledWith(networkError); + }); + + it('should call handleFailedResponse when response is not ok', async () => { + const failedResponse = new Response('Bad request', { + status: StatusCodes.BAD_REQUEST + }); + mockFetch.mockResolvedValue(failedResponse); + + const handleFailedResponseSpy = jest.spyOn( + client as any, + 'handleFailedResponse' + ); + + await expect( + client.testBuildApiUrlAndFetch({ + url: 'http://example.com/api', + method: HttpMethod.GET + }) + ).rejects.toMatchObject({ + status: StatusCodes.BAD_REQUEST + }); + + expect(handleFailedResponseSpy).toHaveBeenCalledWith( + failedResponse, + 'http://example.com/api' + ); + }); + }); +}); diff --git a/src/ApiClient.ts b/src/ApiClient.ts index 10df692..27d1236 100644 --- a/src/ApiClient.ts +++ b/src/ApiClient.ts @@ -1,10 +1,11 @@ +import { createFetchOptions } from './agent'; import { getAsyncStore } from './asyncStore'; import { Logger } from './hyperproof-api'; import { HttpMethod, LogContextKey } from './models'; import { IThrottleModel, ThrottleManager } from './util'; import AbortController from 'abort-controller'; -import createHttpError from 'http-errors'; +import createHttpError, { HttpError } from 'http-errors'; import { StatusCodes } from 'http-status-codes'; import fetch, { HeadersInit, Response } from 'node-fetch'; @@ -17,13 +18,14 @@ import fetch, { HeadersInit, Response } from 'node-fetch'; * @property additionalHeaders Additional headers to merge with the client's `commonHeaders` for the * request. */ -type ApiClientRequestArgs = [ - url: string, - method: string, - body?: object | string, - additionalHeaders?: HeadersInit, - abortController?: AbortController -]; +interface ApiClientRequestArgs { + url: string; + method: string; + body?: object | string; + additionalHeaders?: HeadersInit; + abortController?: AbortController; + isAbsoluteUrl?: boolean; +} /** * Type alias for the set of response headers that are returned from a request. @@ -42,6 +44,13 @@ export interface IApiClientResponse { status: number; } +export interface IErrorMessagePattern { + name: string; + messageMatch: RegExp; + fromStatus?: string; + toStatus: number; +} + /** * Generic client for sending requests to external APIs */ @@ -77,7 +86,7 @@ export class ApiClient { } this.baseUrl = baseUrl; this.throttleManager = new ThrottleManager( - params => this.buildApiUrlAndFetch(...params), + params => this.buildApiUrlAndFetch({ ...params }), throttleModel ); } @@ -86,19 +95,24 @@ export class ApiClient { this.throttleManager.setRetryCount(retryCount); } - public async getNonProcessedResponse( + public setBaseUrl(baseUrl: string) { + this.baseUrl = baseUrl; + } + + public async getUnprocessedResponse( url: string, additionalHeaders?: HeadersInit, + isAbsoluteUrl = false, abortController?: AbortController ): Promise { - const { response } = await this.throttleManager.retrieve([ + const { response } = await this.buildApiUrlAndFetch({ url, - HttpMethod.GET, - undefined, - { ...this.headers, ...additionalHeaders }, - abortController - ]); - + method: HttpMethod.GET, + body: undefined, + additionalHeaders, + abortController, + isAbsoluteUrl + }); return response; } @@ -107,13 +121,13 @@ export class ApiClient { headers?: { [key: string]: string }, abortController?: AbortController ) { - return this.doSendRequest( + return this.doSendRequest({ url, - HttpMethod.GET, - undefined, - headers, + method: HttpMethod.GET, + body: undefined, + additionalHeaders: headers, abortController - ); + }); } public async postJson( @@ -122,13 +136,13 @@ export class ApiClient { headers?: { [key: string]: string }, abortController?: AbortController ) { - return this.doSendRequest( + return this.doSendRequest({ url, - HttpMethod.POST, + method: HttpMethod.POST, body, - headers, + additionalHeaders: headers, abortController - ); + }); } public async patchJson( @@ -137,19 +151,110 @@ export class ApiClient { headers?: { [key: string]: string }, abortController?: AbortController ) { - return this.doSendRequest( + return this.doSendRequest({ + url, + method: HttpMethod.PATCH, + body, + additionalHeaders: headers, + abortController + }); + } + + public async putJson( + url: string, + body?: object | string, + headers?: { [key: string]: string }, + abortController?: AbortController + ) { + return this.doSendRequest({ url, - HttpMethod.PATCH, + method: HttpMethod.PUT, body, - headers, + additionalHeaders: headers, abortController + }); + } + + /** + * Maps error message patterns to appropriate HTTP status codes. + * Each pattern is a regex that will be tested against the error message. + * + * A connector can override this method to provide error message patterns + * that map to specific HTTP status codes that are specific to the + * handling of that connector and/or its target API. + * + * This will require the connector to implement its own ApiClient that + * extends this base ApiClient class, and pass via the data source contructor + * the custom ApiClient class to be used. + */ + public getErrorMessageStatusPatterns(): IErrorMessagePattern[] { + return [ + { + name: 'DNS Resolution Failure', + messageMatch: /request to.*getaddrinfo ENOTFOUND.*/i, + fromStatus: 'ENOTFOUND', + toStatus: StatusCodes.BAD_GATEWAY + } + // Add more global patterns here as needed + ]; + } + + protected async getStatusCodeFromErrorMessage(error?: any): Promise { + const status: string = + error?.code?.toString() || + error?.statusCode?.toString() || + error?.status?.toString() || + ''; + const message: string = error?.message || ''; + + if (!status && !message) { + return StatusCodes.INTERNAL_SERVER_ERROR; + } + + const patterns = this.getErrorMessageStatusPatterns(); + + for (const errorPattern of patterns) { + if ( + (!errorPattern.fromStatus || errorPattern.fromStatus === status) && + errorPattern.messageMatch.test(message) + ) { + await Logger.info( + `Mapped error status ${status} to status ${errorPattern.toStatus} using pattern ${errorPattern.name}` + ); + return errorPattern.toStatus; + } + } + + await Logger.warn( + `No matching error pattern found for error status: ${status}, message: ${message}`, + typeof error === 'object' ? JSON.stringify(error) : undefined ); + + return StatusCodes.INTERNAL_SERVER_ERROR; + } + + protected async handleNetworkError(err: any): Promise { + const errorMessage = err.message || 'Network error occurred'; + // If the error contains a statusCode, use it + if (Object.values(StatusCodes).includes(err.status)) { + return createHttpError(err.status, errorMessage, { + ...err + }); + } + + // Map known codes to statusCodes + const status = await this.getStatusCodeFromErrorMessage(err); + + return createHttpError(status, errorMessage, { + ...err + }); } protected async handleFailedResponse(response: Response, apiUrl: string) { const errMsg = await response.text(); + await Logger.warn(`Error retrieving JSON from ${apiUrl}: ${errMsg}`); throw createHttpError( - response.status, + response.status ?? StatusCodes.INTERNAL_SERVER_ERROR, `Error retrieving JSON from ${apiUrl}: ${errMsg}`, { [LogContextKey.Headers]: response.headers.raw(), @@ -160,11 +265,18 @@ export class ApiClient { ); } + /** + * On a successful response, where response.ok is true, this method will be called + * to parse the body into a JSON object. Returns undefined when the body is empty. + */ protected async parseResponseBodyJson( response: Response, url: string - ): Promise { - let json: string | undefined; + ): Promise { + if (response.status === StatusCodes.NO_CONTENT) { + return; + } + let json: any | undefined; const text = await response.text(); if (text.length === 0) { return; @@ -187,27 +299,25 @@ export class ApiClient { return json; } - public sendRequest(...params: ApiClientRequestArgs) { - return this.doSendRequest(...params); + public sendRequest(params: ApiClientRequestArgs) { + return this.doSendRequest(params); } - private async doSendRequest( - ...[ - url, - method, - body, - additionalHeaders, - abortController - ]: ApiClientRequestArgs - ): Promise { + private async doSendRequest({ + url, + method, + body, + additionalHeaders, + abortController + }: ApiClientRequestArgs): Promise { // By default, throttleManager calls buildApiUrlAndFetch() to make the request. - const { response, apiUrl } = await this.throttleManager.retrieve([ + const { response, apiUrl } = await this.throttleManager.retrieve({ url, method, body, additionalHeaders, abortController - ]); + }); const json = await this.parseResponseBodyJson(response, url); @@ -219,33 +329,45 @@ export class ApiClient { }; } - private async buildApiUrlAndFetch( - ...[ - url, - method, - body, - additionalHeaders, - abortController - ]: ApiClientRequestArgs - ): Promise { - const apiUrl = this.buildUrl(url); + private async buildApiUrlAndFetch({ + url, + method, + body, + additionalHeaders, + abortController, + isAbsoluteUrl + }: ApiClientRequestArgs): Promise { + const apiUrl = isAbsoluteUrl ? url : this.buildUrl(url); const headers = { ...this.headers, ...additionalHeaders }; const headerNames = Object.keys(headers); + await Logger.info( `Making ${method} request to ${apiUrl}. Header names: ${headerNames}` ); - const response = await fetch(apiUrl, { - method, - headers, - body: typeof body === 'string' ? body : JSON.stringify(body), - signal: abortController?.signal as AbortSignal | undefined - }); + + let response: Response; + try { + response = await fetch( + apiUrl, + createFetchOptions(apiUrl, { + method, + headers, + body: typeof body === 'string' ? body : JSON.stringify(body), + signal: abortController?.signal as AbortSignal | undefined + }) + ); + } catch (err) { + // Complete failure to make the request + throw await this.handleNetworkError(err); + } + if (!response.ok) { + // Received a response with non-2xx statusCode await this.handleFailedResponse(response, apiUrl); } - await Logger.info(`${url} returned ${response.status}`); - + // Successful response + await Logger.info(`Response from ${method} ${apiUrl}: ${response.status}`); return { response, apiUrl }; } diff --git a/src/add-on-sdk/addOn.ts b/src/add-on-sdk/addOn.ts index 4c00e98..f5d318d 100644 --- a/src/add-on-sdk/addOn.ts +++ b/src/add-on-sdk/addOn.ts @@ -16,6 +16,7 @@ import Mock from 'mock-http'; import Superagent from 'superagent'; import Url from 'url'; +import { getAgent } from '../agent'; import { LogContextKey } from '../models'; let logger: (message?: any, ...optionalParams: any[]) => void = console.log; @@ -277,6 +278,7 @@ export const createFunction = async ( // Create the function const url = `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}`; let response = await Superagent.put(url) + .agent(getAgent(url)) .set('Authorization', accessTokenHeader) .send(functionSpecification); functionCreated = true; @@ -284,9 +286,10 @@ export const createFunction = async ( // Wait for the function to be built and ready let attempts = 15; while (response.status === 201 && attempts > 0) { - response = await Superagent.get( - `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}/build/${response.body.buildId}` - ).set('Authorization', accessTokenHeader); + const url = `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}/build/${response.body.buildId}`; + response = await Superagent.get(url) + .agent(getAgent(url)) + .set('Authorization', accessTokenHeader); if (response.status === 200) { if (response.body.status === 'success') { break; @@ -313,9 +316,10 @@ export const createFunction = async ( if (response.body && response.body.location) { return response.body.location; } else { - response = await Superagent.get( - `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}/location` - ).set('Authorization', accessTokenHeader); + const url = `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ctx.body.subscriptionId}/boundary/${ctx.body.boundaryId}/function/${ctx.body.functionId}/location`; + response = await Superagent.get(url) + .agent(getAgent(url)) + .set('Authorization', accessTokenHeader); if (response.body && response.body.location) { return response.body.location; } @@ -341,13 +345,13 @@ export const deleteFunction = async ( boundaryId?: string, functionId?: string ) => { - await Superagent.delete( - `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ - ctx.body.subscriptionId - }/boundary/${boundaryId || ctx.body.boundaryId}/function/${ - functionId || ctx.body.functionId - }` - ) + const url = `${ctx.body.baseUrl}/v1/account/${ + ctx.body.accountId + }/subscription/${ctx.body.subscriptionId}/boundary/${ + boundaryId || ctx.body.boundaryId + }/function/${functionId || ctx.body.functionId}`; + await Superagent.delete(url) + .agent(getAgent(url)) .set('Authorization', `Bearer ${accessToken}`) .ok(res => res.status === 204 || res.status === 404); }; @@ -358,13 +362,14 @@ export const getFunctionDefinition = async ( boundaryId: string, functionId: string ) => { - const response = await Superagent.get( - `${ctx.body.baseUrl}/v1/account/${ctx.body.accountId}/subscription/${ - ctx.body.subscriptionId - }/boundary/${boundaryId || ctx.body.boundaryId}/function/${ - functionId || ctx.body.functionId - }` - ).set('Authorization', `Bearer ${accessToken}`); + const url = `${ctx.body.baseUrl}/v1/account/${ + ctx.body.accountId + }/subscription/${ctx.body.subscriptionId}/boundary/${ + boundaryId || ctx.body.boundaryId + }/function/${functionId || ctx.body.functionId}`; + const response = await Superagent.get(url) + .agent(getAgent(url)) + .set('Authorization', `Bearer ${accessToken}`); return response.body; }; @@ -403,7 +408,9 @@ export const createStorageClient = async ( if (!storageSubId && !storageIdPrefix) { return undefined; } - const response = await Superagent.get(getUrl(storageSubId)) + const url = getUrl(storageSubId); + const response = await Superagent.get(url) + .agent(getAgent(url)) .set('Authorization', `Bearer ${accessToken}`) .ok(res => res.status < 300 || res.status === 404); return response.status === 404 ? undefined : response.body; @@ -417,7 +424,9 @@ export const createStorageClient = async ( 'Storage objects cannot be stored at the root of the hierarchy. Specify a storageSubId when calling the `put` method, or a storageIdPrefix when creating the storage client.' ); } - const response = await Superagent.put(getUrl(storageSubId)) + const url = getUrl(storageSubId); + const response = await Superagent.put(url) + .agent(getAgent(url)) .set('Authorization', `Bearer ${accessToken}`) .send(data); return response.body; @@ -435,7 +444,9 @@ export const createStorageClient = async ( 'You are attempting to recursively delete all storage objects in the Fusebit subscription. If this is your intent, please pass "true" as the third parameter in the call to delete(storageSubId, recursive, forceRecursive).' ); } - await Superagent.delete(`${getUrl(storageSubId)}${recursive ? '/*' : ''}`) + const url = `${getUrl(storageSubId)}${recursive ? '/*' : ''}`; + await Superagent.delete(url) + .agent(getAgent(url)) .set('Authorization', `Bearer ${accessToken}`) .ok(res => res.status === 404 || res.status === 204); return; @@ -448,7 +459,9 @@ export const createStorageClient = async ( count: count === undefined || isNaN(count) ? undefined : count, next: typeof next === 'string' ? next : undefined }; - const response = await Superagent.get(`${getUrl(storageSubId)}/*`) + const url = `${getUrl(storageSubId)}/*`; + const response = await Superagent.get(url) + .agent(getAgent(url)) .query(params) .set('Authorization', `Bearer ${accessToken}`); return response.body; @@ -552,7 +565,9 @@ export const createFusebitFunctionFromExpress = ( * to handle incoming request to the /invoke endpoint. Invoke requests are * forwarded to the Express app created and configured by the integration. */ -export const createHttpServerApp = (integrationApp: express.Express) => { +export const createHttpServerApp = ( + integrationApp: express.Express +): express.Express => { const app = express(); app.use(bodyParser.json()); diff --git a/src/agent.ts b/src/agent.ts new file mode 100644 index 0000000..8b849c8 --- /dev/null +++ b/src/agent.ts @@ -0,0 +1,43 @@ +import http from 'http'; +import https from 'https'; + +const httpAgentDefaults = { + keepAlive: true, + maxSockets: 1000, // per host + maxTotalSockets: 5000, // total sockets across all hosts + maxFreeSockets: 10, + timeout: 60 * 1000 // 1 minute timeout for inactive sockets +}; +const httpsAgentDefaults = { + ...httpAgentDefaults +}; + +const httpAgent: http.Agent = new http.Agent(httpAgentDefaults); +const httpsAgent: https.Agent = new https.Agent(httpsAgentDefaults); + +export const getAgent = (uri: string): http.Agent | https.Agent => { + if (!uri) { + throw new Error('No URI provided to getAgent.'); + } + return new URL(uri).protocol === 'https:' ? httpsAgent : httpAgent; +}; + +/** + * Creates fetch options with agent conditionally included only if it exists. + * This avoids passing undefined agent property to fetch. + * + * @param uri - The URI for which to get the agent + * @param baseOptions - Base fetch options to extend + * @returns Fetch options with agent conditionally included + */ +export const createFetchOptions = ( + uri: string, + baseOptions: RequestInit = {} +): any => { + const agent = getAgent(uri); + const options = { ...baseOptions } as any; + + options.agent = agent; + + return options; +}; diff --git a/src/errors.ts b/src/errors.ts deleted file mode 100644 index 56d23a5..0000000 --- a/src/errors.ts +++ /dev/null @@ -1,15 +0,0 @@ -export enum ErrorName { - REFRESH_TOKEN_ATTEMPTS_EXHAUSTED = 'attemptsExhausted', - REFRESH_TOKEN_ATTEMP_FAILED = 'attemptFailed' -} - -export class RefreshTokenError extends Error { - name: ErrorName; - message: string; - - constructor({ name, message }: { name: ErrorName; message: string }) { - super(); - this.name = name; - this.message = message; - } -} diff --git a/src/hyperproof-api/HyperproofApiClient.test.ts b/src/hyperproof-api/HyperproofApiClient.test.ts new file mode 100644 index 0000000..755b71a --- /dev/null +++ b/src/hyperproof-api/HyperproofApiClient.test.ts @@ -0,0 +1,159 @@ +import { HyperproofApiClient } from './HyperproofApiClient'; + +import { StatusCodes } from 'http-status-codes'; +import fetch from 'node-fetch'; + +import { IntegrationContext } from '../add-on-sdk'; + +jest.mock('node-fetch'); +jest.mock('./Logger'); + +const { Response } = jest.requireActual('node-fetch'); +const delaySeconds = 0.1; + +describe('HyperproofApiClient', () => { + const mockFetch = fetch as jest.MockedFunction; + + beforeAll(() => { + HyperproofApiClient.setSubscriptionKey('subscription-key'); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('fetchWithRetry', () => { + it('should return response JSON on success', async () => { + mockFetch.mockResolvedValue(createSuccessResponse()); + + const client = await HyperproofApiClient.createInstance( + integrationContext, + 'org-id-uuid', + 'user-id-uuid' + ); + const result = await client.fetchWithRetry({ + url: 'https://api.test.com/data', + delaySeconds + }); + + expect(result).toEqual({ data: 'test' }); + expect(mockFetch).toHaveBeenCalledTimes(1); + }); + + it('should retry on failure and eventually succeed', async () => { + mockFetch + .mockResolvedValueOnce( + createErrorResponse(StatusCodes.INTERNAL_SERVER_ERROR) + ) + .mockResolvedValueOnce( + createErrorResponse(StatusCodes.INTERNAL_SERVER_ERROR) + ) + .mockResolvedValueOnce(createSuccessResponse()); + + const client = await HyperproofApiClient.createInstance( + integrationContext, + 'org-id-uuid', + 'user-id-uuid' + ); + const result = await client.fetchWithRetry({ + url: 'https://api.test.com/data', + delaySeconds: 0.1 + }); + + expect(result).toEqual({ data: 'test' }); + expect(mockFetch).toHaveBeenCalledTimes(3); + }); + + it('should throw an error after all attempts fail', async () => { + mockFetch + .mockResolvedValueOnce( + createErrorResponse(StatusCodes.INTERNAL_SERVER_ERROR) + ) + .mockResolvedValueOnce( + createErrorResponse(StatusCodes.INTERNAL_SERVER_ERROR) + ); + const numCalls = 2; + + const client = await HyperproofApiClient.createInstance( + integrationContext, + 'org-id-uuid', + 'user-id-uuid' + ); + await expect( + client.fetchWithRetry({ + url: 'https://api.test.com/data', + delaySeconds, + totalAttempts: numCalls + }) + ).rejects.toThrow( + 'Received 500 response from Hyperproof when attempting to GET /data: Error' + ); + + expect(mockFetch).toHaveBeenCalledTimes(numCalls); + }); + + it('should not throw an error if onErrorResponse returns shouldThrow false', async () => { + mockFetch.mockResolvedValueOnce( + createErrorResponse(StatusCodes.INTERNAL_SERVER_ERROR) + ); + + const client = await HyperproofApiClient.createInstance( + integrationContext, + 'org-id-uuid', + 'user-id-uuid' + ); + const result = await client.fetchWithRetry({ + url: 'https://api.test.com/data', + delaySeconds, + totalAttempts: 1, + onErrorResponse: () => ({ shouldThrow: false }) + }); + + expect(result).toBeUndefined(); + expect(mockFetch).toHaveBeenCalledTimes(1); + }); + }); +}); + +const hyperproofTokenEntry = { + hyperproofToken: { + access_token: 'access-token' + } +}; + +const integrationContext: IntegrationContext = { + storage: { + get: jest.fn(async () => ({ + data: hyperproofTokenEntry, + etag: 'etag', + tags: [], + expires: '' + })), + put: jest.fn(), + delete: jest.fn(), + list: jest.fn() + }, + accountId: '', + subscriptionId: '', + boundaryId: '', + functionId: '', + configuration: {}, + method: 'GET', + query: {}, + headers: {}, + fusebit: { + endpoint: '', + functionAccessToken: '' + }, + caller: { + permissions: { + allow: [] + } + } +}; + +const createSuccessResponse = () => + new Response(JSON.stringify({ data: 'test' }), { status: 200 }); + +const createErrorResponse = (status: number) => + new Response('Error', { status }); diff --git a/src/hyperproof-api/HyperproofApiClient.ts b/src/hyperproof-api/HyperproofApiClient.ts index f08a6b7..c525c0b 100644 --- a/src/hyperproof-api/HyperproofApiClient.ts +++ b/src/hyperproof-api/HyperproofApiClient.ts @@ -6,19 +6,30 @@ import createHttpError from 'http-errors'; import { StatusCodes } from 'http-status-codes'; import mime from 'mime'; import fetch, { RequestInit } from 'node-fetch'; +import { Response } from 'node-fetch'; import path from 'path'; import queryString from 'query-string'; import { debug, IntegrationContext } from '../add-on-sdk'; +import { createFetchOptions } from '../agent'; import { HttpHeader, HttpMethod, + IArchiveProofLinkPost, ICommentBody, + IExternalConnectionFilterSystem, + IExternalConnectionPostSystem, IExternalUser, IIntegration, + IIntegrationPostSystem, IIntegrationSettingsBase, + IProof, + IProofPost, + IProofPostBase, + IProofVersionPost, ITask, ITaskPatch, + ITaskStatus, MimeType, ObjectType } from '../models'; @@ -37,12 +48,11 @@ const alternateMessages: { [key: number]: string } = { [StatusCodes.NOT_FOUND]: 'Referenced object is missing.' }; -const createAndLogErrorMessage = ( +const createErrorMessage = ( status: number, method: string, url: string, - message: string, - objectType?: ObjectType + message: string ) => { const displayUrl = new URL(url).pathname; try { @@ -54,15 +64,27 @@ const createAndLogErrorMessage = ( } catch (ignore: any) { // just use the string if it's not valid json } - const longMsg = `Received ${status} response from Hyperproof when attempting to ${method} ${displayUrl}${ - objectType ? ' ' + objectType : '' - }: ${message}`; - debug(longMsg); + const longMsg = `Received ${status} response from Hyperproof when attempting to ${method} ${displayUrl}: ${message}`; return alternateMessages[status] ? `${alternateMessages[status]} ${longMsg}` : longMsg; }; +interface IFetchWithRetryArgs { + url: string; + options?: RequestInit; + totalAttempts?: number; + delaySeconds?: number; + onErrorResponse?: ( + response: Response, + errorText: string + ) => { errorText?: string; shouldThrow?: boolean }; + onAnyFetchFailure?: ( + response: Response, + errorText: string + ) => { errorText?: string; shouldBreak?: boolean }; +} + /** * Client interface to the Hyperproof API. */ @@ -83,33 +105,86 @@ export class HyperproofApiClient { * Fetch the given url with up to at most `totalAttempts` attempts in the case of failures * Return either the first successful response, or the last response if all responses fail */ - public static async fetchWithRetry( - url: string, - options: RequestInit | undefined = undefined, + public async fetchWithRetry({ + url, + options = {}, totalAttempts = 3, - delay = 3 - ) { + delaySeconds = 3, + onErrorResponse, + onAnyFetchFailure + }: IFetchWithRetryArgs): Promise { + let attempt = 1; totalAttempts = Math.max(totalAttempts, 1); - delay = Math.max(0, delay); + delaySeconds = Math.max(0, delaySeconds); - let response = await fetch(url, options); + const method = options?.method ?? HttpMethod.GET; + let response: Response; + let errorText: string = ''; - // retries - for (let attempts = 1; attempts < totalAttempts; attempts++) { + do { + const attemptCounter = `Attempt ${attempt}/${totalAttempts}`; + await Logger.info( + `HyperproofApiClient: Making ${method} request to ${url}. ${attemptCounter}` + ); + response = await fetch( + url, + createFetchOptions(url, { + ...options, + headers: { + ...options?.headers, + ...TraceParent.getHeaders(), + [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, + [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey + } + } as any) // ignore typescript error caused by incompatible RequestInit type + ); if (response.ok) { break; } - await HyperproofApiClient.sleep(delay); - Logger.warn( - `Retrying fetch after failing ${attempts} time(s) with code ${ - response.status - }: ${await response.text()}` + let shouldBreak = false; + if (onAnyFetchFailure) { + const { shouldBreak: newShouldBreak, errorText: newErrorText } = + onAnyFetchFailure(response, errorText); + shouldBreak = newShouldBreak ?? false; + errorText = newErrorText ?? errorText; + } + if (shouldBreak) { + break; + } + + errorText = await response.text(); + await Logger.warn( + `HyperproofApiClient: Failed to make ${method} request to ${url}. Status code ${response.status}: ${errorText}. ${attemptCounter}` ); - response = await fetch(url, options); + await HyperproofApiClient.sleep(delaySeconds); + attempt++; + } while (attempt <= totalAttempts); + + await Logger.info( + `HyperproofApiClient: Received ${response.status} response from ${method} ${url}` + ); + + if (!response.ok) { + const status = response.status ?? StatusCodes.INTERNAL_SERVER_ERROR; + let shouldThrow = true; + if (onErrorResponse) { + const { shouldThrow: newShouldThrow, errorText: newErrorText } = + onErrorResponse(response, errorText); + shouldThrow = newShouldThrow ?? true; + errorText = newErrorText ?? errorText; + } + if (shouldThrow) { + throw createHttpError( + status, + createErrorMessage(status, method, url, errorText) + ); + } else { + return undefined as T; + } } - return response; + return response.json(); } public static setSubscriptionKey(subscriptionKey: string) { @@ -126,6 +201,7 @@ export class HyperproofApiClient { /** * Factory method that creates a new HyperproofApiClient instance. */ + public static async createInstance( integrationContext: IntegrationContext, orgId: string, @@ -148,6 +224,20 @@ export class HyperproofApiClient { return new HyperproofApiClient(accessToken); } + public static async createInstanceByAccessToken( + accessToken: string + ): Promise { + // this is done to trigger the non null check in the getter method + // eslint-disable-next-line @typescript-eslint/no-unused-expressions + HyperproofApiClient.subscriptionKey; + + await Logger.debug( + `Creating Hyperproof API client using URL via accessToken ${process.env.hyperproof_api_url}` + ); + + return new HyperproofApiClient(accessToken); + } + /** * Retrieves an integration settings instance in Hyperproof. */ @@ -170,32 +260,13 @@ export class HyperproofApiClient { } url += `/integrations/${integrationId}?${query}`; - const response = await HyperproofApiClient.fetchWithRetry(url, { - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey - } - }); - - if (!response.ok) { - const errorText = + return this.fetchWithRetry>({ + url, + onErrorResponse: (response, errorText) => response.status === StatusCodes.CONFLICT - ? 'Operation is already in process' - : await response.text(); - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.GET, - url, - errorText, - objectType - ) - ); - } - - return response.json() as Promise>; + ? { errorText: 'Operation is already in process' } + : { errorText } + }); } /** @@ -218,37 +289,16 @@ export class HyperproofApiClient { if (suffix) { url += `/${suffix}`; } - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'PATCH', - body: JSON.stringify(settings), - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.PATCH, + body: JSON.stringify(settings), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - - debug(`PATCH ${url} - ${response.status}`); - - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.PATCH, - url, - await response.text(), - objectType - ) - ); - } - try { - return await response.json(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - } catch (err) { - // swallow for 204; - } } /** @@ -264,151 +314,53 @@ export class HyperproofApiClient { url += `/${objectType}s/${objectId}`; } url += `/integrations`; - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'POST', - body: JSON.stringify(settings), - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: JSON.stringify(settings), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - - debug(`POST ${url} - ${response.status}`); - - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.POST, - url, - await response.text(), - objectType - ) - ); - } - - return response.json(); } /** * Posts a proof file to a Hyperproof organization or object. - * - * @param file File to upload. - * @param filename Name of the file. - * @param mimeType MIME type for the file. - * @param objectType Type of object to which the file should be uploaded. - * @param objectId Unique ID of the object. - * @param sourceId (optional) id of the source of the proof - * @param sourceFileId (optional) id of file in source - * @param sourceModifiedOn (optional) ISO8601 date representing when this piece of proof was modified in the source - * @param user (optional) External user that is uploading this proof - * @param size (optional) Size of the file being uploaded. */ - public async postProof( - file: Buffer, - filename: string, - mimeType: string, - objectType: ObjectType, - objectId: string, - sourceId?: string, - sourceFileId?: string, - sourceModifiedOn?: string, - user?: IExternalUser, - size?: number - ) { - const formData = this.buildProofFormData( - file, - filename, - mimeType, - sourceId, - sourceFileId, - sourceModifiedOn, - user, - size - ); - - return this.postNewProof(objectType, objectId, formData); + public async postProof(post: IProofPost) { + const formData = this.buildProofFormData(post); + return this.postNewProof(post.objectType, post.objectId, formData); } - public async postProofVersion( - file: Buffer, - filename: string, - mimeType: string, - proofId: string, - sourceId: string, - sourceFileId: string, - sourceModifiedOn?: string, - user?: IExternalUser, - size?: number - ) { - const formData = this.buildProofFormData( - file, - filename, - mimeType, - sourceId, - sourceFileId, - sourceModifiedOn, - user, - size - ); - - const url = `${process.env.hyperproof_api_url}/beta/proof/${proofId}/versions`; - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'POST', - body: formData, - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey + public async postProofVersion(post: IProofVersionPost) { + const formData = this.buildProofFormData(post); + const url = `${process.env.hyperproof_api_url}/beta/proof/${post.proofId}/versions`; + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: formData, + headers: {} } }); - debug(`POST ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.POST, - url, - await response.text() - ) - ); - } - return response.json(); } /** * Retrieves the task statuses for Hyperproof org. */ - public async getTaskStatuses() { + public async getTaskStatuses(): Promise { const url = `${process.env.hyperproof_api_url}/v1/taskstatuses`; - - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'GET', - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.GET, + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - debug(`GET ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.GET, - url, - await response.text() - ) - ); - } - - return response.json(); } /** @@ -422,30 +374,16 @@ export class HyperproofApiClient { if (patch.externalUser && !patch.externalUser.id) { delete patch.externalUser; } - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'PATCH', - body: JSON.stringify(patch), - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.PATCH, + body: JSON.stringify(patch), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - debug(`PATCH ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.PATCH, - url, - await response.text() - ) - ); - } - - return response.json(); } /** @@ -455,30 +393,15 @@ export class HyperproofApiClient { */ public async getTask(objectId: string): Promise { const url = `${process.env.hyperproof_api_url}/v1/tasks/${objectId}`; - - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'GET', - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.GET, + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - debug(`GET ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.GET, - url, - await response.text() - ) - ); - } - - return response.json() as Promise; } /** @@ -490,30 +413,15 @@ export class HyperproofApiClient { public async getTaskProofMeta(objectId: string, sourceFileId?: string) { const query = queryString.stringify({ sourceFileId }); const url = `${process.env.hyperproof_api_url}/v1/tasks/${objectId}/proof?${query}`; - - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'GET', - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.GET, + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - debug(`POST ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.POST, - url, - await response.text() - ) - ); - } - - return response.json(); } /** @@ -532,33 +440,45 @@ export class HyperproofApiClient { const results = []; for (const proof of proofMeta as any) { const url = `${process.env.hyperproof_api_url}/beta/proof/${proof.id}/links/${objectId}/archive?objectType=task`; - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'POST', - body: JSON.stringify(user), - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON - } + const json = await this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: JSON.stringify(user), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + }, + onErrorResponse: response => + response.status === StatusCodes.NOT_FOUND + ? { shouldThrow: false } + : {} }); - if (!response.ok && response.status !== 404) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.POST, - url, - await response.text() - ) - ); - } - const proofArchive = await response.json(); - results.push(proofArchive); + results.push(json); } return results; } + + public async archiveProofLink({ + proofId, + objectId, + objectType, + externalUser + }: IArchiveProofLinkPost) { + const url = `${process.env.hyperproof_api_url}/beta/proof/${proofId}/links/${objectId}/archive?objectType=${objectType}`; + await this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: JSON.stringify(externalUser), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + } + }); + } + /** * Gets the comments in an object's activity feed * @@ -568,29 +488,9 @@ export class HyperproofApiClient { public async getComments(objectType: ObjectType, objectId: string) { const versionPath = objectType === ObjectType.TASK ? 'v1' : 'beta'; const url = `${process.env.hyperproof_api_url}/${versionPath}/${objectType}s/${objectId}/comments`; - const response = await HyperproofApiClient.fetchWithRetry(url, { - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey - } + return this.fetchWithRetry({ + url }); - - debug(`GET ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.GET, - url, - await response.text(), - objectType - ) - ); - } - - return response.json(); } /** @@ -650,68 +550,36 @@ export class HyperproofApiClient { */ public async getMe() { const url = `${process.env.hyperproof_api_url}/v1/users/me`; - - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'GET', - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.GET, + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - debug(`GET ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.GET, - url, - await response.text() - ) - ); - } - - return response.json(); } private async postNewProof( objectType: ObjectType, objectId: string, formData: FormData - ) { + ): Promise { let url = `${process.env.hyperproof_api_url}/v1`; if (objectType !== ObjectType.ORGANIZATION) { url += `/${objectType}s/${objectId}/proof`; } else { url += `/proof`; } - - const response = await HyperproofApiClient.fetchWithRetry(url, { - method: 'POST', - body: formData, - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: formData, + headers: {} } }); - debug(`POST ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - HttpMethod.POST, - url, - await response.text(), - objectType - ) - ); - } - - return response.json(); } /** @@ -725,14 +593,15 @@ export class HyperproofApiClient { * @param parentObjectId Optional - Unique ID of the parent object * @param commentId Optional - Unique id of comment in source system (i.e. in hyperproof or in jira) */ - private async sendCommentRequest( + public async sendCommentRequest( commentBody: ICommentBody, method: HttpMethod, objectType: ObjectType, objectId: string, parentObjectType?: ObjectType, parentObjectId?: string, - commentId?: string + commentId?: string, + sourceCommentId?: string ) { const parentPrefix = parentObjectType && parentObjectId @@ -743,34 +612,95 @@ export class HyperproofApiClient { if (commentId) { url += `/${commentId}`; } - const response = await HyperproofApiClient.fetchWithRetry(url, { - method, - body: JSON.stringify({ - ...commentBody, - objectType, - objectId - }), - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.Authorization]: `Bearer ${this.accessToken}`, - [HttpHeader.SubscriptionKey]: HyperproofApiClient.subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + const query = queryString.stringify({ sourceCommentId }); + url += `?${query}`; + return this.fetchWithRetry({ + url, + options: { + method, + body: JSON.stringify({ + ...commentBody, + objectType, + objectId + }), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + } + }); + } + + public async getNotificationIntegrationTokenLocation( + orgId: string, + objectType: ObjectType, + objectId: string + ) { + const url = `${process.env.hyperproof_api_url}/beta/integrations/tokenlocation`; + const requestBody = { + orgId: orgId, + objectTypePlural: `${objectType}s`, + objectId: objectId + }; + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: JSON.stringify(requestBody), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + }, + onErrorResponse: response => + response.status === StatusCodes.NOT_FOUND ? { shouldThrow: false } : {}, + onAnyFetchFailure: response => + response.status === StatusCodes.NOT_FOUND ? { shouldBreak: true } : {} + }); + } + + public async putIntegrationUpsert(integrationPost: IIntegrationPostSystem) { + const url = `${process.env.hyperproof_api_url}/beta/integrations/notifications/system`; + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.PUT, + body: JSON.stringify(integrationPost), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + } + }); + } + + public async createExternalConnection( + externalConnectionPost: IExternalConnectionPostSystem + ) { + const url = `${process.env.hyperproof_api_url}/beta/externalconnections/system`; + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.POST, + body: JSON.stringify(externalConnectionPost), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + } + }); + } + + public async deleteExternalConnection( + externalConnectionFilter: IExternalConnectionFilterSystem + ) { + const url = `${process.env.hyperproof_api_url}/beta/externalconnections/system`; + return this.fetchWithRetry({ + url, + options: { + method: HttpMethod.DELETE, + body: JSON.stringify(externalConnectionFilter), + headers: { + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } } }); - debug(`${method} ${url} - ${response.status}`); - if (!response.ok) { - throw createHttpError( - response.status, - createAndLogErrorMessage( - response.status, - method, - url, - await response.text(), - objectType - ) - ); - } - return response.json(); } private formatFilename(filename: string, mimeType: string) { @@ -815,40 +745,37 @@ export class HyperproofApiClient { return { filename: filename.replace(/\//g, ' '), mimeType }; } - private buildProofFormData( - file: Buffer, - filename: string, - mimeType: string, - sourceId?: string, - sourceFileId?: string, - sourceModifiedOn?: string, - user?: IExternalUser, - size?: number - ) { - if (size && Number(size) >= MAX_FILE_SIZE) { + private buildProofFormData(post: IProofPostBase) { + if (post.size && Number(post.size) >= MAX_FILE_SIZE) { const err = new Error( - `Proof from source ${sourceId} is larger than max file size.` + `Proof from source ${post.sourceId} is larger than max file size.` ); debug(err.message); throw err; } - const fileResults = this.formatFilename(filename, mimeType); - filename = fileResults.filename; - mimeType = fileResults.mimeType; + // Reformat the filename and mimeType if necessary + const { filename, mimeType } = this.formatFilename( + post.filename, + post.mimeType + ); const formData = new FormData(); - formData.append('proof', file, { filename, contentType: mimeType }); - if (sourceId) { - formData.append('hp-proof-source-id', sourceId); + formData.append('proof', post.file, { filename, contentType: mimeType }); + if (post.sourceId) { + formData.append('hp-proof-source-id', post.sourceId); + } + if (post.sourceFileId) { + formData.append('hp-proof-source-file-id', post.sourceFileId); } - if (sourceFileId) { - formData.append('hp-proof-source-file-id', sourceFileId); + if (post.sourceModifiedOn) { + formData.append('hp-proof-source-modified-on', post.sourceModifiedOn); } - if (sourceModifiedOn) { - formData.append('hp-proof-source-modified-on', sourceModifiedOn); + if (post.sourceIntegrationId) { + formData.append('hp-proof-integration-id', post.sourceIntegrationId); } - if (user) { + if (post.user) { + const user = post.user; if (user.id) { formData.append('hp-proof-ext-user-id', user.id); } @@ -877,3 +804,9 @@ export const createHyperproofApiClient = async ( ) => { return HyperproofApiClient.createInstance(integrationContext, orgId, userId); }; + +export const createHyperproofApiClientByAccessToken = async ( + accessToken: string +): Promise => { + return HyperproofApiClient.createInstanceByAccessToken(accessToken); +}; diff --git a/src/hyperproof-api/Logger.ts b/src/hyperproof-api/Logger.ts index c395c53..46bf7b9 100644 --- a/src/hyperproof-api/Logger.ts +++ b/src/hyperproof-api/Logger.ts @@ -1,6 +1,7 @@ import fetch from 'node-fetch'; import { debug } from '../add-on-sdk'; +import { createFetchOptions } from '../agent'; import { getAsyncStore } from '../asyncStore'; import { HttpHeader, MimeType } from '../models'; import { TraceParent } from '../TraceParent'; @@ -161,15 +162,18 @@ export class Logger { stack }; - const response = await fetch(url, { - method: 'POST', - body: JSON.stringify(logEvent), - headers: { - ...TraceParent.getHeaders(), - [HttpHeader.SubscriptionKey]: subscriptionKey, - [HttpHeader.ContentType]: MimeType.APPLICATION_JSON - } - }); + const response = await fetch( + url, + createFetchOptions(url, { + method: 'POST', + body: JSON.stringify(logEvent), + headers: { + ...TraceParent.getHeaders(), + [HttpHeader.SubscriptionKey]: subscriptionKey, + [HttpHeader.ContentType]: MimeType.APPLICATION_JSON + } + }) + ); if (!response.ok) { // Swallow error. Failure to log should not take down the operation const text = await response.text(); diff --git a/src/hyperproof-api/hyperproofTokens.ts b/src/hyperproof-api/hyperproofTokens.ts index f7550b4..a3972dd 100644 --- a/src/hyperproof-api/hyperproofTokens.ts +++ b/src/hyperproof-api/hyperproofTokens.ts @@ -5,6 +5,7 @@ import { StatusCodes } from 'http-status-codes'; import Superagent from 'superagent'; import { IntegrationContext } from '../add-on-sdk'; +import { getAgent } from '../agent'; import { AuthorizationType, IAuthorizationConfig, @@ -149,9 +150,9 @@ export const getHyperproofAccessToken = async ( 'Exchanging Hyperproof authorization code for an access token.' ); try { - const response = await Superagent.post( - process.env.hyperproof_oauth_token_url! - ) + const url = process.env.hyperproof_oauth_token_url!; + const response = await Superagent.post(url) + .agent(getAgent(url)) .type('form') .set({ ...TraceParent.getHeaders() }) .send({ @@ -200,9 +201,9 @@ const refreshHyperproofAccessToken = async ( `Refreshing Hyperproof API client using URL ${process.env.hyperproof_oauth_token_url}` ); const currentRefreshToken = hpUserContext.hyperproofToken.refresh_token; - const response = await Superagent.post( - process.env.hyperproof_oauth_token_url! - ) + const url = process.env.hyperproof_oauth_token_url!; + const response = await Superagent.post(url) + .agent(getAgent(url)) .type('form') .set({ ...TraceParent.getHeaders() }) .send({ @@ -252,7 +253,7 @@ export const ensureHyperproofAccessToken = async ( hyperproofToken.expires_at > Date.now() + ACCESS_TOKEN_EXPIRATION_BUFFER) ) { await Logger.info( - `Returning current Hyperpoof access token for user ${userKey}` + `Returning current Hyperproof access token for user ${userKey}` ); return hyperproofToken.access_token; } @@ -482,9 +483,9 @@ export const deleteHyperproofUser = async ( userId, instanceType ); - await Superagent.delete( - `${process.env.hyperproof_oauth_token_url}/organizations/${orgId}` - ) + const url = `${process.env.hyperproof_oauth_token_url}/organizations/${orgId}`; + await Superagent.delete(url) + .agent(getAgent(url)) .send({ client_secret: hyperproofClientSecret }) .set({ ...TraceParent.getHeaders(), diff --git a/src/index.ts b/src/index.ts index 61da7bc..d0852e6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,12 @@ -export * from './ApiClient'; -export * from './TraceParent'; +export * from './agent'; export * from './add-on-sdk'; +export * from './ApiClient'; +export * from './asyncStore'; export * from './express'; export * from './hyperproof-api'; export * from './managedConnector'; export * from './models'; export * from './oauth-connector'; export * from './sharedConnector'; +export * from './TraceParent'; export * from './util'; diff --git a/src/models/authModels.ts b/src/models/authModels.ts index 0fe56d4..a865b93 100644 --- a/src/models/authModels.ts +++ b/src/models/authModels.ts @@ -1,6 +1,8 @@ import { CredentialFieldType } from './credentials'; import { AuthorizationType } from './enums'; -import { ISelectOption, IValidation } from './hyperproofApiModels'; +import { ISelectOption } from './hyperproofApiModels'; + +import { IValidation } from '@hyperproof/hypersync-models'; /** * Metadata for a field that is used to provide credentials in a custom diff --git a/src/models/hyperproofApiModels.ts b/src/models/hyperproofApiModels.ts index 3c67942..092a486 100644 --- a/src/models/hyperproofApiModels.ts +++ b/src/models/hyperproofApiModels.ts @@ -1,10 +1,4 @@ -import { - AppId, - HealthStatus, - ObjectStatus, - ObjectType, - Priority -} from './enums'; +import { HealthStatus, ObjectStatus, ObjectType, Priority } from './enums'; export interface IApiObject { id: string; @@ -23,12 +17,15 @@ export interface IOrgObject extends ISystemObject { orgId: string; } -export interface IHyperproofUser extends ISystemObject { +export interface IHyperproofUser extends ISystemObject, ILocalizable { id: string; email: string; givenName: string; surname: string; updatedOn: string; +} + +export interface ILocalizable { language: string; locale: string; timeZone: string; @@ -43,11 +40,26 @@ export interface IExternalUser { avatarUrl?: string; } +export interface IExternalGroup { + id: string; + name: string; + avatarUrl?: string; +} + +export type ExternalPrincipal = IExternalUser | IExternalGroup; + +export interface IExternalGroupLink extends IOrgObject { + groupId?: string; + externalGroupId: string; + externalName: string; + instanceIntegrationId: string; +} + export interface ICommentBody { - appId: AppId; - commentTextFormatted: string; - externalUser: IExternalUser; - mentionedExternalUsers: IExternalUser[]; + appId?: string; + commentTextFormatted?: string; + externalUser?: IExternalUser; + mentionedExternalUsers?: IExternalUser[]; sourceCommentId: string; sourceUpdatedOn: string; } @@ -67,11 +79,13 @@ export interface ITaskSyncState { status: ITaskFieldSyncState; dueDate: ITaskFieldSyncState; comment: ITaskFieldSyncState; + group: ITaskFieldSyncState; } export interface ITaskFieldSyncState { syncedOn?: string; syncResult?: TaskSyncResult; + externalGroupLinkId?: string; externalUserId?: string; failureMessage?: string; } @@ -104,11 +118,44 @@ export interface IIntegration< settings: TIntegrationSettings; } +export interface IIntegrationPostSystem { + orgId: string; + appId: string; + settings: IIntegrationSettingsBase; + parentObjectTypePlural: string; + parentObjectId: string; + exteralConnectionId?: string; +} + +export interface IIntegrationFilterSystem { + appId: string; + orgId: string; + parentObjectTypePlural: string; + parentObjectId: string; +} + +export interface IExternalConnectionPostSystem { + externalUserId: string; + appId: string; + name: string; + accountName: string; + userId: string; + hostUrl: string; +} +export interface IExternalConnectionFilterSystem { + appIds: string[]; + externalUserId: string; + ownedBy?: string; + userId?: string; + hostUrl?: string; + includeArchived?: boolean; +} + export interface ITask extends IOrgObject { orgId: string; title: string; description?: string; - assigneeId: string; + assigneeId?: string; targetId: string; targetType: string; targetObjectStatus: ObjectStatus; @@ -125,26 +172,114 @@ export interface ITask extends IOrgObject { closedOn?: string; } +export interface ITaskStatus extends IOrgObject { + name: string; + type: TaskStatusType; + sortOrder: number; + icon: string; + color: string; +} + +export enum TaskStatusType { + NotStarted = 'notStarted', + InProgress = 'inProgress', + Submitted = 'submitted', + Closed = 'closed', + Cancelled = 'cancelled' +} + +// Used for updating a Hyperproof task export interface ITaskPatch { - taskStatusId?: string; - priority?: Priority; - dueDate?: string; clearDueDate?: boolean; + clearGroupId?: boolean; + comments?: IActivity[]; description?: string; - title?: string; - externalUser?: IExternalUser; + dueDate?: string; externalAssignee?: IExternalUser; externalFields?: any; + externalGroup?: IExternalGroup; + externalUser?: IExternalUser; + groupId?: string; + priority?: Priority; + taskStatusId?: string; taskTemplateId?: string; + ticketStatusId?: string; + title?: string; +} + +// Updates from the Hyperproof Task that should be applied to the external ticket +export interface ITicketPatch { + clearAssigneeId?: boolean; + clearDueDate?: boolean; comments?: IActivity[]; - externalUserLinkPairMap?: { - [userId: string]: { - externalUserLink?: IExternalUserLink; - organizationuser: IOrgUser; - }; + description?: string; + dueDate?: string; + externalAssignee?: IExternalUser; + externalFields?: any; + externalGroupLink?: IExternalGroupLink; + externalUser?: IExternalUser; + externalUserLinkPairMap?: IExternalUserLinkPairMap; + externalUserLinks?: IExternalUserLink[]; + group?: string; + priority?: Priority; + taskStatusId?: string; + taskTemplateId?: string; + ticketStatusId?: string; + title?: string; +} + +export interface IExternalFields { + [id: string]: string | string[] | object | number; +} + +export interface IExternalUserLinkPairMap { + [userId: string]: { + externalUserLink?: IExternalUserLink; + organizationUser: IOrgUser; }; } +export interface IProofPost extends IProofPostBase { + objectType: ObjectType; + objectId: string; +} + +export interface IProofVersionPost extends IProofPostBase { + proofId: string; +} + +export interface IProofPostBase { + file: Buffer; + filename: string; + mimeType: string; + sourceId?: string; + sourceFileId: string; + sourceModifiedOn?: string; + sourceIntegrationId?: string; + user?: IExternalUser; + size?: number; +} + +export interface IProof extends IOrgObject { + version: number; + ownedBy: string; + uploadedOn: string; + source: string; + sourceId?: string; + sourceIntegrationId?: string; + integrationStatus: string; + sourceFileId?: string; + sourceModifiedOn?: string; + providedByExternalUserLinkId?: string; +} + +export interface IArchiveProofLinkPost { + proofId: string; + objectId: string; + objectType: ObjectType; + externalUser?: IExternalUser; +} + export interface IActivity extends IOrgObject { createdByAppId: string; commentTextFormatted: string; @@ -194,6 +329,12 @@ export interface ICheckConnectionHealthInvocationPayload { export interface ITestExternalPermissionsBody { appId: string; + projectId?: string; + hostUrl: string; + externalConnectionId: string; + adminExternalConnectionId: string; + vendorUserId: string; + adminVendorUserId: string; [key: string]: any; } @@ -201,51 +342,40 @@ export interface ITestExternalPermissionsResponse { permissions: IExternalPermission[]; } +/** + * Object returned from the validateCredentials method. + * + * Ideally all validateCredentials implementers would return only the vendorUserId + * and vendorUserProfile members. But for historical reasons we also allow connectors + * to return other, arbitrary values which will be blended into the persisted user context. + */ +export interface IValidateCredentialsResponse { + vendorUserId: string; + vendorUserProfile?: object; + [key: string]: any; +} + export interface IExternalPermission { label: string; havePermission: boolean; required?: boolean; } -export interface IExTag { - id: string; - name: string; -} - /** - * IMPORTANT! - * Please keep the types below in sync with the same interface in + * An option that may be chosen in a select control. + * + * Please keep this in sync with the same interface in * @hyperproof/hypersync-models. We want to avoid a dependency * between the two libraries (hypersync-models is designed to - * be small and light) but we definitely need the interfaces in + * be small and light) but we definitely need the interface in * both places. */ - -/** - * An option that may be chosen in a select control. - */ export interface ISelectOption { value: string | number; label: string; } -export interface IValidation { - type: ValidationTypeString; - regex?: string; - errorMessage?: string; -} - -export enum ValidationTypes { - alphaNumeric = 'alphaNumeric', - regex = 'regex', - url = 'url', - urlOrHost = 'urlOrHost', - uuid = 'uuid' +export interface IExTag { + id: string; + name: string; } - -export type ValidationTypeString = - | 'alphaNumeric' - | 'regex' - | 'url' - | 'urlOrHost' - | 'uuid'; diff --git a/src/oauth-connector/OAuthConnector.ts b/src/oauth-connector/OAuthConnector.ts index 0bf846c..6659f2c 100644 --- a/src/oauth-connector/OAuthConnector.ts +++ b/src/oauth-connector/OAuthConnector.ts @@ -4,6 +4,7 @@ import { StatusCodes } from 'http-status-codes'; import Superagent from 'superagent'; import { IntegrationContext } from '../add-on-sdk'; +import { getAgent } from '../agent'; import { Logger } from '../hyperproof-api'; import { LogContextKey } from '../models'; @@ -26,15 +27,7 @@ export interface UserContext { timestamp: number; vendorUserId: string; vendorUserProfile: TVendorUserProfile; - vendorToken?: { - scope: string; - expires_at: number; - expires_in: number; - token_type: string; - access_token: string; - refresh_token: string; - ext_expires_in: number; - }; + vendorToken?: VendorToken; foreignOAuthIdentities?: { [key: string]: { userId: string; @@ -46,6 +39,16 @@ export interface UserContext { refreshErrorCount?: number; } +export interface VendorToken { + scope: string; + expires_at: number; + expires_in: number; + token_type: string; + access_token: string; + refresh_token: string; + ext_expires_in: number; +} + export class OAuthConnector { public accessTokenExpirationBuffer: number; public refreshErrorLimit: number; @@ -62,7 +65,7 @@ export class OAuthConnector { this.accessTokenExpirationBuffer = 30000; /** - * If refreshing an access token fails for refreshErrorLimit of consecutive times, the user is deleted. + * Not currently in use */ this.refreshErrorLimit = 10; @@ -216,9 +219,9 @@ export class OAuthConnector { authorizationCode: string, redirectUri: string ) { - const response = await Superagent.post( - integrationContext.configuration.oauth_token_url - ) + const url = integrationContext.configuration.oauth_token_url; + const response = await Superagent.post(url) + .agent(getAgent(url)) .type('form') .send({ grant_type: 'authorization_code', @@ -242,9 +245,9 @@ export class OAuthConnector { redirectUri: string ) { const currentRefreshToken = tokenContext.refresh_token; - const response = await Superagent.post( - integrationContext.configuration.oauth_token_url - ) + const url = integrationContext.configuration.oauth_token_url; + const response = await Superagent.post(url) + .agent(getAgent(url)) .type('form') .send({ grant_type: 'refresh_token', @@ -330,7 +333,7 @@ export class OAuthConnector { } /** - * Called after a new user successfuly completed a configuration flow and was persisted in the system. This extensibility + * Called after a new user successfully completed a configuration flow and was persisted in the system. This extensibility * point allows for creation of any artifacts required to serve this new user, for example creation of additional * Fusebit functions. * @param {IntegrationContext} integrationContext The integration context of the request @@ -435,6 +438,9 @@ export class OAuthConnector { vendorUserId: string, vendorId?: string ) { + await Logger.debug( + `(OauthConnector) Deleting user with vendorUserId: ${vendorUserId}, vendorId: ${vendorId}` + ); const userContext = await this.getUser( integrationContext, vendorUserId, @@ -501,14 +507,15 @@ export class OAuthConnector { ); if (oauthIdentity) { try { - const response = await Superagent.get( - `${oauthIdentity.connectorBaseUrl}/user/${encodeURIComponent( - oauthIdentity.userId - )}/token` - ).set( - 'Authorization', - `Bearer ${integrationContext.fusebit.functionAccessToken}` - ); + const url = `${ + oauthIdentity.connectorBaseUrl + }/user/${encodeURIComponent(oauthIdentity.userId)}/token`; + const response = await Superagent.get(url) + .agent(getAgent(url)) + .set( + 'Authorization', + `Bearer ${integrationContext.fusebit.functionAccessToken}` + ); return response.body; } catch (e: any) { throw new Error( @@ -523,28 +530,16 @@ export class OAuthConnector { }; const ensureLocalAccessToken = async () => { - if ( - userContext.vendorToken?.access_token && - (userContext.vendorToken.expires_at === undefined || - userContext.vendorToken.expires_at > - Date.now() + this.accessTokenExpirationBuffer) - ) { + if (this.isAccessTokenActive(userContext.vendorToken)) { + // Token is valid await Logger.info( `RETURNING CURRENT ACCESS TOKEN FOR USER ${userContext.vendorUserId}` ); return userContext.vendorToken; } - if (userContext.status === 'refresh_failed') { - await Logger.error( - `EXPIRED ACCESS TOKEN FOR USER ${userContext.vendorUserId}, THROWING UNAUTHORIZED` - ); - throw createHttpError( - StatusCodes.UNAUTHORIZED, - expiredRefreshTokenMessage - ); - } if (userContext.vendorToken?.refresh_token) { + // Token needs refresh await Logger.info( `REFRESHING ACCESS TOKEN FOR USER ${userContext.vendorUserId}` ); @@ -572,12 +567,14 @@ export class OAuthConnector { await this.saveUser(integrationContext, userContext); return userContext.vendorToken; } catch (e: any) { + // Token refresh failed const responseText = e.response?.text; if ( userContext.refreshErrorCount && userContext.refreshErrorCount > this.refreshErrorLimit ) { - const msg = `Credential "${userContext.vendorUserId}" has expired. This may be resolved by reauthorizing the connection. Unable to refresh token after ${this.refreshErrorLimit} attempts: ${e.message}`; + // At or above maximum refresh attempts + const msg = `Credential "${userContext.vendorUserId}" may have expired. This can be resolved by reauthorizing the connection. Error: ${e.message}`; userContext.status = 'refresh_failed'; userContext.lastRefreshError = msg; await this.saveUser(integrationContext, userContext); @@ -588,9 +585,10 @@ export class OAuthConnector { integrationContext.configuration?.oauth_token_url }); } else { + // Increment refresh failure counter userContext.refreshErrorCount = (userContext.refreshErrorCount || 0) + 1; - const msg = `Error refreshing access token, attempt ${userContext.refreshErrorCount} out of ${this.refreshErrorLimit}: ${e.message}`; + const msg = `Error refreshing access token, attempt ${userContext.refreshErrorCount}: ${e.message}`; userContext.status = 'refresh_error'; userContext.lastRefreshError = msg; await this.saveUser(integrationContext, userContext); @@ -690,6 +688,17 @@ export class OAuthConnector { } } + /** + * Evaluate whether the vendorToken.access_token is ready to use or not + */ + public isAccessTokenActive(vendorToken?: VendorToken): boolean { + return ( + vendorToken?.access_token !== undefined && + (vendorToken.expires_at === undefined || + vendorToken.expires_at > Date.now() + this.accessTokenExpirationBuffer) + ); + } + getStorageIdForVendorUser(id: string, foreignVendorId?: string) { return foreignVendorId ? `foreign-vendor-user/${encodeURIComponent( diff --git a/src/oauth-connector/app.ts b/src/oauth-connector/app.ts index 02153e4..a381365 100644 --- a/src/oauth-connector/app.ts +++ b/src/oauth-connector/app.ts @@ -14,7 +14,7 @@ const httpError = (res: express.Response, status: number, message: string) => { }); }; -export const createApp = (connector: OAuthConnector) => { +export const createApp = (connector: OAuthConnector): express.Express => { const app = express(); const settingsManager = createSettingsManager(createConfigure(connector)); diff --git a/src/oauth-connector/configure.ts b/src/oauth-connector/configure.ts index c82a8ce..1863df9 100644 --- a/src/oauth-connector/configure.ts +++ b/src/oauth-connector/configure.ts @@ -1,5 +1,8 @@ +import * as uuid from 'uuid'; import { OAuthConnector, UserContext } from './OAuthConnector'; +import { StatusCodes } from 'http-status-codes'; + import { completeWithSuccess, debug, @@ -10,8 +13,14 @@ import { serializeState } from '../add-on-sdk'; -const createHttpException = (message: string, state: any) => ({ - status: 500, +const SAVED_STATE_COOKIE = 'savedstate'; + +const createHttpException = ( + status: StatusCodes, + message: string, + state: any +) => ({ + status, message, state }); @@ -65,6 +74,7 @@ const configure = (connector: OAuthConnector) => { debug('ERROR POST-PROCESSING USER CONTEXT', e); await connector.deleteUser(ctx, vendorUserId); throw createHttpException( + StatusCodes.INTERNAL_SERVER_ERROR, `Error initializing new user: ${e.message}`, state ); @@ -85,11 +95,13 @@ const configure = (connector: OAuthConnector) => { debug('AUTH INIT', state, data); state.configurationState = 'authCallback'; + data.stateParam = uuid.v4().replace(/-/g, ''); state.data = data; + const serializedState = serializeState(state); const authorizationUrl = await connector.getAuthorizationUrl( ctx, - serializeState(state), + serializedState, `${ctx.baseUrl}/callback` ); @@ -107,7 +119,10 @@ const configure = (connector: OAuthConnector) => { } : { status: 302, - headers: { location: authorizationUrl } + headers: { + location: authorizationUrl, + ['set-cookie']: `${SAVED_STATE_COOKIE}=${serializedState}; Secure; HttpOnly` + } }; }; @@ -117,6 +132,32 @@ const configure = (connector: OAuthConnector) => { ) => { // Process OAuth callback + let savedState; + const cookieHeader = ctx.headers?.cookie; + if (cookieHeader) { + cookieHeader.split(';').forEach(cookie => { + // Can't use split--value may have = chars. + const index = cookie.indexOf('='); + if (index > 0) { + if ( + cookie.substring(0, index).trim().toLowerCase() === + SAVED_STATE_COOKIE + ) { + savedState = cookie.substring(index + 1).trim(); + } + } + }); + } + + if (serializeState(state) !== savedState) { + debug('CALLBACK STATE DOES NOT MATCH SAVED STATE'); + throw createHttpException( + StatusCodes.UNAUTHORIZED, + 'Error processing authorization code response.', + state + ); + } + let vendorUserId = ''; let userPersisted = false; let userContext: UserContext; @@ -149,6 +190,7 @@ const configure = (connector: OAuthConnector) => { await connector.deleteUser(ctx, vendorUserId); } throw createHttpException( + StatusCodes.INTERNAL_SERVER_ERROR, `Error exchanging the authorization code for an access token: ${e.message}`, state ); @@ -161,6 +203,7 @@ const configure = (connector: OAuthConnector) => { return settingsManagers(ctx, state, data); } else { throw createHttpException( + StatusCodes.INTERNAL_SERVER_ERROR, `Authentication failed: ${ ctx.query?.error_description || ctx.query?.error || 'Unknown error' }`, diff --git a/src/sharedConnector.ts b/src/sharedConnector.ts index 6c635d6..af81592 100644 --- a/src/sharedConnector.ts +++ b/src/sharedConnector.ts @@ -1,6 +1,7 @@ /* eslint-disable max-lines-per-function */ import * as express from 'express'; import { debug, IntegrationContext } from './add-on-sdk'; +import { createFetchOptions } from './agent'; import { asyncLocalStorage, IAsyncStore } from './asyncStore'; import { getHyperproofAccessToken, @@ -15,13 +16,16 @@ import { import { AuthorizationType, CustomAuthCredentials, + HealthStatus, HttpHeader, IAuthorizationConfigBase, ICheckConnectionHealthInvocationPayload, IConnectionHealth, ITestExternalPermissionsBody, ITestExternalPermissionsResponse, - LogContextKey + IValidateCredentialsResponse, + LogContextKey, + MimeType } from './models'; import { OAuthConnector, @@ -35,6 +39,7 @@ import createHttpError, { HttpError } from 'http-errors'; import { StatusCodes } from 'http-status-codes'; import path from 'path'; import { ParsedQs } from 'qs'; +import queryString from 'query-string'; /** * Representation of a user's connection to an external service. @@ -123,6 +128,45 @@ export const errorHandler = async ( } }; +export const getIntegrationsSystemAccessToken = async () => { + // get accessToken from Hyperproof Public API using Integrations System API + const clientId = process.env.integrations_system_api_client_id; + const clientSecret = process.env.integrations_system_api_client_secret; + + const url = process.env.hyperproof_oauth_token_url; + + const body = { + grant_type: 'client_credentials', + client_id: clientId, + client_secret: clientSecret + }; + + if (!url) { + throw new Error( + `Unable to get access token: no hyperproof_oauth_token_url is set.` + ); + } + const response = await fetch( + url, + createFetchOptions(url, { + method: 'POST', + headers: { + 'Content-Type': `${MimeType.FORM_URL_ENCODED};charset=UTF-8` + }, + body: queryString.stringify(body) + }) + ); + if (!response.ok) { + await Logger.error( + `Failed to get access token from Hyperproof Public API: ${await response.text()}` + ); + throw new Error(`Failed to get access token from Hyperproof Public API`); + } + const obj = await response.json(); + + return obj.access_token; +}; + /** * Dynamically creates a connector class that can be used as a base for a Hyperproof integration. * @@ -312,9 +356,13 @@ export function createConnector(superclass: typeof OAuthConnector) { ); /** - * Check a connection's health by vendorUserId + * Checks the health of connection for a given vendorUserId. + * This called by Hyperproof to verify that the connection is still valid and + * that the user can still access the service. Returns an IConnectionHealth object + * indicating the health status of a connection to include message, details, + * and resulting external service HTTP status code. */ - app.post( + app.put( [ '/organizations/:orgId/users/:userId/connections/:vendorUserId/connectionhealth' ], @@ -461,7 +509,7 @@ export function createConnector(superclass: typeof OAuthConnector) { }); return; } - this.serveStaticFile(req.query.fileName as string, res); + await this.serveStaticFile(req.query.fileName as string, res); } catch (err: any) { next(err); } @@ -558,7 +606,7 @@ export function createConnector(superclass: typeof OAuthConnector) { * @param {string} vendorUserId The vendor user id * @param {string} vendorId If specified, vendorUserId represents the identity of the user in another system. */ - async getHyperproofUserContext( + async getHyperproofUserContext( integrationContext: IntegrationContext, vendorUserId: string, vendorId?: string @@ -567,7 +615,7 @@ export function createConnector(superclass: typeof OAuthConnector) { integrationContext, vendorUserId, vendorId - )) as IHyperproofUserContext; + )) as IHyperproofUserContext; } /** @@ -650,7 +698,43 @@ export function createConnector(superclass: typeof OAuthConnector) { await integrationContext.storage.delete(location); } - /* eslint-disable @typescript-eslint/no-unused-vars */ + /** + * Validates custom auth credentials that are provided when creating a new + * new user connection. Designed to be overridden. + * + * @returns An object containing values to be persisted in UserContext. + */ + async validateCredentials( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + credentials: CustomAuthCredentials, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + integrationContext: IntegrationContext, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + hyperproofUserId: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + externalUserId: string + ): Promise { + throw createHttpError(StatusCodes.NOT_IMPLEMENTED, 'Not Implemented'); + } + + /** + * Validate access token of the OAuth connector. This must be implemented by the connector. + * + * The connector's implementation should not handle any error so that it can be handled in checkConnectionHealth + */ + async validateAccessToken( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + integrationContext: IntegrationContext, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + userContext: UserContext, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + accessToken: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + body?: ICheckConnectionHealthInvocationPayload + ): Promise { + throw createHttpError(StatusCodes.NOT_IMPLEMENTED, 'Not Implemented'); + } + async checkConnectionHealth( integrationContext: IntegrationContext, orgId: string, @@ -658,9 +742,128 @@ export function createConnector(superclass: typeof OAuthConnector) { vendorUserId: string, body?: ICheckConnectionHealthInvocationPayload ): Promise { - throw new Error('Must be implemented by the derived class.'); + try { + const userContext = await this.getHyperproofUserContext( + integrationContext, + vendorUserId + ); + + // we'll need to allow JiraHS to find its userContext using hostUrl + if (!userContext) { + throw createHttpError( + StatusCodes.NOT_FOUND, + this.getUserNotFoundMessage(vendorUserId) + ); + } + + if (this.authorizationType === AuthorizationType.CUSTOM) { + // NOTE: calling this will not save any token retrieved from the corresponding service to the vendor-user. + // In the case of AWS, the temporary token for cross-account role auth is saved in vendor-user for each sync, but not saved by validateCredentials itself. + // Since the token is temporary they will expire in an hour and way before AWS scheduled syncs are run and thus no reason to save it in this step. + await this.validateCredentials( + userContext.keys!, + integrationContext, + userId, + vendorUserId + ); + } else { + const tokenResponse = await this.ensureAccessToken( + integrationContext, + userContext + ); + + await this.validateAccessToken( + integrationContext, + userContext, + tokenResponse.access_token, + body + ); + } + } catch (e: any) { + // The connector can customize the health result status and message here. + // However custom connectors' validateCredentials may have already handled the + // error and threw a different error/status code. + const healthResult = this.handleHealthError(e); + + if (healthResult.healthStatus === HealthStatus.NotImplemented) { + await Logger.info( + `Connection health check found the connector did not implement validate credentials function.` + ); + } else if (healthResult.healthStatus === HealthStatus.Unhealthy) { + if (healthResult.statusCode === StatusCodes.NOT_FOUND) { + await Logger.info( + `Connection health check returned an unhealthy response: ${this.getUserNotFoundMessage( + vendorUserId + )}` + ); + } else { + await Logger.info( + `Connection health check returned an unhealthy response: ${healthResult.message}` + ); + } + } else if (healthResult.healthStatus === HealthStatus.Unknown) { + await Logger.warn( + `Connection health check returned an unknown error: ${healthResult.message}` + ); + } + + return healthResult; + } + + return { + healthStatus: HealthStatus.Healthy, + message: undefined, + details: undefined, + statusCode: StatusCodes.OK + }; + } + + getUserNotFoundMessage(vendorUserId: string) { + return `No ${this.connectorName} account found with id ${vendorUserId}. The connection may have been deleted.`; + } + + handleHealthError(error: any): IConnectionHealth { + const errorMessage = error.message; + const extendedErrorMessage = error[LogContextKey.ExtendedMessage]; + const healthResult: Readonly = { + healthStatus: HealthStatus.Unknown, + message: `Error: ${ + extendedErrorMessage ? extendedErrorMessage : errorMessage + }`, + details: undefined, + statusCode: error.statusCode || StatusCodes.INTERNAL_SERVER_ERROR + }; + const statusCode = error.statusCode ?? error.status; + switch (statusCode) { + case StatusCodes.NOT_FOUND: + return { + ...healthResult, + healthStatus: HealthStatus.Unhealthy, + message: `Hyperproof cannot connect to ${this.connectorName}, your credentials may have expired. Try Update Credentials in Hyperproof and if that doesn't fix the connection, contact your system admin.` + }; + case StatusCodes.UNAUTHORIZED: + case StatusCodes.FORBIDDEN: + return { + ...healthResult, + healthStatus: HealthStatus.Unhealthy, + message: extendedErrorMessage ? extendedErrorMessage : errorMessage + }; + case StatusCodes.NOT_IMPLEMENTED: + return { + ...healthResult, + healthStatus: HealthStatus.NotImplemented, + message: 'The function for validating token is not implemented.' + }; + case StatusCodes.SERVICE_UNAVAILABLE: + return { + ...healthResult, + healthStatus: HealthStatus.Unhealthy, + message: extendedErrorMessage ? extendedErrorMessage : errorMessage + }; + } + + return healthResult; } - /* eslint-enable @typescript-eslint/no-unused-vars */ /** * Awaitable sleep function. diff --git a/src/util/common.ts b/src/util/common.ts index f9fb1fa..e56a24e 100644 --- a/src/util/common.ts +++ b/src/util/common.ts @@ -1,3 +1,5 @@ +import crypto from 'crypto'; + import { debug, IntegrationContext, @@ -312,3 +314,11 @@ export const pickProps = ( * Removes any leading or trailing whitespace and trailing slashes from a URL */ export const trimUrl = (url: string) => url.trim().replace(/\/+$/, ''); + +/** + * Utility function to hash strings + * @param toHash string to hash + * @returns a hashed string + */ +export const computeHash = (toHash: string) => + crypto.createHash('sha256').update(toHash).digest('base64url'); diff --git a/src/util/index.ts b/src/util/index.ts index 966f9cb..be7f526 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -1,6 +1,6 @@ +export * from './common'; export * from './Dates'; export * from './RecordingManager'; -export * from './common'; export * from './sanitize'; export * from './stringHelpers'; export * from './throttle'; diff --git a/src/util/stringHelpers.ts b/src/util/stringHelpers.ts index 178e466..6150033 100644 --- a/src/util/stringHelpers.ts +++ b/src/util/stringHelpers.ts @@ -45,3 +45,9 @@ export const removeSurrounding = (str: string, char: string) => { export const removeSurroundingQuotes = (str: string) => { return removeSurrounding(str, '"'); }; + +export const formatString = (str: string, ...values: any) => { + return str.replace(/{(\d+)}/g, function (match, index) { + return typeof values[index] !== 'undefined' ? values[index] : match; + }); +}; diff --git a/src/util/throttle.ts b/src/util/throttle.ts index 6d2435b..d21a1f9 100644 --- a/src/util/throttle.ts +++ b/src/util/throttle.ts @@ -114,9 +114,16 @@ export class ThrottleManager { * @throws {ExternalAPIError} Any exception thrown by `_sendRequest()` is wrapped with an * `ExternalAPIError` instance and propagated. */ - async retrieve(request: RequestType): Promise { + async retrieve( + request: RequestType, + logger?: (response: any) => void + ): Promise { try { - return await this._sendRequest(request); + const response = await this._sendRequest(request); + if (logger) { + logger(response); + } + return response; } catch (e: any) { throw this._makeError(e); } @@ -177,7 +184,6 @@ export class ExternalAPIError { [ StatusCodes.TOO_MANY_REQUESTS, StatusCodes.GATEWAY_TIMEOUT, - StatusCodes.BAD_GATEWAY, StatusCodes.SERVICE_UNAVAILABLE ].includes(this.responseCode ?? 0) || /rate limit/i.test(this.message) || @@ -271,7 +277,10 @@ const jitteredBackoff = ( * @returns The first non-undefined attribute with one of the possible names found in one * of the targets, or `undefined` if no such attribute was found. */ -const findAttr = (possibleNames: (string | undefined)[], ...targets: any[]) => { +export const findAttr = ( + possibleNames: (string | undefined)[], + ...targets: any[] +) => { const lowercaseNames = possibleNames.map(name => name?.toLowerCase()); for (const target of targets) { if (target) { diff --git a/yarn.lock b/yarn.lock index 406d808..0f3a160 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,6 +7,274 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" + integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" + integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" + integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.6", "@babel/generator@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" + integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== + dependencies: + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== + dependencies: + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== + dependencies: + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" + integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" + integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== + dependencies: + "@babel/types" "^7.28.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/template@^7.28.6", "@babel/template@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" + integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" + integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -63,6 +331,253 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== +"@hyperproof/hypersync-models@6.0.0-beta": + version "6.0.0-beta" + resolved "https://registry.yarnpkg.com/@hyperproof/hypersync-models/-/hypersync-models-6.0.0-beta.tgz#0c05f264c721e91b489e9153c57ea17f595e482c" + integrity sha512-ep6jTQDbEuID2loJFSU0x/zo7DICU8xgW0H7Nc2iF3KE9n/Prn4ITmu6f2jbGSMoaR9VcN7a2UpGn8oNxouvSA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@js-joda/core@3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273" @@ -164,11 +679,63 @@ qs "^6.10.1" url-parse "^1.5.3" +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + "@sindresorhus/fnv1a@^2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@sindresorhus/fnv1a/-/fnv1a-2.0.1.tgz#2aefdfa7eb5b7f29a7936978218e986c70c603fc" integrity sha512-suq9tRQ6bkpMukTG5K5z0sPWB7t0zExMzZCdmYm6xTSSIm/yCKNm7VCL36wVeyTsFr597/UhU1OAYdHGMDiHrw== +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -209,11 +776,45 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + "@types/http-errors@*": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.1.tgz#20172f9578b225f6c7da63446f56d4ce108d5a65" integrity sha512-/K3ds8TRAfBvi5vfjuz8y6+GiAYBZ0x4tXv1Av6CWBWn0IlADc+ZX9pMq7oU0fNQPnBwIZl3rmeLp6SBApbxSQ== +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.5.4": + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + "@types/methods@^1.1.4": version "1.1.4" resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.4.tgz#d3b7ac30ac47c91054ea951ce9eed07b1051e547" @@ -229,13 +830,13 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== -"@types/node-fetch@^2.6.11": - version "2.6.11" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.11.tgz#9b39b78665dae0e82a08f02f4967d62c66f95d24" - integrity sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g== +"@types/node-fetch@^2.6.13": + version "2.6.13" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.13.tgz#e0c9b7b5edbdb1b50ce32c127e85e880872d56ee" + integrity sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw== dependencies: "@types/node" "*" - form-data "^4.0.0" + form-data "^4.0.4" "@types/node@*": version "20.4.9" @@ -276,6 +877,11 @@ dependencies: "@types/node" "*" +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + "@types/superagent@^8.1.9": version "8.1.9" resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-8.1.9.tgz#28bfe4658e469838ed0bf66d898354bcab21f49f" @@ -286,6 +892,23 @@ "@types/node" "*" form-data "^4.0.0" +"@types/uuid@^8.3.1": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@8.7.0": version "8.7.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.7.0.tgz#d0070f206daad26253bf00ca5b80f9b54f9e2dd0" @@ -407,6 +1030,18 @@ ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -419,11 +1054,31 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -444,11 +1099,79 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +baseline-browser-mapping@^2.9.0: + version "2.9.17" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.17.tgz#9d6019766cd7eba738cb5f32c84b9f937cc87780" + integrity sha512-agD0MgJFUP/4nvjqzIB29zRPUuCF7Ge6mEv9s8dHrtYD7QWXRcx75rOADE/d5ah1NI+0vkDl0yorDd5U852IQQ== + basic-auth@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" @@ -524,6 +1247,31 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== + dependencies: + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-equal-constant-time@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" @@ -539,6 +1287,14 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -563,6 +1319,21 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001759: + version "1.0.30001765" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001765.tgz#4a78d8a797fd4124ebaab2043df942eb091648ee" + integrity sha512-LWcNtSyZrakjECqmpP4qdg0MMGdN368D7X8XvvAqOcqMv0RxnlqVKZl2V6/mBR68oYMxOZPLw/gO7DuisMHUvQ== + chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -571,6 +1342,21 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -580,6 +1366,25 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -626,6 +1431,11 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" @@ -636,6 +1446,11 @@ cookie@0.6.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== + cookiejar@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" @@ -667,6 +1482,19 @@ cors@^2.8.5: object-assign "^4" vary "^1" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -676,6 +1504,15 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.3: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + cssfilter@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/cssfilter/-/cssfilter-0.0.10.tgz#c6d2672632a2e5c83e013e6864a42ce8defd20ae" @@ -695,6 +1532,13 @@ debug@^4.1.0, debug@^4.3.2, debug@^4.3.4: dependencies: ms "2.1.2" +debug@^4.1.1: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + debug@^4.3.1: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" @@ -707,11 +1551,21 @@ decode-uri-component@^0.2.2: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== +dedent@^1.0.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.1.tgz#364661eea3d73f3faba7089214420ec2f8f13e15" + integrity sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" @@ -736,6 +1590,11 @@ destroy@1.2.0: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + dezalgo@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" @@ -744,6 +1603,11 @@ dezalgo@^1.0.4: asap "^2.0.0" wrappy "1" +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + diff@^3.1.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -756,6 +1620,15 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ecdsa-sig-formatter@1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" @@ -768,6 +1641,16 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== +electron-to-chromium@^1.5.263: + version "1.5.267" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7" + integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -783,6 +1666,13 @@ encodeurl@~2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== +error-ex@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== + dependencies: + is-arrayish "^0.2.1" + es-define-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" @@ -790,21 +1680,53 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + es-errors@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" @@ -886,6 +1808,11 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + esquery@^1.4.2: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" @@ -920,17 +1847,48 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -express@4.21.0: - version "4.21.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" - integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +express@4.21.2: + version "4.21.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32" + integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA== dependencies: accepts "~1.3.8" array-flatten "1.1.1" body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.6.0" + cookie "0.7.1" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" @@ -944,7 +1902,7 @@ express@4.21.0: methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.10" + path-to-regexp "0.1.12" proxy-addr "~2.0.7" qs "6.13.0" range-parser "~1.2.1" @@ -1010,7 +1968,7 @@ fast-glob@^3.3.2: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -1032,6 +1990,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1077,6 +2042,14 @@ finalhandler@1.3.1: statuses "2.0.1" unpipe "~1.0.0" +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" @@ -1098,14 +2071,16 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== -form-data@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682" - integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg== +form-data@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.4.tgz#938273171d3f999286a4557528ce022dc2c98df1" + integrity sha512-f0cRzm6dkyVYV3nPoooP8XlccPQukegwhAnpoLcXy+X+A8KfpGOoXwDr9FLZd3wzgLaBGQBE3lY93Zm/i1JvIQ== dependencies: asynckit "^0.4.0" combined-stream "^1.0.8" - mime-types "^2.1.12" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.35" form-data@^4.0.0: version "4.0.0" @@ -1116,6 +2091,17 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" +form-data@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + formidable@^3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/formidable/-/formidable-3.5.1.tgz#9360a23a656f261207868b1484624c4c8d06ee1a" @@ -1149,6 +2135,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" @@ -1159,6 +2150,11 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -1185,6 +2181,40 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -1199,7 +2229,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.0.5, glob@^7.1.3: +glob@^7.0.5, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -1225,7 +2255,12 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.6, graceful-fs@^4.2.0: +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -1235,6 +2270,18 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -1257,6 +2304,18 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -1264,7 +2323,7 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -1281,6 +2340,11 @@ html-entities@2.5.2: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + http-errors@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -1304,6 +2368,11 @@ http-status-codes@2.3.0: resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.3.0.tgz#987fefb28c69f92a43aecc77feec2866349a8bfc" integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1329,6 +2398,14 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -1357,6 +2434,18 @@ is-absolute-url@^3.0.3: resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1367,6 +2456,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -1384,6 +2478,11 @@ is-path-inside@^3.0.3: resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -1399,6 +2498,440 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@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" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-junit@^12.2.0: + version "12.3.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.3.0.tgz#ee41a74e439eecdc8965f163f83035cce5998d6d" + integrity sha512-+NmE5ogsEjFppEl90GChrk7xgz8xzvF0f+ZT5AnhW6suJC93gvQtmQjfyjDnE0Z2nXJqEkxF0WXlvjG/J+wn/g== + dependencies: + mkdirp "^1.0.4" + strip-ansi "^5.2.0" + uuid "^8.3.2" + xml "^1.0.1" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.6.4: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -1406,6 +2939,16 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -1421,6 +2964,11 @@ json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonfile@^6.0.1: version "6.1.0" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" @@ -1463,6 +3011,16 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1471,6 +3029,18 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" @@ -1513,6 +3083,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -1528,6 +3103,13 @@ loglevel@^1.8.0: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.9.1.tgz#d63976ac9bcd03c7c873116d41c2a85bafff1be7" integrity sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg== +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -1535,11 +3117,30 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-error@^1.1.1: +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1, make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -1555,6 +3156,11 @@ merge-descriptors@1.0.3: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -1583,7 +3189,7 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -1605,7 +3211,12 @@ mime@3.0.0: resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== -minimatch@^3.0.3, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -1619,6 +3230,11 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" +minimist@^1.2.5: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" @@ -1667,6 +3283,11 @@ negotiator@0.6.3: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + nocache@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/nocache/-/nocache-3.0.4.tgz#5b37a56ec6e09fc7d401dceaed2eab40c8bfdf79" @@ -1688,6 +3309,16 @@ node-fetch@2.7.0: dependencies: whatwg-url "^5.0.0" +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== + noms@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859" @@ -1696,6 +3327,18 @@ noms@0.0.0: inherits "^2.0.1" readable-stream "~1.0.31" +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + object-assign@^4: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -1737,6 +3380,13 @@ once@^1.3.0, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -1749,13 +3399,27 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" -p-limit@^3.0.2: +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" @@ -1763,6 +3427,11 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -1770,6 +3439,16 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -1785,26 +3464,48 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-to-regexp@0.1.10: - version "0.1.10" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" - integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7" + integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ== path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== -picomatch@^2.3.1: +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -1815,11 +3516,28 @@ prettier@^2.6.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + propagate@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" @@ -1838,6 +3556,11 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + qs@6.11.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" @@ -1894,6 +3617,11 @@ raw-body@2.5.2: iconv-lite "0.4.24" unpipe "1.0.0" +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + readable-stream@~1.0.31: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -1927,11 +3655,37 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== + +resolve@^1.20.0: + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -1971,6 +3725,16 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + semver@^7.5.4: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" @@ -2094,11 +3858,34 @@ side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slugify@^1.6.3: version "1.6.6" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.6.tgz#2d4ac0eacb47add6af9e04d3be79319cbcc7924b" integrity sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-support@^0.5.6: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -2107,7 +3894,7 @@ source-map-support@^0.5.6: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -2117,6 +3904,18 @@ split-on-first@^1.0.0: resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -2127,7 +3926,15 @@ strict-uri-encode@^2.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ== -string-width@^4.1.0, string-width@^4.2.0: +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2148,6 +3955,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -2155,6 +3969,16 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2182,6 +4006,27 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -2195,6 +4040,11 @@ through2@^2.0.1: readable-stream "~2.3.6" xtend "~4.0.1" +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2217,6 +4067,21 @@ ts-api-utils@^1.3.0: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== +ts-jest@^29.1.1: + version "29.4.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.4.6.tgz#51cb7c133f227396818b71297ad7409bb77106e9" + integrity sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA== + dependencies: + bs-logger "^0.2.6" + fast-json-stable-stringify "^2.1.0" + handlebars "^4.7.8" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.3" + type-fest "^4.41.0" + yargs-parser "^21.1.1" + ts-node@8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.2.tgz#9ecdf8d782a0ca4c80d1d641cbb236af4ac1b756" @@ -2235,11 +4100,26 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^4.41.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -2253,6 +4133,11 @@ typescript@5.5.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -2268,6 +4153,14 @@ untildify@^4.0.0: resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -2298,11 +4191,37 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== +uuid@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294" + integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -2323,6 +4242,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -2337,6 +4261,19 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== + xss@1.0.15: version "1.0.15" resolved "https://registry.yarnpkg.com/xss/-/xss-1.0.15.tgz#96a0e13886f0661063028b410ed1b18670f4e59a" @@ -2355,6 +4292,11 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -2365,6 +4307,11 @@ yargs-parser@^20.2.2: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs@^16.1.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" @@ -2378,6 +4325,19 @@ yargs@^16.1.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yn@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"