diff --git a/.circleci/config.yml b/.circleci/config.yml index 3777fe028..cb62d62d1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: build: docker: - image: cimg/node:lts-browsers - resource_class: xlarge + resource_class: 2xlarge steps: - checkout - restore_cache: diff --git a/README.md b/README.md index 339acd9a8..b8197675c 100644 --- a/README.md +++ b/README.md @@ -238,10 +238,16 @@ For other comprehensive examples, see the [EXAMPLES.md](https://github.com/auth0 ## API Reference -### Server (for Node.js) +### Server + +#### For Node `import * from @auth0/nextjs-auth0` +#### For Edge runtime + +`import * from @auth0/nextjs-auth0/edge` + - [Configuration Options and Environment variables](https://auth0.github.io/nextjs-auth0/modules/config.html) - [initAuth0](https://auth0.github.io/nextjs-auth0/modules/index.html#initauth0) - [handleAuth](https://auth0.github.io/nextjs-auth0/modules/handlers_auth.html) @@ -254,15 +260,7 @@ For other comprehensive examples, see the [EXAMPLES.md](https://github.com/auth0 - [getSession](https://auth0.github.io/nextjs-auth0/modules/session_get_session.html) - [updateSession](https://auth0.github.io/nextjs-auth0/modules/session_update_session.html) - [getAccessToken](https://auth0.github.io/nextjs-auth0/modules/session_get_access_token.html) - -### Edge (for Middleware and the Edge runtime) - -`import * from @auth0/nextjs-auth0/edge` - -- [Configuration Options and Environment variables](https://auth0.github.io/nextjs-auth0/modules/config.html) -- [initAuth0](https://auth0.github.io/nextjs-auth0/modules/edge.html#initauth0-1) -- [withMiddlewareAuthRequired](https://auth0.github.io/nextjs-auth0/modules/helpers_with_middleware_auth_required.html) -- [getSession](https://auth0.github.io/nextjs-auth0/modules/edge.html#getsession-1) +- [withMiddlewareAuthRequired](https://auth0.github.io/nextjs-auth0/modules/helpers_with_middleware_auth_required.html) (Edge only) ### Client (for the Browser) diff --git a/cypress/e2e/smoke.cy.ts b/cypress/e2e/smoke.cy.ts index 46c59e16b..7eb5d5492 100644 --- a/cypress/e2e/smoke.cy.ts +++ b/cypress/e2e/smoke.cy.ts @@ -120,4 +120,42 @@ describe('smoke tests', () => { cy.get('[data-testid=login]').should('exist'); }); }); + describe('app router (edge)', () => { + it('should render an app route', () => { + cy.visit('/edge-profile'); + login(); + cy.url().should('eq', `${Cypress.config().baseUrl}/edge-profile`); + cy.get('[data-testid=profile]').contains(EMAIL); + cy.get('[data-testid=logout-edge]').click(); + }); + + it('should protect an api', () => { + cy.request({ url: '/api/edge-profile', failOnStatusCode: false }).as('unauthorized-edge'); + + cy.get('@unauthorized-edge').should((response: any) => { + expect(response.status).to.eq(401); + expect(response.body.error).to.eq('not_authenticated'); + }); + }); + + it('should access an api', () => { + cy.visit('/edge-profile-api'); + login(); + + cy.url().should('eq', `${Cypress.config().baseUrl}/edge-profile-api`); + cy.get('[data-testid=profile-api]').contains(EMAIL); + }); + + it('should logout and return to the index page', () => { + cy.visit('/edge-profile'); + login(); + cy.url().should('eq', `${Cypress.config().baseUrl}/edge-profile`); + cy.get('[data-testid=logout-edge]').click(); + if (!useAuth0) { + cy.get('[name=logout]').click(); + } + cy.url().should('eq', `${Cypress.config().baseUrl}/`); + cy.get('[data-testid=login-edge]').should('exist'); + }); + }); }); diff --git a/example-app/app/api/edge-auth/[auth0]/route.ts b/example-app/app/api/edge-auth/[auth0]/route.ts new file mode 100644 index 000000000..3b9dab536 --- /dev/null +++ b/example-app/app/api/edge-auth/[auth0]/route.ts @@ -0,0 +1,17 @@ +import { handleAuth, handleLogin, handleCallback } from '@auth0/nextjs-auth0/edge'; + +const redirectUri = `${process.env.AUTH0_BASE_URL}/api/edge-auth/callback`; + +export const GET = handleAuth({ + login: handleLogin({ + authorizationParams: { redirect_uri: redirectUri } + }), + callback: handleCallback({ redirectUri }), + onError(req: Request, error: Error) { + console.error(error); + } +}); + +export const runtime = 'edge'; +//https://github.com/vercel/next.js/issues/51642 +export const fetchCache = 'force-no-store'; diff --git a/example-app/app/api/edge-profile/route.ts b/example-app/app/api/edge-profile/route.ts new file mode 100644 index 000000000..65b0ee598 --- /dev/null +++ b/example-app/app/api/edge-profile/route.ts @@ -0,0 +1,12 @@ +import { getSession, withApiAuthRequired } from '@auth0/nextjs-auth0/edge'; +import { NextResponse } from 'next/server'; + +const GET = withApiAuthRequired(async () => { + const session = await getSession(); + + return NextResponse.json(session?.user); +}); + +export { GET }; + +export const runtime = 'edge'; diff --git a/example-app/app/edge-profile-api/page.tsx b/example-app/app/edge-profile-api/page.tsx new file mode 100644 index 000000000..c0c5d9596 --- /dev/null +++ b/example-app/app/edge-profile-api/page.tsx @@ -0,0 +1,23 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import { withPageAuthRequired } from '@auth0/nextjs-auth0/client'; + +export default withPageAuthRequired(function ProfileApi() { + const [user, setUser] = useState(); + + useEffect(() => { + (async () => { + const res = await fetch(`${window.location.origin}/api/edge-profile`); + setUser(await res.json()); + })(); + }, []); + + return ( +
+

Profile (fetched from API)

+

User

+
{JSON.stringify(user, null, 2)}
+
+ ); +}); diff --git a/example-app/app/edge-profile/page.tsx b/example-app/app/edge-profile/page.tsx new file mode 100644 index 000000000..e3962fe1b --- /dev/null +++ b/example-app/app/edge-profile/page.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { getSession, withPageAuthRequired } from '@auth0/nextjs-auth0/edge'; + +export default withPageAuthRequired( + async function Page() { + const session = await getSession(); + + return ( +
+

Profile

+

Page:

+

Access Token

+
{JSON.stringify({ accessToken: session?.accessToken }, null, 2)}
+

User

+
{JSON.stringify(session?.user, null, 2)}
+
+ ); + }, + { returnTo: '/edge-profile' } +); + +export const runtime = 'edge'; diff --git a/example-app/app/globals.css b/example-app/app/globals.css index ef5fae192..9920ca83c 100644 --- a/example-app/app/globals.css +++ b/example-app/app/globals.css @@ -24,7 +24,7 @@ ul { li { margin-right: 1rem; } -.header.secondary li:nth-last-child(2) { +.header.secondary li:nth-last-child(3) { margin-right: auto; } .header a { @@ -32,10 +32,12 @@ li { text-decoration: none; } .header.home a[href='/'], -.header.page-router a[href$='page-router'], -.header.profile a[href$='profile'], -.header.profile-middleware a[href$='profile-middleware'], -.header.profile-api a[href$='profile-api'], +.header.page-router a[href$='/page-router'], +.header.profile a[href$='/profile'], +.header.edge-profile a[href$='/edge-profile'], +.header.profile-middleware a[href$='/profile-middleware'], +.header.profile-api a[href$='/profile-api'], +.header.edge-profile-api a[href$='/edge-profile-api'], a.active { color: #888; } diff --git a/example-app/app/nav.tsx b/example-app/app/nav.tsx index 6f2cde643..c7806e83e 100644 --- a/example-app/app/nav.tsx +++ b/example-app/app/nav.tsx @@ -41,28 +41,52 @@ export default function Nav() { Profile +
  • + + Profile (Edge) + +
  • Profile (API)
  • +
  • + + Profile (API / Edge) + +
  • Profile (Middleware)
  • {' '} {user ? ( -
  • - - Logout - -
  • + <> +
  • + + Logout + +
  • +
  • + + Logout (Edge) + +
  • + ) : ( -
  • - - Login - -
  • + <> +
  • + + Login + +
  • +
  • + + Login (Edge) + +
  • + )} diff --git a/example-app/app/profile-api/page.tsx b/example-app/app/profile-api/page.tsx index 21c4d21e2..c0c5d9596 100644 --- a/example-app/app/profile-api/page.tsx +++ b/example-app/app/profile-api/page.tsx @@ -8,7 +8,7 @@ export default withPageAuthRequired(function ProfileApi() { useEffect(() => { (async () => { - const res = await fetch(`${window.location.origin}/api/profile`); + const res = await fetch(`${window.location.origin}/api/edge-profile`); setUser(await res.json()); })(); }, []); diff --git a/example-app/middleware.ts b/example-app/middleware.ts index e62cf4f1c..7c1200309 100644 --- a/example-app/middleware.ts +++ b/example-app/middleware.ts @@ -1,8 +1,6 @@ -import { initAuth0 } from '@auth0/nextjs-auth0/edge'; +import { withMiddlewareAuthRequired } from '@auth0/nextjs-auth0/edge'; -const auth0 = initAuth0({ routes: { login: '/api/page-router-auth/login' } }); - -export default auth0.withMiddlewareAuthRequired(); +export default withMiddlewareAuthRequired(); export const config = { matcher: ['/page-router/profile-middleware', '/profile-middleware'] diff --git a/example-app/pages/api/page-router-auth/[...auth0].ts b/example-app/pages/api/page-router-auth/[...auth0].ts index 5f7d39fb5..1c15c7a8a 100644 --- a/example-app/pages/api/page-router-auth/[...auth0].ts +++ b/example-app/pages/api/page-router-auth/[...auth0].ts @@ -1,28 +1,11 @@ -import { NextApiRequest, NextApiResponse } from 'next'; -import { Session, LoginOptions } from '@auth0/nextjs-auth0'; -import { pageRouterAuth } from '../../../lib/auth0'; +import { pageRouterAuth } from '@/lib/auth0'; + +const redirectUri = `${process.env.AUTH0_BASE_URL}/api/page-router-auth/callback`; export default pageRouterAuth.handleAuth({ login: pageRouterAuth.handleLogin({ - authorizationParams: { redirect_uri: `${process.env.AUTH0_BASE_URL}/api/page-router-auth/callback` }, - getLoginState(req: NextApiRequest, options: LoginOptions) { - return { - returnTo: options.returnTo, - foo: 'bar' - }; - } - }), - callback: pageRouterAuth.handleCallback({ - redirectUri: `${process.env.AUTH0_BASE_URL}/api/page-router-auth/callback`, - afterCallback(_req: NextApiRequest, _res: NextApiResponse, session: Session) { - return { ...session, foo: 'bar' }; - } - }), - me: pageRouterAuth.handleProfile({ - refetch: true, - afterRefetch(req: NextApiRequest, res: NextApiResponse, session: Session) { - return { ...session, foo: 'bar' }; - } + authorizationParams: { redirect_uri: redirectUri } }), + callback: pageRouterAuth.handleCallback({ redirectUri }), logout: pageRouterAuth.handleLogout({ returnTo: `${process.env.AUTH0_BASE_URL}/page-router` }) }); diff --git a/example-app/server.js b/example-app/server.js index 136f2445e..eb2036f36 100644 --- a/example-app/server.js +++ b/example-app/server.js @@ -6,9 +6,10 @@ const port = +(process.env.PORT || 3000); const app = next({ dev: true, hostname: 'localhost', port }); const handle = app.getRequestHandler(); -process.env.AUTH0_ISSUER_BASE_URL = `http://localhost:${port}/oidc`; +process.env.AUTH0_ISSUER_BASE_URL = `http://localhost:${port}/oidc/`; process.env.AUTH0_CLIENT_ID = 'testing'; process.env.AUTH0_CLIENT_SECRET = 'testing'; +process.env.AUTH0_SCOPE = 'openid profile email offline_access'; app .prepare() diff --git a/jest-base.config.js b/jest-base.config.js new file mode 100644 index 000000000..65bd5b054 --- /dev/null +++ b/jest-base.config.js @@ -0,0 +1,9 @@ +/** @type {import('jest').Config} */ +module.exports = { + rootDir: '.', + moduleFileExtensions: ['ts', 'tsx', 'js'], + preset: 'ts-jest/presets/js-with-ts', + globalSetup: './tests/global-setup.ts', + setupFilesAfterEnv: ['./tests/setup.ts'], + transformIgnorePatterns: ['/node_modules/(?!oauth4webapi)'] +}; diff --git a/jest-edge.config.js b/jest-edge.config.js new file mode 100644 index 000000000..19bfac4db --- /dev/null +++ b/jest-edge.config.js @@ -0,0 +1,18 @@ +const base = require('./jest-base.config'); + +/** @type {import('jest').Config} */ +module.exports = { + ...base, + displayName: 'edge', + testEnvironment: '@edge-runtime/jest-environment', + testMatch: [ + '**/tests/handlers/login.test.ts', + '**/tests/handlers/logout.test.ts', + '**/tests/handlers/callback.test.ts', + '**/tests/handlers/profile.test.ts', + '**/tests/http/auth0-next-request.test.ts', + '**/tests/http/auth0-next-response.test.ts', + '**/tests/helpers/with-middleware-auth-required.test.ts', + '**/tests/session/get-access-token.test.ts' + ] +}; diff --git a/jest-node.config.js b/jest-node.config.js new file mode 100644 index 000000000..ac525efe2 --- /dev/null +++ b/jest-node.config.js @@ -0,0 +1,8 @@ +const base = require('./jest-base.config'); + +/** @type {import('jest').Config} */ +module.exports = { + ...base, + displayName: 'node', + testEnvironment: 'jest-environment-node-single-context' +}; diff --git a/package-lock.json b/package-lock.json index d3e63befa..09a998478 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,15 +12,15 @@ "@panva/hkdf": "^1.0.2", "cookie": "^0.5.0", "debug": "^4.3.4", - "http-errors": "^1.8.1", "joi": "^17.6.0", "jose": "^4.9.2", + "oauth4webapi": "^2.3.0", "openid-client": "^5.2.1", "tslib": "^2.4.0", "url-join": "^4.0.1" }, "devDependencies": { - "@edge-runtime/jest-environment": "^1.1.0-beta.31", + "@edge-runtime/jest-environment": "^2.1.0", "@testing-library/jest-dom": "^5.11.9", "@testing-library/react": "^13.4.0", "@testing-library/react-hooks": "^5.0.3", @@ -28,10 +28,10 @@ "@types/clone": "^2.1.0", "@types/cookie": "^0.5.1", "@types/debug": "^4.1.5", - "@types/http-errors": "^1.8.0", - "@types/jest": "^27.0.1", + "@types/jest": "^29.5.2", "@types/jsonwebtoken": "^8.5.0", "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", "@types/on-headers": "^1.0.0", "@types/react": "^18.0.24", "@types/react-dom": "^17.0.9", @@ -51,10 +51,12 @@ "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", - "jest": "^27.2.0", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", "jest-environment-node-single-context": "^27.3.0", - "next": "^13.4.5-canary.0", + "next": "^13.4.6", "nock": "^13.0.5", + "node-fetch": "^2.6.11", "oidc-provider": "^7.6.0", "on-headers": "^1.0.2", "prettier": "^2.2.1", @@ -65,7 +67,7 @@ "start-server-and-test": "^1.11.7", "timekeeper": "^2.2.0", "tough-cookie": "^4.0.0", - "ts-jest": "^27.0.5", + "ts-jest": "^29.1.0", "typedoc": "^0.24.1", "typescript": "^4.1.3" }, @@ -82,6 +84,19 @@ "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", "dev": true }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -92,35 +107,35 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", + "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.15.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz", - "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.5", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.2", + "semver": "^6.3.0" }, "engines": { "node": ">=6.9.0" @@ -131,17 +146,23 @@ } }, "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, "node_modules/@babel/core/node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -154,47 +175,31 @@ "node": ">=6" } }, - "node_modules/@babel/core/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@babel/generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz", - "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", + "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", + "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { @@ -204,186 +209,167 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" + "yallist": "^3.0.2" } }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", + "node_modules/@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", + "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", "dev": true, "dependencies": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, - "dependencies": { - "@babel/types": "^7.15.4" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", + "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", "dev": true, "dependencies": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -454,9 +440,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -525,6 +511,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -613,12 +614,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -640,44 +641,45 @@ } }, "node_modules/@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", + "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -686,12 +688,12 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -707,12 +709,13 @@ } }, "node_modules/@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -826,34 +829,20 @@ } }, "node_modules/@edge-runtime/jest-environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/jest-environment/-/jest-environment-1.1.0.tgz", - "integrity": "sha512-YwiR+zxAt3BksS1DrOuVdqnDw+18EZxm3vpGo8vuxqKXOg9UNdmj7c3nfkdTdhQ3gr3+sSpcS/4+vLoqW1QSKA==", - "dev": true, - "dependencies": { - "@edge-runtime/vm": "1.1.0", - "@jest/environment": "28.1.3", - "@jest/fake-timers": "28.1.3", - "@jest/types": "28.1.3", - "jest-mock": "28.1.3", - "jest-util": "28.1.3" - } - }, - "node_modules/@edge-runtime/jest-environment/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/jest-environment/-/jest-environment-2.1.0.tgz", + "integrity": "sha512-NzBLXK6FG59xKDmKo8ad0gV1HrlURMWtgGj4iYzmRk8w/Itrm769VWJSCeCbRGue/LnlLTE8AwDs5d3/TQeGIw==", "dev": true, "dependencies": { - "@jest/schemas": "^28.1.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" + "@edge-runtime/vm": "2.1.2", + "@jest/environment": "29.5.0", + "@jest/fake-timers": "29.5.0", + "@jest/types": "29.5.0", + "jest-mock": "29.5.0", + "jest-util": "29.5.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=14" } }, "node_modules/@edge-runtime/jest-environment/node_modules/chalk": { @@ -873,12 +862,12 @@ } }, "node_modules/@edge-runtime/jest-environment/node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -886,22 +875,28 @@ "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@edge-runtime/primitives": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-1.1.0.tgz", - "integrity": "sha512-MpL5fKlOs9mz5DMRuFchLe3Il84t7XpfbPq4qtaEK37uNMCRx1MzA3d7A4aTsR/guXSZvV/AtEbKVqBWjuSThA==", - "dev": true + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-2.1.2.tgz", + "integrity": "sha512-SR04SMDybALlhIYIi0hiuEUwIl0b7Sn+RKwQkX6hydg4+AKMzBNDFhj2nqHDD1+xkHArV9EhmJIb6iGjShwSzg==", + "dev": true, + "engines": { + "node": ">=14" + } }, "node_modules/@edge-runtime/vm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-1.1.0.tgz", - "integrity": "sha512-a3PSCdznoop5+ifkNDaSINB9V+Anwh+wpoaASIWhq9PLQuBF9D6Yxe/mLRZkuZRkOJ2ZmaTzMGDI5ROUChTL7g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-2.1.2.tgz", + "integrity": "sha512-j4H5S26NJhYOyjVMN8T/YJuwwslfnEX1P0j6N2Rq1FaubgNowdYunA9nlO7lg8Rgjv6dqJ2zKuM7GD1HFtNSGw==", "dev": true, "dependencies": { - "@edge-runtime/primitives": "1.1.0" + "@edge-runtime/primitives": "2.1.2" + }, + "engines": { + "node": ">=14" } }, "node_modules/@eslint/eslintrc": { @@ -973,76 +968,6 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -1062,57 +987,20 @@ } }, "node_modules/@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/console/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/console/node_modules/chalk": { @@ -1131,63 +1019,60 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/console/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@jest/console/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "rimraf": "^3.0.0", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -1198,43 +1083,6 @@ } } }, - "node_modules/@jest/core/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/core/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1251,234 +1099,122 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/core/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@jest/core/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", - "@types/node": "*", - "jest-mock": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.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" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/environment/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/@jest/core/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", - "dev": true, - "dependencies": { - "@jest/types": "^28.1.3", - "@sinonjs/fake-timers": "^9.1.2", - "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^28.1.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" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/fake-timers/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, - "node_modules/@jest/fake-timers/node_modules/jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "node_modules/@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" + "jest-mock": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" }, "engines": { - "node": ">=6.9.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" + "jest-get-type": "^29.4.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "node_modules/@jest/expect-utils/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/chalk": { + "node_modules/@jest/fake-timers/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -1494,73 +1230,71 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/globals/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/@jest/fake-timers/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/globals/node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "node_modules/@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -1571,31 +1305,6 @@ } } }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/@jest/reporters/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1612,73 +1321,106 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, "dependencies": { - "@sinclair/typebox": "^0.24.1" + "@sinclair/typebox": "^0.25.16" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" + "graceful-fs": "^4.2.9" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/@jest/transform": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "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.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/test-result/node_modules/chalk": { + "node_modules/@jest/transform/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -1694,73 +1436,54 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/test-result": "^27.5.1", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "node_modules/@jest/transform/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", "dev": true, "dependencies": { + "@jest/schemas": "^29.4.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@jest/transform/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/transform/node_modules/chalk": { + "node_modules/@jest/types/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -1776,6 +1499,60 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, "node_modules/@koa/cors": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-3.1.0.tgz", @@ -1789,15 +1566,15 @@ } }, "node_modules/@next/env": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.5-canary.2.tgz", - "integrity": "sha512-a3z9/6k37730bAMiJRTJ2+zGPBZc4ROYFY6LISAmNT7dNfcuSF5xML6jcnMqP38DsIjnFDeSqJmcvY374gj8Yw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.6.tgz", + "integrity": "sha512-nqUxEtvDqFhmV1/awSg0K2XHNwkftNaiUqCYO9e6+MYmqNObpKVl7OgMkGaQ2SZnFx5YqF0t60ZJTlyJIDAijg==", "dev": true }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.5-canary.2.tgz", - "integrity": "sha512-pqYPb2FGsT/srfiDIIaAQM1RbPuylVyfXifHYkzzFfsVbvyRU9O2TvWhgsK977v8DJiVEXJS9Y2zIlgvKVNQZQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.6.tgz", + "integrity": "sha512-ahi6VP98o4HV19rkOXPSUu+ovfHfUxbJQ7VVJ7gL2FnZRr7onEFC1oGQ6NQHpm8CxpIzSSBW79kumlFMOmZVjg==", "cpu": [ "arm64" ], @@ -1811,9 +1588,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.5-canary.2.tgz", - "integrity": "sha512-ZN910CRsKMNIJ2hFSQL1Lk7KDFZ+xz5kTfIBMG0IbApS3J8ayQXxMfVP17GchZbfPTyxI6Cnozo0Wz55/cjBrg==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.6.tgz", + "integrity": "sha512-13cXxKFsPJIJKzUqrU5XB1mc0xbUgYsRcdH6/rB8c4NMEbWGdtD4QoK9ShN31TZdePpD4k416Ur7p+deMIxnnA==", "cpu": [ "x64" ], @@ -1827,9 +1604,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.5-canary.2.tgz", - "integrity": "sha512-IrXHRkDkBJUzZpVcYsez5oZpbcrbzJ6UNbXyL4UNFdIauOLv5JBjAKqUvnF+x5mq7o58+GD6NB+uA20uJVurng==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.6.tgz", + "integrity": "sha512-Ti+NMHEjTNktCVxNjeWbYgmZvA2AqMMI2AMlzkXsU7W4pXCMhrryAmAIoo+7YdJbsx01JQWYVxGe62G6DoCLaA==", "cpu": [ "arm64" ], @@ -1843,9 +1620,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.5-canary.2.tgz", - "integrity": "sha512-B7ZY3fg9Ng0Eh7KKpv6siRI6yrrsuJBOCgVZmnWvtMuWI1jkyIwydVaRXAS8OlefimaOQ1LUJ1aWkqzTaGQscw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.6.tgz", + "integrity": "sha512-OHoC6gO7XfjstgwR+z6UHKlvhqJfyMtNaJidjx3sEcfaDwS7R2lqR5AABi8PuilGgi0BO0O0sCXqLlpp3a0emQ==", "cpu": [ "arm64" ], @@ -1859,9 +1636,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.5-canary.2.tgz", - "integrity": "sha512-I9zd9nrgn6Dv5tF8s81YeDqagoil6u4Ul1TLV+aCibpf7QFtl1z1ebGbKHRY3czY0WEH5JpmjgwZE08uV4C/rQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.6.tgz", + "integrity": "sha512-zHZxPGkUlpfNJCboUrFqwlwEX5vI9LSN70b8XEb0DYzzlrZyCyOi7hwDp/+3Urm9AB7YCAJkgR5Sp1XBVjHdfQ==", "cpu": [ "x64" ], @@ -1875,9 +1652,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.5-canary.2.tgz", - "integrity": "sha512-XkWxdLyG4boqtBX3POx20UZ5IIfdzMjn5nGsYwhTlDs4UohyzEOVZTBMkNKDxisJJH9zZO3w0lZT/aZx8CHZ+A==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.6.tgz", + "integrity": "sha512-K/Y8lYGTwTpv5ME8PSJxwxLolaDRdVy+lOd9yMRMiQE0BLUhtxtCWC9ypV42uh9WpLjoaD0joOsB9Q6mbrSGJg==", "cpu": [ "x64" ], @@ -1891,9 +1668,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.5-canary.2.tgz", - "integrity": "sha512-hMVjxzrJ739aF2I88pLkufO9+6095SFsccfHJObTxWW9s6WRioKtui28OvBSNhdF7umdAIzMaDrGRNzJVgqyhw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.6.tgz", + "integrity": "sha512-U6LtxEUrjBL2tpW+Kr1nHCSJWNeIed7U7l5o7FiKGGwGgIlFi4UHDiLI6TQ2lxi20fAU33CsruV3U0GuzMlXIw==", "cpu": [ "arm64" ], @@ -1907,9 +1684,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.5-canary.2.tgz", - "integrity": "sha512-aYy7iswqT0jQrsaTBgOU7rxx9Qyn58w31Edgmh/xabm4I+sprLua/AvqwApqkvz847nIzMRvRpyjOEg1tXVMNQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.6.tgz", + "integrity": "sha512-eEBeAqpCfhdPSlCZCayjCiyIllVqy4tcqvm1xmg3BgJG0G5ITiMM4Cw2WVeRSgWDJqQGRyyb+q8Y2ltzhXOWsQ==", "cpu": [ "ia32" ], @@ -1923,9 +1700,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.5-canary.2.tgz", - "integrity": "sha512-zOyjxW/fHuwUXDzU1AHKwwi+8Bf5uwLHYNNxoYTHzQPMNx3nHtwWSznI835NOSQay+7JcQIDX5goMj58zIeXkw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.6.tgz", + "integrity": "sha512-OrZs94AuO3ZS5tnqlyPRNgfWvboXaDQCi5aXGve3o3C+Sj0ctMUV9+Do+0zMvvLRumR8E0PTWKvtz9n5vzIsWw==", "cpu": [ "x64" ], @@ -2020,9 +1797,9 @@ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, "node_modules/@sinclair/typebox": { - "version": "0.24.38", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.38.tgz", - "integrity": "sha512-IbYB6vdhLFmzGEyXXEdFAJKyq7S4/RsivkgxNzs/LzwYuUJHmeNQ0cHkjG/Yqm6VgUzzZDLMZAf0XgeeaZAocA==", + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "dev": true }, "node_modules/@sindresorhus/is": { @@ -2047,12 +1824,21 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", + "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" } }, "node_modules/@swc/helpers": { @@ -2188,12 +1974,12 @@ } }, "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 10" } }, "node_modules/@types/aria-query": { @@ -2203,13 +1989,13 @@ "dev": true }, "node_modules/@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", "dev": true, "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -2235,12 +2021,12 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", - "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", "dev": true, "dependencies": { - "@babel/types": "^7.3.0" + "@babel/types": "^7.20.7" } }, "node_modules/@types/body-parser": { @@ -2302,9 +2088,9 @@ } }, "node_modules/@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "dependencies": { "@types/node": "*" @@ -2316,12 +2102,6 @@ "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", "dev": true }, - "node_modules/@types/http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==", - "dev": true - }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -2347,13 +2127,56 @@ } }, "node_modules/@types/jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "version": "29.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz", + "integrity": "sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/jest/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" } }, "node_modules/@types/json-buffer": { @@ -2404,6 +2227,30 @@ "integrity": "sha512-LUhvPmAKAbgm+p/K11IWszLZVoZDlMF4NRmqbhEzDz/CnCuehPkZXwZbBCKGJsgjnuVejotBwM7B3Scrq4EqDw==", "dev": true }, + "node_modules/@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "form-data": "^3.0.0" + } + }, + "node_modules/@types/node-fetch/node_modules/form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/on-headers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/on-headers/-/on-headers-1.0.0.tgz", @@ -2414,9 +2261,9 @@ } }, "node_modules/@types/prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", - "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", "dev": true }, "node_modules/@types/prop-types": { @@ -2575,9 +2422,9 @@ } }, "node_modules/@types/yargs": { - "version": "17.0.20", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.20.tgz", - "integrity": "sha512-eknWrTHofQuPk2iuqDm1waA7V6xPlbgBoaaXEgYkClhLOnB0TtbW+srJaOToAgawPxPlHQzwypFA2bhZaUGP5A==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "dependencies": { "@types/yargs-parser": "*" @@ -2863,13 +2710,25 @@ } }, "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", "dev": true, "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + } + }, + "node_modules/acorn-globals/node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" } }, "node_modules/acorn-jsx": { @@ -2882,9 +2741,9 @@ } }, "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, "engines": { "node": ">=0.4.0" @@ -3386,52 +3245,26 @@ "dev": true }, "node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", "dev": true, "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/transform": "^29.5.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", + "babel-preset-jest": "^29.5.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" } }, - "node_modules/babel-jest/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/babel-jest/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, "node_modules/babel-jest/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3465,18 +3298,18 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", + "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/babel-preset-current-node-syntax": { @@ -3503,16 +3336,16 @@ } }, "node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -3772,33 +3605,36 @@ "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "node_modules/browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.21.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz", + "integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "caniuse-lite": "^1.0.30001502", + "electron-to-chromium": "^1.4.428", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/browserstack-cypress-cli": { @@ -3984,21 +3820,6 @@ "node": ">=10" } }, - "node_modules/browserstack-cypress-cli/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/browserstack-cypress-cli/node_modules/p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -4011,15 +3832,6 @@ "node": ">=6" } }, - "node_modules/browserstack-cypress-cli/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/browserstack-cypress-cli/node_modules/slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -4330,9 +4142,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001429", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", - "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", + "version": "1.0.30001503", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", + "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==", "dev": true, "funding": [ { @@ -4342,6 +4154,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -4401,9 +4217,9 @@ "dev": true }, "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, "node_modules/clean-stack": { @@ -4489,14 +4305,17 @@ "dev": true }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/clone-response": { @@ -4685,13 +4504,10 @@ } }, "node_modules/convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, "node_modules/cookie": { "version": "0.5.0", @@ -4802,9 +4618,9 @@ "dev": true }, "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, "node_modules/cssstyle": { @@ -4980,17 +4796,17 @@ } }, "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/dayjs": { @@ -5025,9 +4841,9 @@ } }, "node_modules/decimal.js": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz", - "integrity": "sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, "node_modules/decompress-response": { @@ -5085,9 +4901,9 @@ "dev": true }, "node_modules/deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, "engines": { "node": ">=0.10.0" @@ -5146,6 +4962,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, "engines": { "node": ">= 0.6" } @@ -5169,15 +4986,6 @@ "node": ">=8" } }, - "node_modules/diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -5218,24 +5026,15 @@ "dev": true }, "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "dev": true, "dependencies": { - "webidl-conversions": "^5.0.0" + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/dot-prop": { @@ -5303,18 +5102,18 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.3.836", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.836.tgz", - "integrity": "sha512-Ney3pHOJBWkG/AqYjrW0hr2AUCsao+2uvq9HUlRP8OlpSdk/zOHOUJP7eu0icDvePC9DlgffuelP4TnOJmMRUg==", + "version": "1.4.431", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.431.tgz", + "integrity": "sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==", "dev": true }, "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -5369,6 +5168,18 @@ "node": ">=8.6" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -6194,91 +6005,61 @@ } }, "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expect/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/expect/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/expect/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/expect/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expect/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/expect/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/expect/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/expect/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/extend": { @@ -6375,9 +6156,9 @@ } }, "node_modules/fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "dependencies": { "bser": "2.1.1" @@ -6470,6 +6251,28 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -6815,6 +6618,12 @@ "node": ">= 6" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "node_modules/global-dirs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", @@ -7031,15 +6840,15 @@ } }, "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.5" + "whatwg-encoding": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/html-escaper": { @@ -7071,6 +6880,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, "dependencies": { "depd": "~1.1.2", "inherits": "2.0.4", @@ -7083,12 +6893,12 @@ } }, "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, "dependencies": { - "@tootallnate/once": "1", + "@tootallnate/once": "2", "agent-base": "6", "debug": "4" }, @@ -7262,7 +7072,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/ini": { "version": "2.0.0", @@ -7770,9 +7581,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "dependencies": { "@babel/core": "^7.12.3", @@ -7861,20 +7672,21 @@ } }, "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "dependencies": { - "@jest/core": "^27.5.1", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^27.5.1" + "jest-cli": "^29.5.0" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -7886,58 +7698,16 @@ } }, "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", "execa": "^5.0.0", - "throat": "^6.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-changed-files/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "p-limit": "^3.1.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-changed-files/node_modules/execa": { @@ -7984,115 +7754,167 @@ "node": ">=10.17.0" } }, + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "stack-utils": "^2.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-circus/node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "node_modules/jest-circus/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^27.5.1" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "node_modules/jest-circus/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } } }, - "node_modules/jest-circus/node_modules/chalk": { + "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8108,99 +7930,69 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-circus/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/jest-cli/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-circus/node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", - "dev": true, - "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", - "exit": "^0.1.2", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "prompts": "^2.0.1", - "yargs": "^16.2.0" - }, - "bin": { - "jest": "bin/jest.js" + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "@types/node": "*", + "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { - "node-notifier": { + "@types/node": { + "optional": true + }, + "ts-node": { "optional": true } } }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-cli/node_modules/chalk": { + "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8216,106 +8008,110 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "node_modules/jest-config/node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - }, - "peerDependencies": { - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "ts-node": { - "optional": true - } + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-config/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-config/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-config/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", + "node_modules/jest-config/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "dependencies": { + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-diff/node_modules/chalk": { + "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8331,60 +8127,92 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "node_modules/jest-each/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-each/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-each/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-environment-jsdom": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.5.0.tgz", + "integrity": "sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0", + "jsdom": "^20.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/jest-each/node_modules/chalk": { + "node_modules/jest-environment-jsdom/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8400,10 +8228,27 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-environment-jsdom": { + "node_modules/jest-environment-jsdom/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", + "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", "dev": true, "dependencies": { "@jest/environment": "^27.5.1", @@ -8411,14 +8256,25 @@ "@jest/types": "^27.5.1", "@types/node": "*", "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" + "jest-util": "^27.5.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/@babel/code-frame": { + "node_modules/jest-environment-node-single-context": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node-single-context/-/jest-environment-node-single-context-27.3.0.tgz", + "integrity": "sha512-28sQFZhG92C6Zr+Tue9sHL9n68a40ZnQmyiu0Ajh3c7yRauX1x2PB9LyUxuZ9imcBOYKEzMitnG69WsSsP9bNg==", + "dev": true, + "dependencies": { + "jest-environment-node": "^27.2.4" + }, + "funding": { + "url": "https://github.com/kayahr/jest-environment-node-single-context?sponsor=1" + } + }, + "node_modules/jest-environment-node/node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", @@ -8430,7 +8286,7 @@ "node": ">=6.9.0" } }, - "node_modules/jest-environment-jsdom/node_modules/@jest/environment": { + "node_modules/jest-environment-node/node_modules/@jest/environment": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", @@ -8445,7 +8301,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/@jest/fake-timers": { + "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", @@ -8462,7 +8318,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/@jest/types": { + "node_modules/jest-environment-node/node_modules/@jest/types": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", @@ -8478,7 +8334,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/@sinonjs/fake-timers": { + "node_modules/jest-environment-node/node_modules/@sinonjs/fake-timers": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", @@ -8487,7 +8343,7 @@ "@sinonjs/commons": "^1.7.0" } }, - "node_modules/jest-environment-jsdom/node_modules/@types/yargs": { + "node_modules/jest-environment-node/node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", @@ -8496,7 +8352,7 @@ "@types/yargs-parser": "*" } }, - "node_modules/jest-environment-jsdom/node_modules/chalk": { + "node_modules/jest-environment-node/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8512,7 +8368,7 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-environment-jsdom/node_modules/jest-message-util": { + "node_modules/jest-environment-node/node_modules/jest-message-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", @@ -8532,7 +8388,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-jsdom/node_modules/jest-mock": { + "node_modules/jest-environment-node/node_modules/jest-mock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", @@ -8545,114 +8401,134 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "node_modules/jest-haste-map": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" } }, - "node_modules/jest-environment-node-single-context": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jest-environment-node-single-context/-/jest-environment-node-single-context-27.3.0.tgz", - "integrity": "sha512-28sQFZhG92C6Zr+Tue9sHL9n68a40ZnQmyiu0Ajh3c7yRauX1x2PB9LyUxuZ9imcBOYKEzMitnG69WsSsP9bNg==", + "node_modules/jest-haste-map/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "jest-environment-node": "^27.2.4" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/kayahr/jest-environment-node-single-context?sponsor=1" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-environment-node/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=6.9.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "node_modules/jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/chalk": { + "node_modules/jest-matcher-utils/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8668,100 +8544,104 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-environment-node/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/jest-matcher-utils/node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-node/node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "node_modules/jest-matcher-utils/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "node_modules/jest-matcher-utils/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "micromatch": "^4.0.4", - "walker": "^1.0.7" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "^2.3.2" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-matcher-utils/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-message-util/node_modules/@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@babel/highlight": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/jest-haste-map/node_modules/chalk": { + "node_modules/jest-message-util/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8777,113 +8657,53 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-jasmine2/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" + "node": ">=10" }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-jasmine2/node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true }, - "node_modules/jest-jasmine2/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "jest-util": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" - } - }, - "node_modules/jest-jasmine2/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-jasmine2/node_modules/chalk": { + "node_modules/jest-mock/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8899,68 +8719,83 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-jasmine2/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/jest-mock/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-jasmine2/node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "node_modules/jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "dependencies": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "node_modules/jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-matcher-utils/node_modules/chalk": { + "node_modules/jest-resolve/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -8976,56 +8811,56 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" + "picomatch": "^2.2.3" }, "engines": { - "node": ">=6.9.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "node_modules/jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/chalk": { + "node_modules/jest-runner/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -9041,70 +8876,165 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "node_modules/jest-runner/node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "dependencies": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/jest-runner/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@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.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, - "node_modules/jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@jest/types": "^28.1.3", - "@types/node": "*" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/schemas": "^28.1.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-mock/node_modules/chalk": { + "node_modules/jest-runtime/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "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/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -9120,109 +9050,121 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", "dev": true, "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", - "slash": "^3.0.0" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-resolve-dependencies/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-snapshot/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-resolve-dependencies/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, - "node_modules/jest-resolve-dependencies/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jest-util": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", + "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/types": "^27.5.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-resolve/node_modules/@jest/types": { + "node_modules/jest-util/node_modules/@jest/types": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", @@ -9238,7 +9180,7 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-resolve/node_modules/@types/yargs": { + "node_modules/jest-util/node_modules/@types/yargs": { "version": "16.0.4", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", @@ -9247,7 +9189,7 @@ "@types/yargs-parser": "*" } }, - "node_modules/jest-resolve/node_modules/chalk": { + "node_modules/jest-util/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -9263,117 +9205,112 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "node_modules/jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", "chalk": "^4.0.0", - "emittery": "^0.8.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, "engines": { - "node": ">=6.9.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-runner/node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner/node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "node_modules/jest-validate/node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/chalk": { + "node_modules/jest-watcher/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", @@ -9389,683 +9326,178 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runner/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runner/node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "node_modules/jest-worker/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "node_modules/jest-worker/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=6.9.0" + "node": ">=8" } }, - "node_modules/jest-runtime/node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "node_modules/jest-worker/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^27.5.1" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-runtime/node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "has-flag": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, + "node_modules/joi": { + "version": "17.9.2", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz", + "integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, - "node_modules/jest-runtime/node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^1.7.0" + "node_modules/jose": { + "version": "4.14.4", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", + "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", "dev": true, "dependencies": { - "@types/yargs-parser": "*" + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jest-runtime/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsdom": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", + "cssstyle": "^2.3.0", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", + "escodegen": "^2.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "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" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-runtime/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-runtime/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/jest-runtime/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-runtime/node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.7.2", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^27.5.1", - "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-snapshot/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-snapshot/node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-util/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-util/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", - "dev": true, - "dependencies": { - "@jest/types": "^27.5.1", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "leven": "^3.1.0", - "pretty-format": "^27.5.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-validate/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dev": true, - "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-watcher/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/joi": { - "version": "17.9.2", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz", - "integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==", - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/jose": { - "version": "4.14.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.14.4.tgz", - "integrity": "sha512-j8GhLiKmUAh+dsFXlX1aJCbt5KMibuKb+d7j1JaOJG6s2UjX1PQlW+OKB/sD4a/5ZYF4RcmYmLSndOoU3Lt/3g==", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" + "node": ">=14" }, "peerDependencies": { "canvas": "^2.5.0" @@ -10077,9 +9509,9 @@ } }, "node_modules/jsdom/node_modules/acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -10089,9 +9521,9 @@ } }, "node_modules/jsdom/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "dependencies": { "asynckit": "^0.4.0", @@ -10422,6 +9854,18 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -10809,17 +10253,18 @@ } }, "node_modules/next": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.5-canary.2.tgz", - "integrity": "sha512-mcUWP0rqWv+Fq1pJBnrBhntm9WoRVJt+ONt5RzkBBBfZNBHqa4NQKBmU5GQEoQRoXOHWhpEl6a5R9rISr08msQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.6.tgz", + "integrity": "sha512-sjVqjxU+U2aXZnYt4Ud6CTLNNwWjdSfMgemGpIQJcN3Z7Jni9xRWbR0ie5fQzCg87aLqQVhKA2ud2gPoqJ9lGw==", "dev": true, "dependencies": { - "@next/env": "13.4.5-canary.2", + "@next/env": "13.4.6", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", "styled-jsx": "5.1.1", + "watchpack": "2.4.0", "zod": "3.21.4" }, "bin": { @@ -10829,15 +10274,15 @@ "node": ">=16.8.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.5-canary.2", - "@next/swc-darwin-x64": "13.4.5-canary.2", - "@next/swc-linux-arm64-gnu": "13.4.5-canary.2", - "@next/swc-linux-arm64-musl": "13.4.5-canary.2", - "@next/swc-linux-x64-gnu": "13.4.5-canary.2", - "@next/swc-linux-x64-musl": "13.4.5-canary.2", - "@next/swc-win32-arm64-msvc": "13.4.5-canary.2", - "@next/swc-win32-ia32-msvc": "13.4.5-canary.2", - "@next/swc-win32-x64-msvc": "13.4.5-canary.2" + "@next/swc-darwin-arm64": "13.4.6", + "@next/swc-darwin-x64": "13.4.6", + "@next/swc-linux-arm64-gnu": "13.4.6", + "@next/swc-linux-arm64-musl": "13.4.6", + "@next/swc-linux-x64-gnu": "13.4.6", + "@next/swc-linux-x64-musl": "13.4.6", + "@next/swc-win32-arm64-msvc": "13.4.6", + "@next/swc-win32-ia32-msvc": "13.4.6", + "@next/swc-win32-x64-msvc": "13.4.6" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -10873,6 +10318,48 @@ "node": ">= 10.13" } }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10880,9 +10367,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", "dev": true }, "node_modules/normalize-path": { @@ -10919,9 +10406,9 @@ } }, "node_modules/nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", + "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==", "dev": true }, "node_modules/oauth-sign": { @@ -10933,6 +10420,14 @@ "node": "*" } }, + "node_modules/oauth4webapi": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.3.0.tgz", + "integrity": "sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -11238,6 +10733,33 @@ "node": ">=8" } }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", @@ -11253,6 +10775,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -11450,10 +10981,16 @@ } }, "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } }, "node_modules/parseurl": { "version": "1.3.3", @@ -11586,76 +11123,6 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pkg-dir/node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/postcss": { "version": "8.4.14", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", @@ -11887,6 +11354,22 @@ "node": ">=8" } }, + "node_modules/pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, "node_modules/qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", @@ -11896,6 +11379,12 @@ "node": ">=0.6" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -12284,6 +11773,12 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "node_modules/resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -12338,9 +11833,9 @@ } }, "node_modules/resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, "engines": { "node": ">=10" @@ -12452,15 +11947,15 @@ "dev": true }, "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "dependencies": { "xmlchars": "^2.2.0" }, "engines": { - "node": ">=10" + "node": ">=v12.22.7" } }, "node_modules/scheduler": { @@ -12508,7 +12003,8 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true }, "node_modules/shebang-command": { "version": "2.0.0", @@ -12611,9 +12107,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -12765,6 +12261,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, "engines": { "node": ">= 0.6" } @@ -12965,19 +12462,6 @@ "node": ">=8" } }, - "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -13130,22 +12614,6 @@ "rimraf": "bin.js" } }, - "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -13166,12 +12634,6 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "node_modules/throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, "node_modules/throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -13221,7 +12683,7 @@ "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, "engines": { "node": ">=4" @@ -13252,43 +12714,45 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, "engines": { "node": ">=0.6" } }, "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.1.2" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { "node": ">=6" } }, "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, "engines": { "node": ">= 4.0.0" } }, "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, "dependencies": { "punycode": "^2.1.1" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/traverse": { @@ -13301,38 +12765,38 @@ } }, "node_modules/ts-jest": { - "version": "27.1.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", - "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", + "version": "29.1.0", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz", + "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "20.x" + "yargs-parser": "^21.0.1" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", - "@types/jest": "^27.0.0", - "babel-jest": ">=27.0.0 <28", - "jest": "^27.0.0", - "typescript": ">=3.8 <5.0" + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" }, "peerDependenciesMeta": { "@babel/core": { "optional": true }, - "@types/jest": { + "@jest/types": { "optional": true }, "babel-jest": { @@ -13343,6 +12807,39 @@ } } }, + "node_modules/ts-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-jest/node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/ts-jest/node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -13626,6 +13123,36 @@ "integrity": "sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==", "dev": true }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, "node_modules/update-notifier": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", @@ -13717,6 +13244,16 @@ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -13751,27 +13288,24 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^1.6.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/vary": { "version": "1.1.2", @@ -13808,25 +13342,16 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, "dependencies": { - "xml-name-validator": "^3.0.0" + "xml-name-validator": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/wait-on": { @@ -13857,42 +13382,72 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "engines": { - "node": ">=10.4" + "node": ">=12" } }, "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "iconv-lite": "0.4.24" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } }, "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/which": { @@ -14056,16 +13611,16 @@ } }, "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -14086,10 +13641,13 @@ } }, "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } }, "node_modules/xmlchars": { "version": "2.2.0", @@ -14109,30 +13667,30 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs/node_modules/y18n": { @@ -14163,6 +13721,18 @@ "node": ">= 4.0.0" } }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zip-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", @@ -14208,6 +13778,16 @@ "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", "dev": true }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -14218,226 +13798,209 @@ } }, "@babel/compat-data": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.5.tgz", + "integrity": "sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==", "dev": true }, "@babel/core": { - "version": "7.15.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.5.tgz", - "integrity": "sha512-pYgXxiwAgQpgM1bNkZsDEq85f0ggXMA5L7c+o3tskGMh2BunCI9QUwB9Z4jpvXUOuMdyGKiGKQiRe11VS6Jzvg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-compilation-targets": "^7.15.4", - "@babel/helper-module-transforms": "^7.15.4", - "@babel/helpers": "^7.15.4", - "@babel/parser": "^7.15.5", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.5.tgz", + "integrity": "sha512-SBuTAjg91A3eKOvD+bPEz3LlhHZRNu1nFOVts9lzDJTXshHTjII0BAtDS3Y2DAkdZdDKWVZGVwkDfc4Clxn1dg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.5", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", - "semver": "^6.3.0", - "source-map": "^0.5.0" + "json5": "^2.2.2", + "semver": "^6.3.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.5" } }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true } } }, "@babel/generator": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.4.tgz", - "integrity": "sha512-d3itta0tu+UayjEORPNz6e1T3FtvWlP5N4V5M+lhp/CxT4oAA7/NcScnpRyspUMLK6tu9MNHmQHxRykuN2R7hw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.5.tgz", + "integrity": "sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==", "dev": true, "requires": { - "@babel/types": "^7.15.4", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } + "@babel/types": "^7.22.5", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" } }, "@babel/helper-compilation-targets": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", - "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.5.tgz", + "integrity": "sha512-Ji+ywpHeuqxB8WDxraCiqR0xfhYjiDE/e6k7FuIaANnoOFxAHskHChz4vA1mJC9Lbm01s1PVAGhQY4FUKSkGZw==", "dev": true, "requires": { - "@babel/compat-data": "^7.15.0", - "@babel/helper-validator-option": "^7.14.5", - "browserslist": "^4.16.6", + "@babel/compat-data": "^7.22.5", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } } }, - "@babel/helper-function-name": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", - "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.15.4", - "@babel/template": "^7.15.4", - "@babel/types": "^7.15.4" - } + "@babel/helper-environment-visitor": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "dev": true }, - "@babel/helper-get-function-arity": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", - "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", + "@babel/helper-function-name": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helper-hoist-variables": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", - "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", - "dev": true, - "requires": { - "@babel/types": "^7.15.4" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", - "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-imports": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", - "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" } }, "@babel/helper-module-transforms": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.4.tgz", - "integrity": "sha512-9fHHSGE9zTC++KuXLZcB5FKgvlV83Ox+NLUmQTawovwlJ85+QMhk1CnVk406CQVj97LaWod6KVjl2Sfgw9Aktw==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.15.4", - "@babel/helper-replace-supers": "^7.15.4", - "@babel/helper-simple-access": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/helper-validator-identifier": "^7.14.9", - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", - "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/helper-plugin-utils": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", - "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", "dev": true }, - "@babel/helper-replace-supers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", - "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", - "dev": true, - "requires": { - "@babel/helper-member-expression-to-functions": "^7.15.4", - "@babel/helper-optimise-call-expression": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" - } - }, "@babel/helper-simple-access": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", - "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" } }, "@babel/helper-split-export-declaration": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", - "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.5.tgz", + "integrity": "sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==", "dev": true, "requires": { - "@babel/types": "^7.15.4" + "@babel/types": "^7.22.5" } }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true }, "@babel/helpers": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", - "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.5.tgz", + "integrity": "sha512-pSXRmfE1vzcUIDFQcSGA5Mr+GxBV9oiRKDuDxXvWQQBCh8HoIjs/2DlDB7H8smac1IVrB9/xdXj2N3Wol9Cr+Q==", "dev": true, "requires": { - "@babel/template": "^7.15.4", - "@babel/traverse": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" } }, "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", + "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.18.6", + "@babel/helper-validator-identifier": "^7.22.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" }, @@ -14495,9 +14058,9 @@ } }, "@babel/parser": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.6.tgz", - "integrity": "sha512-S/TSCcsRuCkmpUuoWijua0Snt+f3ewU/8spLo+4AXJCZfT0bVCzLD5MuOKdrx0mlAptbKzn5AdgEIIKXxXkz9Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -14545,6 +14108,15 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-jsx": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", + "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.22.5" + } + }, "@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", @@ -14609,12 +14181,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz", - "integrity": "sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", + "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.22.5" } }, "@babel/runtime": { @@ -14627,51 +14199,52 @@ } }, "@babel/template": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", - "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" }, "dependencies": { "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.5" } } } }, "@babel/traverse": { - "version": "7.15.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", - "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.4", - "@babel/helper-function-name": "^7.15.4", - "@babel/helper-hoist-variables": "^7.15.4", - "@babel/helper-split-export-declaration": "^7.15.4", - "@babel/parser": "^7.15.4", - "@babel/types": "^7.15.4", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.5.tgz", + "integrity": "sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { "@babel/code-frame": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", - "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@babel/highlight": "^7.14.5" + "@babel/highlight": "^7.22.5" } }, "globals": { @@ -14683,12 +14256,13 @@ } }, "@babel/types": { - "version": "7.15.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", - "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.5.tgz", + "integrity": "sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.14.9", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" } }, @@ -14788,33 +14362,19 @@ } }, "@edge-runtime/jest-environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/jest-environment/-/jest-environment-1.1.0.tgz", - "integrity": "sha512-YwiR+zxAt3BksS1DrOuVdqnDw+18EZxm3vpGo8vuxqKXOg9UNdmj7c3nfkdTdhQ3gr3+sSpcS/4+vLoqW1QSKA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@edge-runtime/jest-environment/-/jest-environment-2.1.0.tgz", + "integrity": "sha512-NzBLXK6FG59xKDmKo8ad0gV1HrlURMWtgGj4iYzmRk8w/Itrm769VWJSCeCbRGue/LnlLTE8AwDs5d3/TQeGIw==", "dev": true, "requires": { - "@edge-runtime/vm": "1.1.0", - "@jest/environment": "28.1.3", - "@jest/fake-timers": "28.1.3", - "@jest/types": "28.1.3", - "jest-mock": "28.1.3", - "jest-util": "28.1.3" + "@edge-runtime/vm": "2.1.2", + "@jest/environment": "29.5.0", + "@jest/fake-timers": "29.5.0", + "@jest/types": "29.5.0", + "jest-mock": "29.5.0", + "jest-util": "29.5.0" }, "dependencies": { - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.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" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -14826,12 +14386,12 @@ } }, "jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -14842,18 +14402,18 @@ } }, "@edge-runtime/primitives": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-1.1.0.tgz", - "integrity": "sha512-MpL5fKlOs9mz5DMRuFchLe3Il84t7XpfbPq4qtaEK37uNMCRx1MzA3d7A4aTsR/guXSZvV/AtEbKVqBWjuSThA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@edge-runtime/primitives/-/primitives-2.1.2.tgz", + "integrity": "sha512-SR04SMDybALlhIYIi0hiuEUwIl0b7Sn+RKwQkX6hydg4+AKMzBNDFhj2nqHDD1+xkHArV9EhmJIb6iGjShwSzg==", "dev": true }, "@edge-runtime/vm": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-1.1.0.tgz", - "integrity": "sha512-a3PSCdznoop5+ifkNDaSINB9V+Anwh+wpoaASIWhq9PLQuBF9D6Yxe/mLRZkuZRkOJ2ZmaTzMGDI5ROUChTL7g==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@edge-runtime/vm/-/vm-2.1.2.tgz", + "integrity": "sha512-j4H5S26NJhYOyjVMN8T/YJuwwslfnEX1P0j6N2Rq1FaubgNowdYunA9nlO7lg8Rgjv6dqJ2zKuM7GD1HFtNSGw==", "dev": true, "requires": { - "@edge-runtime/primitives": "1.1.0" + "@edge-runtime/primitives": "2.1.2" } }, "@eslint/eslintrc": { @@ -14916,114 +14476,34 @@ "resolve-from": "^5.0.0" }, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15034,92 +14514,58 @@ "supports-color": "^7.1.0" } }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" } } } }, "@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", "dev": true, "requires": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", "micromatch": "^4.0.4", - "rimraf": "^3.0.0", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15130,91 +14576,100 @@ "supports-color": "^7.1.0" } }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" + } + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true } } }, "@jest/environment": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", - "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", "dev": true, "requires": { - "@jest/fake-timers": "^28.1.3", - "@jest/types": "^28.1.3", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "jest-mock": "^28.1.3" + "jest-mock": "^29.5.0" + } + }, + "@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "requires": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + } + }, + "@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "requires": { + "jest-get-type": "^29.4.3" }, "dependencies": { - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.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" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true } } }, "@jest/fake-timers": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", - "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", "dev": true, "requires": { - "@jest/types": "^28.1.3", - "@sinonjs/fake-timers": "^9.1.2", + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", "@types/node": "*", - "jest-message-util": "^28.1.3", - "jest-mock": "^28.1.3", - "jest-util": "^28.1.3" + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" }, "dependencies": { - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.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" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15226,192 +14681,65 @@ } }, "jest-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", - "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@jest/types": "^28.1.3", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - } - } - } - }, - "@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" } } } }, + "@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" + } + }, "@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", - "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15421,132 +14749,140 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } } } }, "@jest/schemas": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", - "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", "dev": true, "requires": { - "@sinclair/typebox": "^0.24.1" + "@sinclair/typebox": "^0.25.16" } }, "@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" + "graceful-fs": "^4.2.9" } }, "@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", "dev": true, "requires": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } } }, "@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", "dev": true, "requires": { - "@jest/test-result": "^27.5.1", + "@jest/test-result": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" } }, "@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "write-file-atomic": "^4.0.2" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" } }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + } + } + }, + "@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.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" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -15559,6 +14895,53 @@ } } }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + } + } + }, "@koa/cors": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-3.1.0.tgz", @@ -15569,71 +14952,71 @@ } }, "@next/env": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.5-canary.2.tgz", - "integrity": "sha512-a3z9/6k37730bAMiJRTJ2+zGPBZc4ROYFY6LISAmNT7dNfcuSF5xML6jcnMqP38DsIjnFDeSqJmcvY374gj8Yw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.6.tgz", + "integrity": "sha512-nqUxEtvDqFhmV1/awSg0K2XHNwkftNaiUqCYO9e6+MYmqNObpKVl7OgMkGaQ2SZnFx5YqF0t60ZJTlyJIDAijg==", "dev": true }, "@next/swc-darwin-arm64": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.5-canary.2.tgz", - "integrity": "sha512-pqYPb2FGsT/srfiDIIaAQM1RbPuylVyfXifHYkzzFfsVbvyRU9O2TvWhgsK977v8DJiVEXJS9Y2zIlgvKVNQZQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.6.tgz", + "integrity": "sha512-ahi6VP98o4HV19rkOXPSUu+ovfHfUxbJQ7VVJ7gL2FnZRr7onEFC1oGQ6NQHpm8CxpIzSSBW79kumlFMOmZVjg==", "dev": true, "optional": true }, "@next/swc-darwin-x64": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.5-canary.2.tgz", - "integrity": "sha512-ZN910CRsKMNIJ2hFSQL1Lk7KDFZ+xz5kTfIBMG0IbApS3J8ayQXxMfVP17GchZbfPTyxI6Cnozo0Wz55/cjBrg==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.6.tgz", + "integrity": "sha512-13cXxKFsPJIJKzUqrU5XB1mc0xbUgYsRcdH6/rB8c4NMEbWGdtD4QoK9ShN31TZdePpD4k416Ur7p+deMIxnnA==", "dev": true, "optional": true }, "@next/swc-linux-arm64-gnu": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.5-canary.2.tgz", - "integrity": "sha512-IrXHRkDkBJUzZpVcYsez5oZpbcrbzJ6UNbXyL4UNFdIauOLv5JBjAKqUvnF+x5mq7o58+GD6NB+uA20uJVurng==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.6.tgz", + "integrity": "sha512-Ti+NMHEjTNktCVxNjeWbYgmZvA2AqMMI2AMlzkXsU7W4pXCMhrryAmAIoo+7YdJbsx01JQWYVxGe62G6DoCLaA==", "dev": true, "optional": true }, "@next/swc-linux-arm64-musl": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.5-canary.2.tgz", - "integrity": "sha512-B7ZY3fg9Ng0Eh7KKpv6siRI6yrrsuJBOCgVZmnWvtMuWI1jkyIwydVaRXAS8OlefimaOQ1LUJ1aWkqzTaGQscw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.6.tgz", + "integrity": "sha512-OHoC6gO7XfjstgwR+z6UHKlvhqJfyMtNaJidjx3sEcfaDwS7R2lqR5AABi8PuilGgi0BO0O0sCXqLlpp3a0emQ==", "dev": true, "optional": true }, "@next/swc-linux-x64-gnu": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.5-canary.2.tgz", - "integrity": "sha512-I9zd9nrgn6Dv5tF8s81YeDqagoil6u4Ul1TLV+aCibpf7QFtl1z1ebGbKHRY3czY0WEH5JpmjgwZE08uV4C/rQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.6.tgz", + "integrity": "sha512-zHZxPGkUlpfNJCboUrFqwlwEX5vI9LSN70b8XEb0DYzzlrZyCyOi7hwDp/+3Urm9AB7YCAJkgR5Sp1XBVjHdfQ==", "dev": true, "optional": true }, "@next/swc-linux-x64-musl": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.5-canary.2.tgz", - "integrity": "sha512-XkWxdLyG4boqtBX3POx20UZ5IIfdzMjn5nGsYwhTlDs4UohyzEOVZTBMkNKDxisJJH9zZO3w0lZT/aZx8CHZ+A==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.6.tgz", + "integrity": "sha512-K/Y8lYGTwTpv5ME8PSJxwxLolaDRdVy+lOd9yMRMiQE0BLUhtxtCWC9ypV42uh9WpLjoaD0joOsB9Q6mbrSGJg==", "dev": true, "optional": true }, "@next/swc-win32-arm64-msvc": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.5-canary.2.tgz", - "integrity": "sha512-hMVjxzrJ739aF2I88pLkufO9+6095SFsccfHJObTxWW9s6WRioKtui28OvBSNhdF7umdAIzMaDrGRNzJVgqyhw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.6.tgz", + "integrity": "sha512-U6LtxEUrjBL2tpW+Kr1nHCSJWNeIed7U7l5o7FiKGGwGgIlFi4UHDiLI6TQ2lxi20fAU33CsruV3U0GuzMlXIw==", "dev": true, "optional": true }, "@next/swc-win32-ia32-msvc": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.5-canary.2.tgz", - "integrity": "sha512-aYy7iswqT0jQrsaTBgOU7rxx9Qyn58w31Edgmh/xabm4I+sprLua/AvqwApqkvz847nIzMRvRpyjOEg1tXVMNQ==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.6.tgz", + "integrity": "sha512-eEBeAqpCfhdPSlCZCayjCiyIllVqy4tcqvm1xmg3BgJG0G5ITiMM4Cw2WVeRSgWDJqQGRyyb+q8Y2ltzhXOWsQ==", "dev": true, "optional": true }, "@next/swc-win32-x64-msvc": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.5-canary.2.tgz", - "integrity": "sha512-zOyjxW/fHuwUXDzU1AHKwwi+8Bf5uwLHYNNxoYTHzQPMNx3nHtwWSznI835NOSQay+7JcQIDX5goMj58zIeXkw==", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.6.tgz", + "integrity": "sha512-OrZs94AuO3ZS5tnqlyPRNgfWvboXaDQCi5aXGve3o3C+Sj0ctMUV9+Do+0zMvvLRumR8E0PTWKvtz9n5vzIsWw==", "dev": true, "optional": true }, @@ -15701,9 +15084,9 @@ "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" }, "@sinclair/typebox": { - "version": "0.24.38", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.38.tgz", - "integrity": "sha512-IbYB6vdhLFmzGEyXXEdFAJKyq7S4/RsivkgxNzs/LzwYuUJHmeNQ0cHkjG/Yqm6VgUzzZDLMZAf0XgeeaZAocA==", + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", "dev": true }, "@sindresorhus/is": { @@ -15722,12 +15105,23 @@ } }, "@sinonjs/fake-timers": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.1.0.tgz", + "integrity": "sha512-w1qd368vtrwttm1PRJWPW1QHlbmHrVDGs1eBH/jZvRPUFS4MNXV9Q33EQdjOdeAxZ7O8+3wM7zxztm2nfUSyKw==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@sinonjs/commons": "^3.0.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + } } }, "@swc/helpers": { @@ -15830,9 +15224,9 @@ } }, "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true }, "@types/aria-query": { @@ -15842,13 +15236,13 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.19", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", - "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", + "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", "dev": true, "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*" @@ -15874,12 +15268,12 @@ } }, "@types/babel__traverse": { - "version": "7.18.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.1.tgz", - "integrity": "sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==", + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", + "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", "dev": true, "requires": { - "@babel/types": "^7.3.0" + "@babel/types": "^7.20.7" } }, "@types/body-parser": { @@ -15941,9 +15335,9 @@ } }, "@types/graceful-fs": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", "dev": true, "requires": { "@types/node": "*" @@ -15955,12 +15349,6 @@ "integrity": "sha512-c3Xy026kOF7QOTn00hbIllV1dLR9hG9NkSrLQgCVs8NF6sBU+VGWjD3wLPhmh1TYAc7ugCFsvHYMN4VcBN1U1A==", "dev": true }, - "@types/http-errors": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-1.8.0.tgz", - "integrity": "sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==", - "dev": true - }, "@types/istanbul-lib-coverage": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", @@ -15986,13 +15374,49 @@ } }, "@types/jest": { - "version": "27.0.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.1.tgz", - "integrity": "sha512-HTLpVXHrY69556ozYkcq47TtQJXpcWAWfkoqz+ZGz2JnmZhzlRjprCIyFnetSy8gpDWwTTGBcRVv1J1I1vBrHw==", + "version": "29.5.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.2.tgz", + "integrity": "sha512-mSoZVJF5YzGVCk+FsDxzDuH7s+SCkzrgKZzf0Z0T2WudhBUPoF6ktoTPC4R0ZoCPCV5xUvuU6ias5NvxcBcMMg==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, + "@types/jsdom": { + "version": "20.0.1", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", + "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", "dev": true, "requires": { - "jest-diff": "^27.0.0", - "pretty-format": "^27.0.0" + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" } }, "@types/json-buffer": { @@ -16043,6 +15467,29 @@ "integrity": "sha512-LUhvPmAKAbgm+p/K11IWszLZVoZDlMF4NRmqbhEzDz/CnCuehPkZXwZbBCKGJsgjnuVejotBwM7B3Scrq4EqDw==", "dev": true }, + "@types/node-fetch": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.4.tgz", + "integrity": "sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==", + "dev": true, + "requires": { + "@types/node": "*", + "form-data": "^3.0.0" + }, + "dependencies": { + "form-data": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } + } + }, "@types/on-headers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/on-headers/-/on-headers-1.0.0.tgz", @@ -16053,9 +15500,9 @@ } }, "@types/prettier": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.0.tgz", - "integrity": "sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", "dev": true }, "@types/prop-types": { @@ -16215,9 +15662,9 @@ } }, "@types/yargs": { - "version": "17.0.20", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.20.tgz", - "integrity": "sha512-eknWrTHofQuPk2iuqDm1waA7V6xPlbgBoaaXEgYkClhLOnB0TtbW+srJaOToAgawPxPlHQzwypFA2bhZaUGP5A==", + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", "dev": true, "requires": { "@types/yargs-parser": "*" @@ -16398,13 +15845,21 @@ "dev": true }, "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", + "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", "dev": true, "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "acorn": "^8.1.0", + "acorn-walk": "^8.0.2" + }, + "dependencies": { + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + } } }, "acorn-jsx": { @@ -16415,9 +15870,9 @@ "requires": {} }, "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, "agent-base": { @@ -16809,49 +16264,26 @@ "isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, - "babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", - "dev": true, - "requires": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + } + } + }, + "babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "requires": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -16878,14 +16310,14 @@ } }, "babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", "dev": true, "requires": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", + "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, @@ -16910,12 +16342,12 @@ } }, "babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.5.1", + "babel-plugin-jest-hoist": "^29.5.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -17116,23 +16548,16 @@ "fill-range": "^7.0.1" } }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "version": "4.21.8", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.8.tgz", + "integrity": "sha512-j+7xYe+v+q2Id9qbBeCI8WX5NmZSRe8es1+0xntD/+gaWXznP8tFEkv5IgSaHf5dS1YwVMbX/4W6m937mj+wQw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "caniuse-lite": "^1.0.30001502", + "electron-to-chromium": "^1.4.428", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" } }, "browserstack-cypress-cli": { @@ -17279,15 +16704,6 @@ "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, "p-locate": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", @@ -17297,12 +16713,6 @@ "p-limit": "^2.0.0" } }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, "slice-ansi": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", @@ -17556,9 +16966,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001429", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", - "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", + "version": "1.0.30001503", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001503.tgz", + "integrity": "sha512-Sf9NiF+wZxPfzv8Z3iS0rXM1Do+iOy2Lxvib38glFX+08TCYYYGR5fRJXk4d77C4AYwhUjgYgMsMudbh2TqCKw==", "dev": true }, "caseless": { @@ -17605,9 +17015,9 @@ "dev": true }, "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, "clean-stack": { @@ -17667,13 +17077,13 @@ "dev": true }, "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "requires": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, @@ -17819,13 +17229,10 @@ "dev": true }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, "cookie": { "version": "0.5.0", @@ -17913,9 +17320,9 @@ "dev": true }, "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", "dev": true }, "cssstyle": { @@ -18060,14 +17467,14 @@ } }, "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" } }, "dayjs": { @@ -18091,9 +17498,9 @@ "dev": true }, "decimal.js": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.0.tgz", - "integrity": "sha512-Nv6ENEzyPQ6AItkGwLE2PGKinZZ9g59vSh2BeH6NqPu0OTKZ5ruJsVqh/orbAnqXc9pBbgXAIrc2EyaCj8NpGg==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, "decompress-response": { @@ -18138,9 +17545,9 @@ "dev": true }, "deepmerge": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true }, "defer-to-connect": { @@ -18180,7 +17587,8 @@ "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true }, "destroy": { "version": "1.2.0", @@ -18194,12 +17602,6 @@ "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, - "diff-sequences": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.5.1.tgz", - "integrity": "sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==", - "dev": true - }, "dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -18233,20 +17635,12 @@ "dev": true }, "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "dev": true, "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } + "webidl-conversions": "^7.0.0" } }, "dot-prop": { @@ -18305,15 +17699,15 @@ } }, "electron-to-chromium": { - "version": "1.3.836", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.836.tgz", - "integrity": "sha512-Ney3pHOJBWkG/AqYjrW0hr2AUCsao+2uvq9HUlRP8OlpSdk/zOHOUJP7eu0icDvePC9DlgffuelP4TnOJmMRUg==", + "version": "1.4.431", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.431.tgz", + "integrity": "sha512-m232JTVmCawA2vG+1azVxhKZ9Sv1Q//xxNv5PkP5rWxGgQE8c3CiZFrh8Xnp+d1NmNxlu3QQrGIfdeW5TtXX5w==", "dev": true }, "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true }, "emoji-regex": { @@ -18356,6 +17750,12 @@ "ansi-colors": "^4.1.1" } }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -18982,48 +18382,18 @@ "dev": true }, "expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -19034,21 +18404,24 @@ "supports-color": "^7.1.0" } }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" } } } @@ -19130,9 +18503,9 @@ } }, "fb-watchman": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz", - "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, "requires": { "bser": "2.1.1" @@ -19209,6 +18582,24 @@ "integrity": "sha512-zrXoV1Uaz52DqPs+qEwNJWJFAWZpYJ47UNmpN9q4j+/EYsz85uV0DC9k8tRND5kYmoVzL0W+Y75q4Rg8sRJCdg==", "dev": true }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "dependencies": { + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + } + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -19465,6 +18856,12 @@ "is-glob": "^4.0.1" } }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, "global-dirs": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", @@ -19619,12 +19016,12 @@ "dev": true }, "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.5" + "whatwg-encoding": "^2.0.0" } }, "html-escaper": { @@ -19653,6 +19050,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.4", @@ -19662,12 +19060,12 @@ } }, "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, "requires": { - "@tootallnate/once": "1", + "@tootallnate/once": "2", "agent-base": "6", "debug": "4" } @@ -19781,7 +19179,8 @@ "inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "ini": { "version": "2.0.0", @@ -20127,9 +19526,9 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", - "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -20196,59 +19595,27 @@ } }, "jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", "dev": true, "requires": { - "@jest/core": "^27.5.1", + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", "import-local": "^3.0.2", - "jest-cli": "^27.5.1" + "jest-cli": "^29.5.0" } }, "jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", "dev": true, "requires": { - "@jest/types": "^27.5.1", "execa": "^5.0.0", - "throat": "^6.0.1" + "p-limit": "^3.1.0" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -20277,102 +19644,46 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } } } }, "jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", "dev": true, "requires": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "dedent": "^0.7.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20383,77 +19694,76 @@ "supports-color": "^7.1.0" } }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "picomatch": "^2.2.3" } }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "yocto-queue": "^0.1.0" + } + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true } } }, "jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", "dev": true, "requires": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "prompts": "^2.0.1", - "yargs": "^16.2.0" + "yargs": "^17.3.1" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20463,143 +19773,146 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } } } }, "jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", "dev": true, "requires": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" } - } - } - }, - "jest-diff": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", - "integrity": "sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - }, - "dependencies": { - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true } } }, "jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", "dev": true, "requires": { - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20609,90 +19922,70 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } - } - } - }, - "jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, + "jest-environment-jsdom": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.5.0.tgz", + "integrity": "sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/jsdom": "^20.0.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0", + "jsdom": "^20.0.0" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20703,31 +19996,18 @@ "supports-color": "^7.1.0" } }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "picomatch": "^2.2.3" } } } @@ -20860,55 +20140,26 @@ "jest-environment-node": "^27.2.4" } }, - "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", - "dev": true - }, "jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", + "@jest/types": "^29.5.0", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", "micromatch": "^4.0.4", - "walker": "^1.0.7" + "walker": "^1.0.8" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -20918,159 +20169,74 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } } } }, - "jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", "dev": true, "requires": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" } }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" - } + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true } } }, - "jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", - "dev": true, - "requires": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, "jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" }, "dependencies": { "chalk": { @@ -21082,47 +20248,82 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true + }, + "jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + } + }, + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true } } }, "jest-message-util": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", - "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^28.1.3", + "@jest/types": "^29.5.0", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^28.1.3", + "pretty-format": "^29.5.0", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "@babel/code-frame": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", + "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", "dev": true, "requires": { - "@jest/schemas": "^28.1.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" + "@babel/highlight": "^7.22.5" } }, "chalk": { @@ -21136,13 +20337,12 @@ } }, "pretty-format": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", - "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@jest/schemas": "^28.1.3", - "ansi-regex": "^5.0.1", + "@jest/schemas": "^29.4.3", "ansi-styles": "^5.0.0", "react-is": "^18.0.0" }, @@ -21164,29 +20364,16 @@ } }, "jest-mock": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", - "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", "dev": true, "requires": { - "@jest/types": "^28.1.3", - "@types/node": "*" + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" }, "dependencies": { - "@jest/types": { - "version": "28.1.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", - "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", - "dev": true, - "requires": { - "@jest/schemas": "^28.1.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" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -21196,62 +20383,53 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } } } }, "jest-pnp-resolver": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", - "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, "requires": {} }, "jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", "dev": true }, "jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", "dev": true, "requires": { - "@jest/types": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", + "jest-haste-map": "^29.5.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", "resolve": "^1.20.0", - "resolve.exports": "^1.1.0", + "resolve.exports": "^2.0.0", "slash": "^3.0.0" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -21261,284 +20439,141 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } } } }, "jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - } + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" } }, "jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", "dev": true, "requires": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "emittery": "^0.13.1", "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" - } - }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, - "requires": { - "@sinonjs/commons": "^1.7.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" - } - } - } - }, - "jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "execa": "^5.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", - "dev": true, - "requires": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1" - } - }, - "@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", - "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", "dev": true, "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" } }, - "@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@sinonjs/commons": "^1.7.0" + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" } }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "yocto-queue": "^0.1.0" } - }, + } + } + }, + "jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@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.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -21549,60 +20584,18 @@ "supports-color": "^7.1.0" } }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "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" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", + "@jest/types": "^29.5.0", + "@types/node": "*", "chalk": "^4.0.0", + "ci-info": "^3.2.0", "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - } - }, - "jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", - "dev": true, - "requires": { - "@jest/types": "^27.5.1", - "@types/node": "*" + "picomatch": "^2.2.3" } }, "strip-bom": { @@ -21613,108 +20606,114 @@ } } }, - "jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - } - }, "jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", "dev": true, "requires": { - "@babel/core": "^7.7.2", + "@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/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.5.1", + "expect": "^29.5.0", "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" + "pretty-format": "^29.5.0", + "semver": "^7.3.5" }, "dependencies": { - "@babel/code-frame": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "@babel/highlight": "^7.18.6" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" } }, - "jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -21771,41 +20770,19 @@ } }, "jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", "dev": true, "requires": { - "@jest/types": "^27.5.1", + "@jest/types": "^29.5.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", + "jest-get-type": "^29.4.3", "leven": "^3.1.0", - "pretty-format": "^27.5.1" + "pretty-format": "^29.5.0" }, "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -21821,46 +20798,56 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } - } - } - }, - "jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", - "dev": true, - "requires": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "jest-util": "^27.5.1", - "string-length": "^4.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } }, - "@types/yargs": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", - "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", "dev": true, "requires": { - "@types/yargs-parser": "*" + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } } }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "requires": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "dependencies": { "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -21870,20 +20857,70 @@ "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } } } }, "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", "dev": true, "requires": { "@types/node": "*", + "jest-util": "^29.5.0", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -21935,50 +20972,49 @@ "dev": true }, "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", + "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", + "abab": "^2.0.6", + "acorn": "^8.8.1", + "acorn-globals": "^7.0.0", + "cssom": "^0.5.0", "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", + "data-urls": "^3.0.2", + "decimal.js": "^10.4.2", + "domexception": "^4.0.0", "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", + "nwsapi": "^2.2.2", + "parse5": "^7.1.1", + "saxes": "^6.0.0", "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0", + "ws": "^8.11.0", + "xml-name-validator": "^4.0.0" }, "dependencies": { "acorn": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", "dev": true }, "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, "requires": { "asynckit": "^0.4.0", @@ -22256,6 +21292,15 @@ } } }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -22554,26 +21599,27 @@ "dev": true }, "next": { - "version": "13.4.5-canary.2", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.5-canary.2.tgz", - "integrity": "sha512-mcUWP0rqWv+Fq1pJBnrBhntm9WoRVJt+ONt5RzkBBBfZNBHqa4NQKBmU5GQEoQRoXOHWhpEl6a5R9rISr08msQ==", - "dev": true, - "requires": { - "@next/env": "13.4.5-canary.2", - "@next/swc-darwin-arm64": "13.4.5-canary.2", - "@next/swc-darwin-x64": "13.4.5-canary.2", - "@next/swc-linux-arm64-gnu": "13.4.5-canary.2", - "@next/swc-linux-arm64-musl": "13.4.5-canary.2", - "@next/swc-linux-x64-gnu": "13.4.5-canary.2", - "@next/swc-linux-x64-musl": "13.4.5-canary.2", - "@next/swc-win32-arm64-msvc": "13.4.5-canary.2", - "@next/swc-win32-ia32-msvc": "13.4.5-canary.2", - "@next/swc-win32-x64-msvc": "13.4.5-canary.2", + "version": "13.4.6", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.6.tgz", + "integrity": "sha512-sjVqjxU+U2aXZnYt4Ud6CTLNNwWjdSfMgemGpIQJcN3Z7Jni9xRWbR0ie5fQzCg87aLqQVhKA2ud2gPoqJ9lGw==", + "dev": true, + "requires": { + "@next/env": "13.4.6", + "@next/swc-darwin-arm64": "13.4.6", + "@next/swc-darwin-x64": "13.4.6", + "@next/swc-linux-arm64-gnu": "13.4.6", + "@next/swc-linux-arm64-musl": "13.4.6", + "@next/swc-linux-x64-gnu": "13.4.6", + "@next/swc-linux-x64-musl": "13.4.6", + "@next/swc-win32-arm64-msvc": "13.4.6", + "@next/swc-win32-ia32-msvc": "13.4.6", + "@next/swc-win32-x64-msvc": "13.4.6", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", "postcss": "8.4.14", "styled-jsx": "5.1.1", + "watchpack": "2.4.0", "zod": "3.21.4" } }, @@ -22589,6 +21635,39 @@ "propagate": "^2.0.0" } }, + "node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + }, + "dependencies": { + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -22596,9 +21675,9 @@ "dev": true }, "node-releases": { - "version": "1.1.75", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz", - "integrity": "sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw==", + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", "dev": true }, "normalize-path": { @@ -22623,9 +21702,9 @@ } }, "nwsapi": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.2.tgz", - "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==", + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", + "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==", "dev": true }, "oauth-sign": { @@ -22634,6 +21713,11 @@ "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true }, + "oauth4webapi": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-2.3.0.tgz", + "integrity": "sha512-JGkb5doGrwzVDuHwgrR4nHJayzN4h59VCed6EW8Tql6iHDfZIabCJvg6wtbn5q6pyB2hZruI3b77Nudvq7NmvA==" + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -22852,6 +21936,24 @@ "integrity": "sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==", "dev": true }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, "p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", @@ -22861,6 +21963,12 @@ "aggregate-error": "^3.0.0" } }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, "package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -23022,10 +22130,13 @@ } }, "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "requires": { + "entities": "^4.4.0" + } }, "parseurl": { "version": "1.3.3", @@ -23122,57 +22233,6 @@ "dev": true, "requires": { "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - } } }, "postcss": { @@ -23335,12 +22395,24 @@ "escape-goat": "^2.0.0" } }, + "pure-rand": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", + "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", + "dev": true + }, "qs": { "version": "6.5.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -23639,6 +22711,12 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve": { "version": "1.22.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", @@ -23680,9 +22758,9 @@ "dev": true }, "resolve.exports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true }, "responselike": { @@ -23761,9 +22839,9 @@ "dev": true }, "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "requires": { "xmlchars": "^2.2.0" @@ -23808,7 +22886,8 @@ "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true }, "shebang-command": { "version": "2.0.0", @@ -23890,9 +22969,9 @@ "dev": true }, "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -24004,7 +23083,8 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true }, "stream-combiner": { "version": "0.0.4", @@ -24151,16 +23231,6 @@ "has-flag": "^4.0.0" } }, - "supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", - "dev": true, - "requires": { - "has-flag": "^4.0.0", - "supports-color": "^7.0.0" - } - }, "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -24279,16 +23349,6 @@ } } }, - "terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" - } - }, "test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -24306,12 +23366,6 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, - "throat": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", - "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", - "dev": true - }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", @@ -24358,7 +23412,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true }, "to-readable-stream": { @@ -24379,31 +23433,33 @@ "toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true }, "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "requires": { "psl": "^1.1.33", "punycode": "^2.1.1", - "universalify": "^0.1.2" + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "dependencies": { "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true } } }, "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, "requires": { "punycode": "^2.1.1" @@ -24416,21 +23472,45 @@ "dev": true }, "ts-jest": { - "version": "27.1.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", - "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", + "version": "29.1.0", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.0.tgz", + "integrity": "sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA==", "dev": true, "requires": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "20.x" + "yargs-parser": "^21.0.1" }, "dependencies": { + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -24646,6 +23726,16 @@ } } }, + "update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, "update-notifier": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", @@ -24718,6 +23808,16 @@ "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "url-parse-lax": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", @@ -24746,20 +23846,20 @@ "dev": true }, "v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^1.6.0" }, "dependencies": { - "source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true } } @@ -24793,22 +23893,13 @@ "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", "dev": true }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, "requires": { - "xml-name-validator": "^3.0.0" + "xml-name-validator": "^4.0.0" } }, "wait-on": { @@ -24833,36 +23924,56 @@ "makeerror": "1.0.12" } }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true }, "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "requires": { - "iconv-lite": "0.4.24" + "iconv-lite": "0.6.3" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } } }, "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true }, "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" } }, "which": { @@ -24992,9 +24103,9 @@ } }, "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, "requires": {} }, @@ -25005,9 +24116,9 @@ "dev": true }, "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true }, "xmlchars": { @@ -25028,18 +24139,18 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "requires": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "dependencies": { "y18n": { @@ -25051,9 +24162,9 @@ } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yauzl": { @@ -25072,6 +24183,12 @@ "integrity": "sha512-RXRJzMiK6U2ye0BlGGZnmpwJDPgakn6aNQ0A7gHRbD4I0uvK4TW6UqkK1V0pp9jskjJBAXd3dRrbzWkqJ+6cxA==", "dev": true }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, "zip-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", diff --git a/package.json b/package.json index f976647b2..2f8c557d8 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ }, "homepage": "https://github.com/auth0/nextjs-auth0#readme", "devDependencies": { - "@edge-runtime/jest-environment": "^1.1.0-beta.31", + "@edge-runtime/jest-environment": "^2.1.0", "@testing-library/jest-dom": "^5.11.9", "@testing-library/react": "^13.4.0", "@testing-library/react-hooks": "^5.0.3", @@ -76,10 +76,10 @@ "@types/clone": "^2.1.0", "@types/cookie": "^0.5.1", "@types/debug": "^4.1.5", - "@types/http-errors": "^1.8.0", - "@types/jest": "^27.0.1", + "@types/jest": "^29.5.2", "@types/jsonwebtoken": "^8.5.0", "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", "@types/on-headers": "^1.0.0", "@types/react": "^18.0.24", "@types/react-dom": "^17.0.9", @@ -99,10 +99,12 @@ "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", - "jest": "^27.2.0", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", "jest-environment-node-single-context": "^27.3.0", - "next": "^13.4.5-canary.0", + "next": "^13.4.6", "nock": "^13.0.5", + "node-fetch": "^2.6.11", "oidc-provider": "^7.6.0", "on-headers": "^1.0.2", "prettier": "^2.2.1", @@ -113,7 +115,7 @@ "start-server-and-test": "^1.11.7", "timekeeper": "^2.2.0", "tough-cookie": "^4.0.0", - "ts-jest": "^27.0.5", + "ts-jest": "^29.1.0", "typedoc": "^0.24.1", "typescript": "^4.1.3" }, @@ -121,9 +123,9 @@ "@panva/hkdf": "^1.0.2", "cookie": "^0.5.0", "debug": "^4.3.4", - "http-errors": "^1.8.1", "joi": "^17.6.0", "jose": "^4.9.2", + "oauth4webapi": "^2.3.0", "openid-client": "^5.2.1", "tslib": "^2.4.0", "url-join": "^4.0.1" @@ -132,16 +134,11 @@ "next": ">=10" }, "jest": { - "testEnvironment": "jest-environment-node-single-context", - "rootDir": ".", - "moduleFileExtensions": [ - "ts", - "tsx", - "js" - ], "collectCoverageFrom": [ "/src/**/*.*", "!/src/edge.ts", + "!/src/index.ts", + "!/src/shared.ts", "!/src/auth0-session/config.ts", "!/src/auth0-session/index.ts", "!/src/auth0-session/session-cache.ts" @@ -160,10 +157,9 @@ } }, "coverageProvider": "v8", - "preset": "ts-jest", - "globalSetup": "./tests/global-setup.ts", - "setupFilesAfterEnv": [ - "./tests/setup.ts" + "projects": [ + "/jest-node.config.js", + "/jest-edge.config.js" ] } } diff --git a/scripts/oidc-provider.js b/scripts/oidc-provider.js index 14a3d8e10..cec7f3645 100644 --- a/scripts/oidc-provider.js +++ b/scripts/oidc-provider.js @@ -21,7 +21,11 @@ const config = { { client_id: 'testing', client_secret: 'testing', - redirect_uris: ['http://localhost:3000/api/auth/callback', 'http://localhost:3000/api/page-router-auth/callback'], + redirect_uris: [ + 'http://localhost:3000/api/auth/callback', + 'http://localhost:3000/api/page-router-auth/callback', + 'http://localhost:3000/api/edge-auth/callback' + ], post_logout_redirect_uris: ['http://localhost:3000', 'http://localhost:3000/page-router'], token_endpoint_auth_method: 'client_secret_post', grant_types: ['authorization_code', 'refresh_token'] @@ -53,7 +57,7 @@ module.exports = function createProvider(opts) { provider.use(async (ctx, next) => { await next(); - if (ctx.oidc.route === 'end_session_success') { + if (ctx.oidc?.route === 'end_session_success') { ctx.redirect('http://localhost:3000'); } }); diff --git a/src/auth0-session/client.ts b/src/auth0-session/client.ts deleted file mode 100644 index d0ce9f32f..000000000 --- a/src/auth0-session/client.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { Issuer, custom, Client, EndSessionParameters, ClientAuthMethod } from 'openid-client'; -import url, { UrlObject } from 'url'; -import urlJoin from 'url-join'; -import createDebug from './utils/debug'; -import { DiscoveryError } from './utils/errors'; -import { Config } from './config'; -import { ParsedUrlQueryInput } from 'querystring'; -import { exportJWK } from 'jose'; -import { createPrivateKey } from 'crypto'; - -const debug = createDebug('client'); - -export interface ClientFactory { - (): Promise; -} - -export type Telemetry = { - name: string; - version: string; -}; - -function sortSpaceDelimitedString(str: string): string { - return str.split(' ').sort().join(' '); -} - -export default function get(config: Config, { name, version }: Telemetry): ClientFactory { - let client: Client | null = null; - - return async (): Promise => { - if (client) { - return client; - } - - custom.setHttpOptionsDefaults({ - headers: { - 'User-Agent': `${name}/${version}`, - ...(config.enableTelemetry - ? { - 'Auth0-Client': Buffer.from( - JSON.stringify({ - name, - version, - env: { - node: process.version - } - }) - ).toString('base64') - } - : undefined) - }, - timeout: config.httpTimeout - }); - - let issuer: Issuer; - try { - issuer = await Issuer.discover(config.issuerBaseURL); - } catch (e) { - throw new DiscoveryError(e, config.issuerBaseURL); - } - - const issuerTokenAlgs = Array.isArray(issuer.id_token_signing_alg_values_supported) - ? issuer.id_token_signing_alg_values_supported - : []; - if (!issuerTokenAlgs.includes(config.idTokenSigningAlg)) { - debug( - 'ID token algorithm %o is not supported by the issuer. Supported ID token algorithms are: %o.', - config.idTokenSigningAlg, - issuerTokenAlgs - ); - } - - const configRespType = sortSpaceDelimitedString(config.authorizationParams.response_type); - const issuerRespTypes = Array.isArray(issuer.response_types_supported) ? issuer.response_types_supported : []; - issuerRespTypes.map(sortSpaceDelimitedString); - if (!issuerRespTypes.includes(configRespType)) { - debug( - 'Response type %o is not supported by the issuer. Supported response types are: %o.', - configRespType, - issuerRespTypes - ); - } - - const configRespMode = config.authorizationParams.response_mode; - const issuerRespModes = Array.isArray(issuer.response_modes_supported) ? issuer.response_modes_supported : []; - if (configRespMode && !issuerRespModes.includes(configRespMode)) { - debug( - 'Response mode %o is not supported by the issuer. Supported response modes are %o.', - configRespMode, - issuerRespModes - ); - } - - let jwks; - if (config.clientAssertionSigningKey) { - const privateKey = createPrivateKey({ key: config.clientAssertionSigningKey }); - const jwk = await exportJWK(privateKey); - jwks = { keys: [jwk] }; - } - - client = new issuer.Client( - { - client_id: config.clientID, - client_secret: config.clientSecret, - id_token_signed_response_alg: config.idTokenSigningAlg, - token_endpoint_auth_method: config.clientAuthMethod as ClientAuthMethod, - token_endpoint_auth_signing_alg: config.clientAssertionSigningAlg - }, - jwks - ); - client[custom.clock_tolerance] = config.clockTolerance; - - if (config.idpLogout) { - if ( - config.auth0Logout || - ((url.parse(issuer.metadata.issuer).hostname as string).match('\\.auth0\\.com$') && - config.auth0Logout !== false) - ) { - Object.defineProperty(client, 'endSessionUrl', { - value(params: EndSessionParameters) { - const { id_token_hint, post_logout_redirect_uri, ...extraParams } = params; - const parsedUrl: UrlObject = url.parse(urlJoin(issuer.metadata.issuer, '/v2/logout')); - parsedUrl.query = { - ...extraParams, - returnTo: post_logout_redirect_uri, - client_id: config.clientID - }; - Object.entries(parsedUrl.query).forEach(([key, value]) => { - if (value === null || value === undefined) { - delete (parsedUrl.query as ParsedUrlQueryInput)[key]; - } - }); - return url.format(parsedUrl); - } - }); - } else if (!issuer.end_session_endpoint) { - debug('the issuer does not support RP-Initiated Logout'); - } - } - - return client; - }; -} diff --git a/src/auth0-session/client/abstract-client.ts b/src/auth0-session/client/abstract-client.ts new file mode 100644 index 000000000..d51771e73 --- /dev/null +++ b/src/auth0-session/client/abstract-client.ts @@ -0,0 +1,106 @@ +import { Config } from '../config'; +import { Auth0Request } from '../http'; + +export type Telemetry = { + name: string; + version: string; +}; + +export interface CallbackParamsType { + access_token?: string; + code?: string; + error?: string; + error_description?: string; + error_uri?: string; + expires_in?: string; + id_token?: string; + state?: string; + token_type?: string; + session_state?: string; + response?: string; + + [key: string]: any; +} + +export interface CallbackExtras { + exchangeBody?: Record; + clientAssertionPayload?: Record; +} + +export interface OpenIDCallbackChecks { + max_age?: number; + nonce?: string; + response_type: string; + state?: string; + code_verifier?: string; +} + +export interface TokenEndpointResponse { + access_token?: string; + token_type?: string; + id_token?: string; + refresh_token?: string; + scope?: string; + expires_in?: number; + [key: string]: unknown; +} + +export interface EndSessionParameters { + id_token_hint?: string; + post_logout_redirect_uri: string; + state?: string; + client_id?: string; + logout_hint?: string; + + [key: string]: any; +} + +export type ClientAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'private_key_jwt' | 'none'; + +export interface AuthorizationParameters { + acr_values?: string; + audience?: string; + claims_locales?: string; + client_id?: string; + code_challenge_method?: string; + code_challenge?: string; + display?: string; + id_token_hint?: string; + login_hint?: string; + max_age?: number; + nonce?: string; + prompt?: string; + redirect_uri?: string; + registration?: string; + request_uri?: string; + request?: string; + resource?: string | string[]; + response_mode?: string; + response_type?: string; + scope?: string; + state?: string; + ui_locales?: string; + + [key: string]: unknown; +} + +export abstract class AbstractClient { + constructor(protected config: Config, protected telemetry: Telemetry) {} + abstract authorizationUrl(parameters: Record): Promise; + abstract callbackParams(req: Auth0Request, expectedState: string): Promise; + abstract callback( + redirectUri: string, + parameters: URLSearchParams, + checks: OpenIDCallbackChecks, + extras: CallbackExtras + ): Promise; + abstract endSessionUrl(parameters: EndSessionParameters): Promise; + abstract userinfo(accessToken: string): Promise>; + abstract refresh( + refreshToken: string, + extras: { exchangeBody?: Record } + ): Promise; + abstract generateRandomCodeVerifier(): string; + abstract generateRandomNonce(): string; + abstract calculateCodeChallenge(codeVerifier: string): Promise | string; +} diff --git a/src/auth0-session/client/edge-client.ts b/src/auth0-session/client/edge-client.ts new file mode 100644 index 000000000..0529d1c69 --- /dev/null +++ b/src/auth0-session/client/edge-client.ts @@ -0,0 +1,245 @@ +import * as oauth from 'oauth4webapi'; +import * as jose from 'jose'; +import { Auth0Request } from '../http'; +import { + CallbackExtras, + OpenIDCallbackChecks, + TokenEndpointResponse, + AbstractClient, + EndSessionParameters, + Telemetry +} from './abstract-client'; +import { ApplicationError, DiscoveryError, IdentityProviderError, UserInfoError } from '../utils/errors'; +import { AccessTokenError, AccessTokenErrorCode } from '../../utils/errors'; +import urlJoin from 'url-join'; +import { Config } from '../config'; + +const encodeBase64 = (input: string) => { + const unencoded = new TextEncoder().encode(input); + const CHUNK_SIZE = 0x8000; + const arr = []; + for (let i = 0; i < unencoded.length; i += CHUNK_SIZE) { + // @ts-expect-error Argument of type 'Uint8Array' is not assignable to parameter of type 'number[]'. + arr.push(String.fromCharCode.apply(null, unencoded.subarray(i, i + CHUNK_SIZE))); + } + return btoa(arr.join('')); +}; + +export class EdgeClient extends AbstractClient { + private client?: oauth.Client; + private as?: oauth.AuthorizationServer; + private httpOptions: () => oauth.HttpRequestOptions; + + constructor(protected config: Config, protected telemetry: Telemetry) { + super(config, telemetry); + if (config.authorizationParams.response_type !== 'code') { + throw new Error('This SDK only supports `response_type=code` when used in an Edge runtime.'); + } + + this.httpOptions = () => { + const headers = new Headers(); + if (config.enableTelemetry) { + const { name, version } = telemetry; + headers.set('User-Agent', `${name}/${version}`); + headers.set( + 'Auth0-Client', + encodeBase64( + JSON.stringify({ + name, + version, + env: { + edge: true + } + }) + ) + ); + } + return { + signal: AbortSignal.timeout(this.config.httpTimeout), + headers + }; + }; + } + + private async getClient(): Promise<[oauth.AuthorizationServer, oauth.Client]> { + if (this.as) { + return [this.as, this.client as oauth.Client]; + } + + const issuer = new URL(this.config.issuerBaseURL); + try { + this.as = await oauth + .discoveryRequest(issuer, this.httpOptions()) + .then((response) => oauth.processDiscoveryResponse(issuer, response)); + } catch (e) { + throw new DiscoveryError(e, this.config.issuerBaseURL); + } + + this.client = { + client_id: this.config.clientID, + ...(!this.config.clientAssertionSigningKey && { client_secret: this.config.clientSecret }), + token_endpoint_auth_method: this.config.clientAuthMethod, + id_token_signed_response_alg: this.config.idTokenSigningAlg, + [oauth.clockTolerance]: this.config.clockTolerance + }; + + return [this.as, this.client]; + } + + async authorizationUrl(parameters: Record): Promise { + const [as] = await this.getClient(); + const authorizationUrl = new URL(as.authorization_endpoint as string); + authorizationUrl.searchParams.set('client_id', this.config.clientID); + Object.entries(parameters).forEach(([key, value]) => { + if (value === null || value === undefined) { + return; + } + authorizationUrl.searchParams.set(key, String(value)); + }); + return authorizationUrl.toString(); + } + + async callbackParams(req: Auth0Request, expectedState: string) { + const [as, client] = await this.getClient(); + const url = + req.getMethod().toUpperCase() === 'GET' ? new URL(req.getUrl()) : new URLSearchParams(await req.getBody()); + let result: ReturnType; + try { + result = oauth.validateAuthResponse(as, client, url, expectedState); + } catch (e) { + throw new ApplicationError(e); + } + if (oauth.isOAuth2Error(result)) { + throw new IdentityProviderError({ + message: result.error_description || result.error, + error: result.error, + error_description: result.error_description + }); + } + return result; + } + + async callback( + redirectUri: string, + parameters: URLSearchParams, + checks: OpenIDCallbackChecks, + extras: CallbackExtras + ): Promise { + const [as, client] = await this.getClient(); + + const { clientAssertionSigningKey, clientAssertionSigningAlg } = this.config; + + let clientPrivateKey = clientAssertionSigningKey as CryptoKey | undefined; + /* c8 ignore next 3 */ + if (clientPrivateKey && !(clientPrivateKey instanceof CryptoKey)) { + clientPrivateKey = await jose.importPKCS8(clientPrivateKey, clientAssertionSigningAlg || 'RS256'); + } + const response = await oauth.authorizationCodeGrantRequest( + as, + client, + parameters, + redirectUri, + checks.code_verifier as string, + { + additionalParameters: extras.exchangeBody, + ...(clientPrivateKey && { clientPrivateKey }), + ...this.httpOptions() + } + ); + + const result = await oauth.processAuthorizationCodeOpenIDResponse( + as, + client, + response, + checks.nonce, + checks.max_age + ); + if (oauth.isOAuth2Error(result)) { + throw new IdentityProviderError({ + message: result.error_description || /* c8 ignore next */ result.error, + error: result.error, + error_description: result.error_description + }); + } + return result; + } + + async endSessionUrl(parameters: EndSessionParameters): Promise { + const [as] = await this.getClient(); + const issuerUrl = new URL(as.issuer); + + if ( + this.config.idpLogout && + (this.config.auth0Logout || (issuerUrl.hostname.match('\\.auth0\\.com$') && this.config.auth0Logout !== false)) + ) { + const { id_token_hint, post_logout_redirect_uri, ...extraParams } = parameters; + const auth0LogoutUrl: URL = new URL(urlJoin(as.issuer, '/v2/logout')); + post_logout_redirect_uri && auth0LogoutUrl.searchParams.set('returnTo', post_logout_redirect_uri); + auth0LogoutUrl.searchParams.set('client_id', this.config.clientID); + Object.entries(extraParams).forEach(([key, value]: [string, string]) => { + if (value === null || value === undefined) { + return; + } + auth0LogoutUrl.searchParams.set(key, value); + }); + return auth0LogoutUrl.toString(); + } + if (!as.end_session_endpoint) { + throw new Error('RP Initiated Logout is not supported on your Authorization Server.'); + } + const oidcLogoutUrl = new URL(as.end_session_endpoint); + Object.entries(parameters).forEach(([key, value]: [string, string]) => { + if (value === null || value === undefined) { + return; + } + oidcLogoutUrl.searchParams.set(key, value); + }); + + oidcLogoutUrl.searchParams.set('client_id', this.config.clientID); + return oidcLogoutUrl.toString(); + } + + async userinfo(accessToken: string): Promise> { + const [as, client] = await this.getClient(); + const response = await oauth.userInfoRequest(as, client, accessToken, this.httpOptions()); + + try { + return await oauth.processUserInfoResponse(as, client, oauth.skipSubjectCheck, response); + } catch (e) { + throw new UserInfoError(e.message); + } + } + + async refresh(refreshToken: string, extras: { exchangeBody: Record }): Promise { + const [as, client] = await this.getClient(); + const res = await oauth.refreshTokenGrantRequest(as, client, refreshToken, { + additionalParameters: extras.exchangeBody, + ...this.httpOptions() + }); + const result = await oauth.processRefreshTokenResponse(as, client, res); + if (oauth.isOAuth2Error(result)) { + throw new AccessTokenError( + AccessTokenErrorCode.FAILED_REFRESH_GRANT, + 'The request to refresh the access token failed.', + new IdentityProviderError({ + message: result.error_description || /* c8 ignore next */ result.error, + error: result.error, + error_description: result.error_description + }) + ); + } + return result; + } + + generateRandomCodeVerifier(): string { + return oauth.generateRandomCodeVerifier(); + } + + generateRandomNonce(): string { + return oauth.generateRandomNonce(); + } + + calculateCodeChallenge(codeVerifier: string): Promise { + return oauth.calculatePKCECodeChallenge(codeVerifier); + } +} diff --git a/src/auth0-session/client/node-client.ts b/src/auth0-session/client/node-client.ts new file mode 100644 index 000000000..264b6a714 --- /dev/null +++ b/src/auth0-session/client/node-client.ts @@ -0,0 +1,236 @@ +import { Auth0Request } from '../http'; +import { + CallbackExtras, + CallbackParamsType, + OpenIDCallbackChecks, + TokenEndpointResponse, + AbstractClient +} from './abstract-client'; +import { + Client, + ClientAuthMethod, + custom, + CustomHttpOptionsProvider, + EndSessionParameters, + errors, + generators, + Issuer +} from 'openid-client'; +import { ApplicationError, DiscoveryError, EscapedError, IdentityProviderError, UserInfoError } from '../utils/errors'; +import { createPrivateKey } from 'crypto'; +import { exportJWK } from 'jose'; +import urlJoin from 'url-join'; +import createDebug from '../utils/debug'; +import { IncomingMessage } from 'http'; +import { AccessTokenError, AccessTokenErrorCode } from '../../utils/errors'; + +const debug = createDebug('client'); + +function sortSpaceDelimitedString(str: string): string { + return str.split(' ').sort().join(' '); +} + +export class NodeClient extends AbstractClient { + private client?: Client; + + private async getClient(): Promise { + if (this.client) { + return this.client; + } + const { + config, + telemetry: { name, version } + } = this; + + const defaultHttpOptions: CustomHttpOptionsProvider = (_url, options) => ({ + ...options, + headers: { + ...options.headers, + 'User-Agent': `${name}/${version}`, + ...(config.enableTelemetry + ? { + 'Auth0-Client': Buffer.from( + JSON.stringify({ + name, + version, + env: { + node: process.version + } + }) + ).toString('base64') + } + : undefined) + }, + timeout: config.httpTimeout + }); + const applyHttpOptionsCustom = (entity: Issuer | typeof Issuer | Client) => { + entity[custom.http_options] = defaultHttpOptions; + }; + + applyHttpOptionsCustom(Issuer); + let issuer: Issuer; + try { + issuer = await Issuer.discover(config.issuerBaseURL); + } catch (e) { + throw new DiscoveryError(e, config.issuerBaseURL); + } + applyHttpOptionsCustom(issuer); + + const issuerTokenAlgs = Array.isArray(issuer.id_token_signing_alg_values_supported) + ? issuer.id_token_signing_alg_values_supported + : []; + if (!issuerTokenAlgs.includes(config.idTokenSigningAlg)) { + debug( + 'ID token algorithm %o is not supported by the issuer. Supported ID token algorithms are: %o.', + config.idTokenSigningAlg, + issuerTokenAlgs + ); + } + + const configRespType = sortSpaceDelimitedString(config.authorizationParams.response_type); + const issuerRespTypes = Array.isArray(issuer.response_types_supported) ? issuer.response_types_supported : []; + issuerRespTypes.map(sortSpaceDelimitedString); + if (!issuerRespTypes.includes(configRespType)) { + debug( + 'Response type %o is not supported by the issuer. Supported response types are: %o.', + configRespType, + issuerRespTypes + ); + } + + const configRespMode = config.authorizationParams.response_mode; + const issuerRespModes = Array.isArray(issuer.response_modes_supported) ? issuer.response_modes_supported : []; + if (configRespMode && !issuerRespModes.includes(configRespMode)) { + debug( + 'Response mode %o is not supported by the issuer. Supported response modes are %o.', + configRespMode, + issuerRespModes + ); + } + + let jwks; + if (config.clientAssertionSigningKey) { + const privateKey = createPrivateKey({ key: config.clientAssertionSigningKey as string }); + const jwk = await exportJWK(privateKey); + jwks = { keys: [jwk] }; + } + + this.client = new issuer.Client( + { + client_id: config.clientID, + client_secret: config.clientSecret, + id_token_signed_response_alg: config.idTokenSigningAlg, + token_endpoint_auth_method: config.clientAuthMethod as ClientAuthMethod, + token_endpoint_auth_signing_alg: config.clientAssertionSigningAlg + }, + jwks + ); + applyHttpOptionsCustom(this.client); + + this.client[custom.clock_tolerance] = config.clockTolerance; + const issuerUrl = new URL(issuer.metadata.issuer); + + if (config.idpLogout) { + if ( + this.config.idpLogout && + (this.config.auth0Logout || (issuerUrl.hostname.match('\\.auth0\\.com$') && this.config.auth0Logout !== false)) + ) { + Object.defineProperty(this.client, 'endSessionUrl', { + value(params: EndSessionParameters) { + const { id_token_hint, post_logout_redirect_uri, ...extraParams } = params; + const parsedUrl = new URL(urlJoin(issuer.metadata.issuer, '/v2/logout')); + parsedUrl.searchParams.set('client_id', config.clientID); + post_logout_redirect_uri && parsedUrl.searchParams.set('returnTo', post_logout_redirect_uri); + Object.entries(extraParams).forEach(([key, value]) => { + if (value === null || value === undefined) { + return; + } + parsedUrl.searchParams.set(key, value as string); + }); + return parsedUrl.toString(); + } + }); + } else if (!issuer.end_session_endpoint) { + debug('the issuer does not support RP-Initiated Logout'); + } + } + + return this.client; + } + + async authorizationUrl(parameters: Record): Promise { + const client = await this.getClient(); + return client.authorizationUrl(parameters); + } + + async callbackParams(req: Auth0Request) { + const client = await this.getClient(); + const obj: CallbackParamsType = client.callbackParams({ + method: req.getMethod(), + url: req.getUrl(), + body: await req.getBody() + } as unknown as IncomingMessage); + return new URLSearchParams(obj); + } + + async callback( + redirectUri: string, + parameters: URLSearchParams, + checks: OpenIDCallbackChecks, + extras: CallbackExtras + ): Promise { + const params = Object.fromEntries(parameters.entries()); + const client = await this.getClient(); + try { + return await client.callback(redirectUri, params, checks, extras); + } catch (err) { + if (err instanceof errors.OPError) { + throw new IdentityProviderError(err); + } else if (err instanceof errors.RPError) { + throw new ApplicationError(err); + /* c8 ignore next 3 */ + } else { + throw new EscapedError(err.message); + } + } + } + + async endSessionUrl(parameters: EndSessionParameters): Promise { + const client = await this.getClient(); + return client.endSessionUrl(parameters); + } + + async userinfo(accessToken: string): Promise> { + const client = await this.getClient(); + try { + return await client.userinfo(accessToken); + } catch (e) { + throw new UserInfoError(e.message); + } + } + + async refresh(refreshToken: string, extras: { exchangeBody: Record }): Promise { + const client = await this.getClient(); + try { + return await client.refresh(refreshToken, extras); + } catch (e) { + throw new AccessTokenError( + AccessTokenErrorCode.FAILED_REFRESH_GRANT, + 'The request to refresh the access token failed.', + new IdentityProviderError(e as errors.OPError) + ); + } + } + + generateRandomCodeVerifier(): string { + return generators.codeVerifier(); + } + + generateRandomNonce(): string { + return generators.nonce(); + } + + calculateCodeChallenge(codeVerifier: string): string { + return generators.codeChallenge(codeVerifier); + } +} diff --git a/src/auth0-session/config.ts b/src/auth0-session/config.ts index bb2a847b7..1963d6125 100644 --- a/src/auth0-session/config.ts +++ b/src/auth0-session/config.ts @@ -1,4 +1,7 @@ -import type { AuthorizationParameters as OidcAuthorizationParameters, ClientAuthMethod } from 'openid-client'; +import type { + AuthorizationParameters as OidcAuthorizationParameters, + ClientAuthMethod +} from './client/abstract-client'; import { SessionStore } from './session/stateful-session'; /** @@ -172,8 +175,10 @@ export interface Config { * Private key for use with `private_key_jwt` clients. * This should be a string that is the contents of a PEM file. * you can also use the `AUTH0_CLIENT_ASSERTION_SIGNING_KEY` environment variable. + * + * For Edge runtime, you can also provide an instance of `CryptoKey`. */ - clientAssertionSigningKey?: string; + clientAssertionSigningKey?: string | CryptoKey; /** * The algorithm used to sign the client assertion JWT. diff --git a/src/auth0-session/handlers/callback.ts b/src/auth0-session/handlers/callback.ts index f4b5fbc55..441d679e8 100644 --- a/src/auth0-session/handlers/callback.ts +++ b/src/auth0-session/handlers/callback.ts @@ -1,20 +1,11 @@ -import type { IncomingMessage } from 'http'; import urlJoin from 'url-join'; -import createHttpError from 'http-errors'; -import { errors } from 'openid-client'; import { AuthorizationParameters, Config } from '../config'; -import { ClientFactory } from '../client'; import TransientStore from '../transient-store'; import { decodeState } from '../utils/encoding'; import { SessionCache } from '../session-cache'; -import { - ApplicationError, - EscapedError, - IdentityProviderError, - MissingStateCookieError, - MissingStateParamError -} from '../utils/errors'; +import { MissingStateCookieError, MissingStateParamError } from '../utils/errors'; import { Auth0Request, Auth0Response } from '../http'; +import { AbstractClient } from '../client/abstract-client'; function getRedirectUri(config: Config): string { return urlJoin(config.baseURL, config.routes.callback); @@ -30,38 +21,37 @@ export type CallbackOptions = { authorizationParams?: Partial; }; -type ValidState = { [key: string]: any; returnTo?: string }; - export type HandleCallback = (req: Auth0Request, res: Auth0Response, options?: CallbackOptions) => Promise; export default function callbackHandlerFactory( config: Config, - getClient: ClientFactory, + client: AbstractClient, sessionCache: SessionCache, transientCookieHandler: TransientStore ): HandleCallback { return async (req, res, options) => { - const client = await getClient(); const redirectUri = options?.redirectUri || getRedirectUri(config); - let tokenSet; - - const callbackParams = client.callbackParams({ - method: req.getMethod(), - url: req.getUrl(), - body: await req.getBody() - } as unknown as IncomingMessage); - - if (!callbackParams.state) { - throw createHttpError(404, new MissingStateParamError()); - } + let tokenResponse; const expectedState = await transientCookieHandler.read('state', req, res); - if (!expectedState) { - throw createHttpError(400, new MissingStateCookieError()); + throw new MissingStateCookieError(); } + let callbackParams: URLSearchParams; + try { + callbackParams = await client.callbackParams(req, expectedState); + } catch (err) { + err.status = 400; + err.statusCode = 400; + err.openIdState = decodeState(expectedState); + throw err; + } + + if (!callbackParams.get('state')) { + throw new MissingStateParamError(); + } const max_age = await transientCookieHandler.read('max_age', req, res); const code_verifier = await transientCookieHandler.read('code_verifier', req, res); const nonce = await transientCookieHandler.read('nonce', req, res); @@ -69,7 +59,7 @@ export default function callbackHandlerFactory( (await transientCookieHandler.read('response_type', req, res)) || config.authorizationParams.response_type; try { - tokenSet = await client.callback( + tokenResponse = await client.callback( redirectUri, callbackParams, { @@ -82,19 +72,14 @@ export default function callbackHandlerFactory( { exchangeBody: options?.authorizationParams } ); } catch (err) { - if (err instanceof errors.OPError) { - err = new IdentityProviderError(err); - } else if (err instanceof errors.RPError) { - err = new ApplicationError(err); - /* c8 ignore next 3 */ - } else { - err = new EscapedError(err.message); - } - throw createHttpError(400, err, { openIdState: decodeState(expectedState) }); + err.status = 400; + err.statusCode = 400; + err.openIdState = decodeState(expectedState); + throw err; } - const openidState: { returnTo?: string } = decodeState(expectedState as string) as ValidState; - let session = sessionCache.fromTokenSet(tokenSet); + const openidState: { returnTo?: string } = decodeState(expectedState as string)!; + let session = sessionCache.fromTokenEndpointResponse(tokenResponse); if (options?.afterCallback) { session = await options.afterCallback(session, openidState); diff --git a/src/auth0-session/handlers/login.ts b/src/auth0-session/handlers/login.ts index b30e8af80..fb5700f40 100644 --- a/src/auth0-session/handlers/login.ts +++ b/src/auth0-session/handlers/login.ts @@ -1,11 +1,10 @@ import urlJoin from 'url-join'; -import { strict as assert } from 'assert'; import { Config, LoginOptions } from '../config'; import TransientStore, { StoreOptions } from '../transient-store'; import { encodeState } from '../utils/encoding'; -import { ClientFactory } from '../client'; import createDebug from '../utils/debug'; import { Auth0Request, Auth0Response } from '../http'; +import { AbstractClient } from '../client/abstract-client'; const debug = createDebug('handlers'); @@ -17,12 +16,10 @@ export type HandleLogin = (req: Auth0Request, res: Auth0Response, options?: Logi export default function loginHandlerFactory( config: Config, - getClient: ClientFactory, + client: AbstractClient, transientHandler: TransientStore ): HandleLogin { return async (req, res, options = {}) => { - const client = await getClient(); - const returnTo = options.returnTo || config.baseURL; const opts = { @@ -38,7 +35,7 @@ export default function loginHandlerFactory( ...(opts.authorizationParams || {}) }; - const transientOpts: StoreOptions = { + const transientOpts: Pick = { sameSite: opts.authorizationParams.response_mode === 'form_post' ? 'none' : config.session.cookie.sameSite }; @@ -46,14 +43,14 @@ export default function loginHandlerFactory( if (typeof stateValue !== 'object') { throw new Error('Custom state value must be an object.'); } - stateValue.nonce = transientHandler.generateNonce(); + stateValue.nonce = client.generateRandomNonce(); stateValue.returnTo = stateValue.returnTo || opts.returnTo; const responseType = opts.authorizationParams.response_type as string; const usePKCE = responseType.includes('code'); if (usePKCE) { debug('response_type includes code, the authorization request will use PKCE'); - stateValue.code_verifier = transientHandler.generateCodeVerifier(); + stateValue.code_verifier = client.generateRandomCodeVerifier(); } if (responseType !== config.authorizationParams.response_type) { @@ -65,15 +62,18 @@ export default function loginHandlerFactory( const authParams = { ...opts.authorizationParams, - nonce: await transientHandler.save('nonce', req, res, transientOpts), + nonce: await transientHandler.save('nonce', req, res, { ...transientOpts, value: client.generateRandomNonce() }), state: await transientHandler.save('state', req, res, { ...transientOpts, value: encodeState(stateValue) }), ...(usePKCE ? { - code_challenge: transientHandler.calculateCodeChallenge( - await transientHandler.save('code_verifier', req, res, transientOpts) + code_challenge: await client.calculateCodeChallenge( + await transientHandler.save('code_verifier', req, res, { + ...transientOpts, + value: client.generateRandomCodeVerifier() + }) ), code_challenge_method: 'S256' } @@ -81,11 +81,12 @@ export default function loginHandlerFactory( }; const validResponseTypes = ['id_token', 'code id_token', 'code']; - assert( - validResponseTypes.includes(authParams.response_type as string), - `response_type should be one of ${validResponseTypes.join(', ')}` - ); - assert(/\bopenid\b/.test(authParams.scope as string), 'scope should contain "openid"'); + if (!validResponseTypes.includes(authParams.response_type as string)) { + throw new Error(`response_type should be one of ${validResponseTypes.join(', ')}`); + } + if (!/\bopenid\b/.test(authParams.scope as string)) { + throw new Error('scope should contain "openid"'); + } if (authParams.max_age) { await transientHandler.save('max_age', req, res, { @@ -94,7 +95,7 @@ export default function loginHandlerFactory( }); } - const authorizationUrl = client.authorizationUrl(authParams); + const authorizationUrl = await client.authorizationUrl(authParams); debug('redirecting to %s', authorizationUrl); res.redirect(authorizationUrl); diff --git a/src/auth0-session/handlers/logout.ts b/src/auth0-session/handlers/logout.ts index ec42bf131..b511b8317 100644 --- a/src/auth0-session/handlers/logout.ts +++ b/src/auth0-session/handlers/logout.ts @@ -1,10 +1,9 @@ -import url from 'url'; import urlJoin from 'url-join'; import createDebug from '../utils/debug'; import { Config, LogoutOptions } from '../config'; -import { ClientFactory } from '../client'; import { SessionCache } from '../session-cache'; import { Auth0Request, Auth0Response } from '../http'; +import { AbstractClient } from '../client/abstract-client'; const debug = createDebug('logout'); @@ -12,14 +11,16 @@ export type HandleLogout = (req: Auth0Request, res: Auth0Response, options?: Log export default function logoutHandlerFactory( config: Config, - getClient: ClientFactory, + client: AbstractClient, sessionCache: SessionCache ): HandleLogout { return async (req, res, options = {}) => { let returnURL = options.returnTo || config.routes.postLogoutRedirect; debug('logout() with return url: %s', returnURL); - if (url.parse(returnURL).host === null) { + try { + new URL(returnURL); + } catch (_) { returnURL = urlJoin(config.baseURL, returnURL); } @@ -39,8 +40,7 @@ export default function logoutHandlerFactory( return; } - const client = await getClient(); - returnURL = client.endSessionUrl({ + returnURL = await client.endSessionUrl({ ...options.logoutParams, post_logout_redirect_uri: returnURL, id_token_hint: idToken diff --git a/src/auth0-session/index.ts b/src/auth0-session/index.ts index d043b59ab..d1becc606 100644 --- a/src/auth0-session/index.ts +++ b/src/auth0-session/index.ts @@ -13,5 +13,5 @@ export { get as getConfig, ConfigParameters, DeepPartial } from './get-config'; export { default as loginHandler, HandleLogin } from './handlers/login'; export { default as logoutHandler, HandleLogout } from './handlers/logout'; export { default as callbackHandler, CallbackOptions, AfterCallback, HandleCallback } from './handlers/callback'; -export { default as clientFactory, ClientFactory } from './client'; +export { TokenEndpointResponse, AbstractClient } from './client/abstract-client'; export { SessionCache } from './session-cache'; diff --git a/src/auth0-session/session-cache.ts b/src/auth0-session/session-cache.ts index bfa971937..d59fd9068 100644 --- a/src/auth0-session/session-cache.ts +++ b/src/auth0-session/session-cache.ts @@ -1,9 +1,9 @@ -import type { TokenSet } from 'openid-client'; +import { TokenEndpointResponse } from './client/abstract-client'; export interface SessionCache { create(req: Req, res: Res, session: Session): Promise; delete(req: Req, res: Res): Promise; isAuthenticated(req: Req, res: Res): Promise; getIdToken(req: Req, res: Res): Promise; - fromTokenSet(tokenSet: TokenSet): Session; + fromTokenEndpointResponse(tokenSet: TokenEndpointResponse): Session; } diff --git a/src/auth0-session/transient-store.ts b/src/auth0-session/transient-store.ts index 8b7c7b8cf..0a70a327a 100644 --- a/src/auth0-session/transient-store.ts +++ b/src/auth0-session/transient-store.ts @@ -1,4 +1,3 @@ -import { generators } from 'openid-client'; import { generateCookieValue, getCookieValue } from './utils/signed-cookies'; import { signing } from './utils/hkdf'; import { Config } from './config'; @@ -6,7 +5,7 @@ import { Auth0Request, Auth0Response } from './http'; export interface StoreOptions { sameSite?: boolean | 'lax' | 'strict' | 'none'; - value?: string; + value: string; } export default class TransientStore { @@ -39,7 +38,7 @@ export default class TransientStore { key: string, _req: Auth0Request, res: Auth0Response, - { sameSite = 'none', value = this.generateNonce() }: StoreOptions + { sameSite = 'none', value }: StoreOptions ): Promise { const isSameSiteNone = sameSite === 'none'; const { domain, path, secure } = this.config.session.cookie; @@ -99,32 +98,4 @@ export default class TransientStore { return value; } - - /** - * Generates a `nonce` value. - * - * @return {String} - */ - generateNonce(): string { - return generators.nonce(); - } - - /** - * Generates a `code_verifier` value. - * - * @return {String} - */ - generateCodeVerifier(): string { - return generators.codeVerifier(); - } - - /** - * Calculates a `code_challenge` value for a given `codeVerifier`. - * - * @param {String} codeVerifier Code verifier to calculate the `code_challenge` value from. - * @return {String} - */ - calculateCodeChallenge(codeVerifier: string): string { - return generators.codeChallenge(codeVerifier); - } } diff --git a/src/auth0-session/utils/encoding.ts b/src/auth0-session/utils/encoding.ts index aa3354508..c4eeed5a8 100644 --- a/src/auth0-session/utils/encoding.ts +++ b/src/auth0-session/utils/encoding.ts @@ -1,5 +1,4 @@ import * as jose from 'jose'; -import { TextDecoder } from 'util'; /** * Prepare a state object to send. diff --git a/src/auth0-session/utils/errors.ts b/src/auth0-session/utils/errors.ts index 3bb531296..62c455a53 100644 --- a/src/auth0-session/utils/errors.ts +++ b/src/auth0-session/utils/errors.ts @@ -1,5 +1,3 @@ -import type { errors } from 'openid-client'; - export class EscapedError extends Error { /** * **WARNING** The message can contain user input and is only escaped using basic escaping for putting untrusted data @@ -14,6 +12,8 @@ export class EscapedError extends Error { export class MissingStateParamError extends Error { static message = 'Missing state parameter in Authorization Response.'; + status = 400; + statusCode = 400; constructor() { /* c8 ignore next */ @@ -24,6 +24,8 @@ export class MissingStateParamError extends Error { export class MissingStateCookieError extends Error { static message = 'Missing state cookie from login request (check login URL, callback URL and cookie config).'; + status = 400; + statusCode = 400; constructor() { /* c8 ignore next */ @@ -37,7 +39,7 @@ export class ApplicationError extends EscapedError { * **WARNING** The message can contain user input and is only escaped using basic escaping for putting untrusted data * directly into the HTML body */ - constructor(rpError: errors.RPError) { + constructor(rpError: Error) { /* c8 ignore next */ super(rpError.message); Object.setPrototypeOf(this, ApplicationError.prototype); @@ -62,7 +64,7 @@ export class IdentityProviderError extends EscapedError { * **WARNING** The message can contain user input and is only escaped using basic escaping for putting untrusted data * directly into the HTML body */ - constructor(rpError: errors.OPError) { + constructor(rpError: { message: string; error?: string; error_description?: string }) { /* c8 ignore next */ super(rpError.message); this.error = htmlSafe(rpError.error); @@ -79,6 +81,14 @@ export class DiscoveryError extends EscapedError { } } +export class UserInfoError extends EscapedError { + constructor(msg: string) { + /* c8 ignore next */ + super(`Userinfo request failing with: ${msg}`); + Object.setPrototypeOf(this, UserInfoError.prototype); + } +} + // eslint-disable-next-line max-len // Basic escaping for putting untrusted data directly into the HTML body, per: https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html#rule-1-html-encode-before-inserting-untrusted-data-into-html-element-content. export function htmlSafe(input?: string): string | undefined { diff --git a/src/config.ts b/src/config.ts index 231064ec5..90da18cde 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,5 +1,4 @@ -import type { AuthorizationParameters as OidcAuthorizationParameters } from 'openid-client'; -import type { LoginOptions } from './auth0-session/config'; +import type { LoginOptions, AuthorizationParameters as OidcAuthorizationParameters } from './auth0-session/config'; import { SessionStore } from './auth0-session/session/stateful-session'; import Session from './session/session'; import { DeepPartial, get as getBaseConfig } from './auth0-session/get-config'; @@ -180,8 +179,10 @@ export interface BaseConfig { * Private key for use with `private_key_jwt` clients. * This should be a string that is the contents of a PEM file. * You can also use the `AUTH0_CLIENT_ASSERTION_SIGNING_KEY` environment variable. + * + * For Edge runtime, you can also provide an instance of `CryptoKey`. */ - clientAssertionSigningKey?: string; + clientAssertionSigningKey?: string | CryptoKey; /** * The algorithm to sign the client assertion JWT. diff --git a/src/edge.ts b/src/edge.ts index 3ef179279..02447535d 100644 --- a/src/edge.ts +++ b/src/edge.ts @@ -1,24 +1,25 @@ -import { NextMiddleware, NextRequest, NextResponse } from 'next/server'; -import { StatelessSession } from './auth0-session/session/stateless-session'; -import { StatefulSession } from './auth0-session/session/stateful-session'; -import Session from './session/session'; -import SessionCache from './session/cache'; import { - WithMiddlewareAuthRequired, - default as withMiddlewareAuthRequiredFactory -} from './helpers/with-middleware-auth-required'; -import { getConfig, ConfigParameters } from './config'; + Auth0Server, + ConfigParameters, + GetAccessToken, + GetSession, + HandleAuth, + HandleCallback, + HandleLogin, + HandleLogout, + HandleProfile, + SessionCache, + UpdateSession, + WithApiAuthRequired, + WithPageAuthRequired, + telemetry +} from './shared'; +import { _initAuth } from './init'; import { setIsUsingNamedExports, setIsUsingOwnInstance } from './utils/instance-check'; - -export type Auth0Edge = { withMiddlewareAuthRequired: WithMiddlewareAuthRequired; getSession: GetSession }; - -export type GetSession = (req: NextRequest, res: NextResponse) => Promise; - -export type InitAuth0 = (params?: ConfigParameters) => Auth0Edge; - -export { WithMiddlewareAuthRequired }; - -let instance: Auth0Edge; +import { getConfig, getLoginUrl } from './config'; +import { withPageAuthRequiredFactory } from './helpers'; +import { EdgeClient } from './auth0-session/client/edge-client'; +import { WithMiddlewareAuthRequired } from './helpers/with-middleware-auth-required'; const genId = () => { const bytes = new Uint8Array(16); @@ -28,39 +29,55 @@ const genId = () => { .join(''); }; -function getInstance(params?: ConfigParameters): Auth0Edge { +let instance: Auth0Server & { sessionCache: SessionCache }; + +/** + * Initialise your own instance of the SDK. + * + * See {@link ConfigParameters}. + * + * @category Server + */ +export type InitAuth0 = (params?: ConfigParameters) => Auth0Server; + +// For using managed instance with named exports. +function getInstance(): Auth0Server & { sessionCache: SessionCache } { setIsUsingNamedExports(); if (instance) { return instance; } - instance = _initAuth0(params); + const { baseConfig, nextConfig } = getConfig({ session: { genId } }); + const client = new EdgeClient(baseConfig, telemetry); + instance = _initAuth({ baseConfig, nextConfig, client }); return instance; } -export const initAuth0: InitAuth0 = (params?) => { +// For creating own instance. +export const initAuth0: InitAuth0 = (params) => { setIsUsingOwnInstance(); - return _initAuth0(params); -}; - -const _initAuth0: InitAuth0 = (params?) => { const { baseConfig, nextConfig } = getConfig({ ...params, session: { genId, ...params?.session } }); - - // Init base layer (with base config) - const sessionStore = baseConfig.session.store - ? new StatefulSession(baseConfig) - : new StatelessSession(baseConfig); - const sessionCache = new SessionCache(baseConfig, sessionStore); - - // Init Next layer (with next config) - const getSession: GetSession = (req, res) => sessionCache.get(req, res); - const withMiddlewareAuthRequired = withMiddlewareAuthRequiredFactory(nextConfig.routes, () => sessionCache); - - return { - getSession, - withMiddlewareAuthRequired - }; + const client = new EdgeClient(baseConfig, telemetry); + const { sessionCache, ...publicApi } = _initAuth({ baseConfig, nextConfig, client }); + return publicApi; }; +const getSessionCache = () => getInstance().sessionCache; export const getSession: GetSession = (...args) => getInstance().getSession(...args); -export const withMiddlewareAuthRequired: WithMiddlewareAuthRequired = (middleware?: NextMiddleware) => - getInstance().withMiddlewareAuthRequired(middleware); +export const updateSession: UpdateSession = (...args) => getInstance().updateSession(...args); +export const getAccessToken: GetAccessToken = (...args) => getInstance().getAccessToken(...args); +export const withApiAuthRequired: WithApiAuthRequired = (...args) => + (getInstance().withApiAuthRequired as any)(...args); +export const withPageAuthRequired: WithPageAuthRequired = withPageAuthRequiredFactory(getLoginUrl(), getSessionCache); +export const handleLogin: HandleLogin = ((...args: Parameters) => + getInstance().handleLogin(...args)) as HandleLogin; +export const handleLogout: HandleLogout = ((...args: Parameters) => + getInstance().handleLogout(...args)) as HandleLogout; +export const handleCallback: HandleCallback = ((...args: Parameters) => + getInstance().handleCallback(...args)) as HandleCallback; +export const handleProfile: HandleProfile = ((...args: Parameters) => + getInstance().handleProfile(...args)) as HandleProfile; +export const handleAuth: HandleAuth = (...args) => getInstance().handleAuth(...args); +export const withMiddlewareAuthRequired: WithMiddlewareAuthRequired = (...args) => + getInstance().withMiddlewareAuthRequired(...args); + +export * from './shared'; diff --git a/src/handlers/callback.ts b/src/handlers/callback.ts index 8a462b631..54a587717 100644 --- a/src/handlers/callback.ts +++ b/src/handlers/callback.ts @@ -1,4 +1,3 @@ -import { strict as assert } from 'assert'; import { NextApiResponse, NextApiRequest } from 'next'; import { NextRequest, NextResponse } from 'next/server'; import { @@ -297,13 +296,15 @@ const applyOptions = ( (afterCallback?: AfterCallback, organization?: string): BaseAfterCallback => (session, state) => { if (organization) { - assert(session.user.org_id, 'Organization Id (org_id) claim must be a string present in the ID token'); - assert.equal( - session.user.org_id, - organization, - `Organization Id (org_id) claim value mismatch in the ID token; ` + - `expected "${organization}", found "${session.user.org_id}"` - ); + if (!session.user.org_id) { + throw new Error('Organization Id (org_id) claim must be a string present in the ID token'); + } + if (session.user.org_id !== organization) { + throw new Error( + `Organization Id (org_id) claim value mismatch in the ID token; ` + + `expected "${organization}", found "${session.user.org_id}"` + ); + } } if (afterCallback) { if (res) { diff --git a/src/handlers/logout.ts b/src/handlers/logout.ts index a6fbfb0bb..517382e11 100644 --- a/src/handlers/logout.ts +++ b/src/handlers/logout.ts @@ -1,10 +1,10 @@ import { NextApiResponse, NextApiRequest } from 'next'; +import { NextRequest, NextResponse } from 'next/server'; import { HandleLogin as BaseHandleLogin, HandleLogout as BaseHandleLogout } from '../auth0-session'; import { assertReqRes } from '../utils/assert'; import { HandlerErrorCause, LogoutHandlerError } from '../utils/errors'; import { Auth0NextApiRequest, Auth0NextApiResponse, Auth0NextRequest, Auth0NextResponse } from '../http'; import { BaseConfig } from '../config'; -import { NextRequest, NextResponse } from 'next/server'; import { AppRouteHandlerFnContext, AuthHandler, Handler, getHandler, OptionsProvider } from './router-helpers'; /** diff --git a/src/handlers/profile.ts b/src/handlers/profile.ts index cf65af102..3d12d80ce 100644 --- a/src/handlers/profile.ts +++ b/src/handlers/profile.ts @@ -1,6 +1,6 @@ import { NextApiResponse, NextApiRequest } from 'next'; import { NextRequest, NextResponse } from 'next/server'; -import { ClientFactory } from '../auth0-session'; +import { AbstractClient } from '../auth0-session'; import { SessionCache, Session, fromJson, GetAccessToken } from '../session'; import { assertReqRes } from '../utils/assert'; import { ProfileHandlerError, HandlerErrorCause } from '../utils/errors'; @@ -124,12 +124,12 @@ export type ProfileHandler = Handler; * @ignore */ export default function profileHandler( - getClient: ClientFactory, + client: AbstractClient, getAccessToken: GetAccessToken, sessionCache: SessionCache ): HandleProfile { - const appRouteHandler = appRouteHandlerFactory(getClient, getAccessToken, sessionCache); - const pageRouteHandler = pageRouteHandlerFactory(getClient, getAccessToken, sessionCache); + const appRouteHandler = appRouteHandlerFactory(client, getAccessToken, sessionCache); + const pageRouteHandler = pageRouteHandlerFactory(client, getAccessToken, sessionCache); return getHandler(appRouteHandler, pageRouteHandler) as HandleProfile; } @@ -138,11 +138,11 @@ export default function profileHandler( * @ignore */ const appRouteHandlerFactory: ( - getClient: ClientFactory, + client: AbstractClient, getAccessToken: GetAccessToken, sessionCache: SessionCache ) => (req: NextRequest, ctx: AppRouteHandlerFnContext, options?: ProfileOptions) => Promise | Response = - (getClient, getAccessToken, sessionCache) => + (client, getAccessToken, sessionCache) => async (req, _ctx, options = {}) => { try { const res = new NextResponse(); @@ -160,7 +160,6 @@ const appRouteHandlerFactory: ( throw new Error('No access token available to refetch the profile'); } - const client = await getClient(); const userInfo = await client.userinfo(accessToken); let newSession = fromJson({ @@ -190,11 +189,11 @@ const appRouteHandlerFactory: ( * @ignore */ const pageRouteHandlerFactory: ( - getClient: ClientFactory, + client: AbstractClient, getAccessToken: GetAccessToken, sessionCache: SessionCache ) => (req: NextApiRequest, res: NextApiResponse, options?: ProfileOptions) => Promise = - (getClient, getAccessToken, sessionCache) => + (client, getAccessToken, sessionCache) => async (req: NextApiRequest, res: NextApiResponse, options = {}): Promise => { try { assertReqRes(req, res); @@ -213,7 +212,6 @@ const pageRouteHandlerFactory: ( throw new Error('No access token available to refetch the profile'); } - const client = await getClient(); const userInfo = await client.userinfo(accessToken); let newSession = fromJson({ diff --git a/src/helpers/with-middleware-auth-required.ts b/src/helpers/with-middleware-auth-required.ts index a642f8600..005242314 100644 --- a/src/helpers/with-middleware-auth-required.ts +++ b/src/helpers/with-middleware-auth-required.ts @@ -83,7 +83,13 @@ export default function withMiddlewareAuthRequiredFactory( if (res) { const nextRes = new NextResponse(res.body, res); - for (const cookie of authRes.cookies.getAll()) { + let cookies = authRes.cookies.getAll(); + if ('cookies' in res) { + for (const cookie of res.cookies.getAll()) { + nextRes.cookies.set(cookie); + } + } + for (const cookie of cookies) { if (!nextRes.cookies.get(cookie.name)) { nextRes.cookies.set(cookie); } diff --git a/src/http/auth0-next-response.ts b/src/http/auth0-next-response.ts index c70772ace..cb037b0ec 100644 --- a/src/http/auth0-next-response.ts +++ b/src/http/auth0-next-response.ts @@ -17,14 +17,14 @@ export default class Auth0NextResponse extends Auth0Response { } public redirect(location: string, status = 302): void { - const headers = new Headers({ location }); - this.res.headers.forEach((value, key) => { - if (headers.has(key)) { - headers.append(key, value); - } else { - headers.set(key, value); - } + const oldRes = this.res; + this.res = new NextResponse(null, { status }); + oldRes.headers.forEach((value, key) => { + this.res.headers.set(key, value); }); - this.res = new NextResponse(null, { ...this.res, status, headers }); + this.res.headers.set('location', location); + for (const cookie of oldRes.cookies.getAll()) { + this.res.cookies.set(cookie); + } } } diff --git a/src/index.ts b/src/index.ts index cfe0994ae..221ba3022 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,114 +1,31 @@ import crypto from 'crypto'; import { - StatelessSession, - StatefulSession, - SessionStore as GenericSessionStore, - SessionPayload, - TransientStore, - clientFactory, - loginHandler as baseLoginHandler, - logoutHandler as baseLogoutHandler, - callbackHandler as baseCallbackHandler -} from './auth0-session'; -import { - handlerFactory, - callbackHandler, - loginHandler, - logoutHandler, - profileHandler, + Auth0Server as Auth0ServerShared, + ConfigParameters, + GetAccessToken, + GetSession, HandleAuth, + HandleCallback, HandleLogin, - HandleProfile, HandleLogout, - HandleCallback -} from './handlers'; -import { - sessionFactory, - accessTokenFactory, + HandleProfile, SessionCache, - GetSession, - GetAccessToken, - Session, - touchSessionFactory, - TouchSession, - updateSessionFactory, - UpdateSession -} from './session/'; -import { - withPageAuthRequiredFactory, - withApiAuthRequiredFactory, + UpdateSession, WithApiAuthRequired, - WithPageAuthRequired -} from './helpers'; -import version from './version'; -import { getConfig, getLoginUrl, ConfigParameters } from './config'; + WithPageAuthRequired, + telemetry +} from './shared'; +import { _initAuth } from './init'; import { setIsUsingNamedExports, setIsUsingOwnInstance } from './utils/instance-check'; +import { getConfig, getLoginUrl } from './config'; +import { withPageAuthRequiredFactory } from './helpers'; +import { NodeClient } from './auth0-session/client/node-client'; -/** - * The SDK server instance. - * - * This is created for you when you use the named exports, or you can create your own using {@link InitAuth0}. - * - * See {@link ConfigParameters} for more info. - * - * @category Server - */ -export interface Auth0Server { - /** - * Session getter. - */ - getSession: GetSession; - - /** - * Update the expiry of a rolling session when autoSave is disabled. - */ - touchSession: TouchSession; - - /** - * Append properties to the user. - */ - updateSession: UpdateSession; - - /** - * Access token getter. - */ - getAccessToken: GetAccessToken; - - /** - * Login handler which will redirect the user to Auth0. - */ - handleLogin: HandleLogin; - - /** - * Callback handler which will complete the transaction and create a local session. - */ - handleCallback: HandleCallback; - - /** - * Logout handler which will clear the local session and the Auth0 session. - */ - handleLogout: HandleLogout; - - /** - * Profile handler which return profile information about the user. - */ - handleProfile: HandleProfile; - - /** - * Helper that adds auth to an API route. - */ - withApiAuthRequired: WithApiAuthRequired; +const genId = () => crypto.randomBytes(16).toString('hex'); - /** - * Helper that adds auth to a Page route. - */ - withPageAuthRequired: WithPageAuthRequired; +export type Auth0Server = Omit; - /** - * Create the main handlers for your api routes. - */ - handleAuth: HandleAuth; -} +let instance: Auth0ServerShared & { sessionCache: SessionCache }; /** * Initialise your own instance of the SDK. @@ -117,74 +34,29 @@ export interface Auth0Server { * * @category Server */ -export type InitAuth0 = (params?: ConfigParameters) => Auth0Server; - -let instance: Auth0Server & { sessionCache: SessionCache }; - -const genId = () => crypto.randomBytes(16).toString('hex'); +export type InitAuth0 = (params?: ConfigParameters) => Omit; // For using managed instance with named exports. -function getInstance(): Auth0Server & { sessionCache: SessionCache } { +function getInstance(): Auth0ServerShared & { sessionCache: SessionCache } { setIsUsingNamedExports(); if (instance) { return instance; } - instance = _initAuth(); + const { baseConfig, nextConfig } = getConfig({ session: { genId } }); + const client = new NodeClient(baseConfig, telemetry); + instance = _initAuth({ baseConfig, nextConfig, client }); return instance; } // For creating own instance. export const initAuth0: InitAuth0 = (params) => { setIsUsingOwnInstance(); - const { sessionCache, ...publicApi } = _initAuth(params); // eslint-disable-line @typescript-eslint/no-unused-vars - return publicApi; -}; - -export const _initAuth = (params?: ConfigParameters): Auth0Server & { sessionCache: SessionCache } => { const { baseConfig, nextConfig } = getConfig({ ...params, session: { genId, ...params?.session } }); - - // Init base layer (with base config) - const getClient = clientFactory(baseConfig, { name: 'nextjs-auth0', version }); - const transientStore = new TransientStore(baseConfig); - - const sessionStore = baseConfig.session.store - ? new StatefulSession(baseConfig) - : new StatelessSession(baseConfig); - const sessionCache = new SessionCache(baseConfig, sessionStore); - const baseHandleLogin = baseLoginHandler(baseConfig, getClient, transientStore); - const baseHandleLogout = baseLogoutHandler(baseConfig, getClient, sessionCache); - const baseHandleCallback = baseCallbackHandler(baseConfig, getClient, sessionCache, transientStore); - - // Init Next layer (with next config) - const getSession = sessionFactory(sessionCache); - const touchSession = touchSessionFactory(sessionCache); - const updateSession = updateSessionFactory(sessionCache); - const getAccessToken = accessTokenFactory(nextConfig, getClient, sessionCache); - const withApiAuthRequired = withApiAuthRequiredFactory(sessionCache); - const withPageAuthRequired = withPageAuthRequiredFactory(nextConfig.routes.login, () => sessionCache); - const handleLogin = loginHandler(baseHandleLogin, nextConfig, baseConfig); - const handleLogout = logoutHandler(baseHandleLogout); - const handleCallback = callbackHandler(baseHandleCallback, nextConfig); - const handleProfile = profileHandler(getClient, getAccessToken, sessionCache); - const handleAuth = handlerFactory({ handleLogin, handleLogout, handleCallback, handleProfile }); - - return { - sessionCache, - getSession, - touchSession, - updateSession, - getAccessToken, - withApiAuthRequired, - withPageAuthRequired, - handleLogin, - handleLogout, - handleCallback, - handleProfile, - handleAuth - }; + const client = new NodeClient(baseConfig, telemetry); + const { sessionCache, withMiddlewareAuthRequired, ...publicApi } = _initAuth({ baseConfig, nextConfig, client }); + return publicApi; }; -/* c8 ignore start */ const getSessionCache = () => getInstance().sessionCache; export const getSession: GetSession = (...args) => getInstance().getSession(...args); export const updateSession: UpdateSession = (...args) => getInstance().updateSession(...args); @@ -202,83 +74,4 @@ export const handleProfile: HandleProfile = ((...args: Parameters getInstance().handleProfile(...args)) as HandleProfile; export const handleAuth: HandleAuth = (...args) => getInstance().handleAuth(...args); -export { - AuthError, - AccessTokenErrorCode, - AccessTokenError, - HandlerError, - CallbackHandlerError, - LoginHandlerError, - LogoutHandlerError, - ProfileHandlerError -} from './utils/errors'; - -export { - Handlers, - LoginOptions, - LogoutOptions, - GetLoginState, - GetLoginStatePageRoute, - GetLoginStateAppRoute, - ProfileOptions, - CallbackOptions, - AfterCallback, - AfterCallbackPageRoute, - AfterCallbackAppRoute, - AfterRefetch, - AfterRefetchPageRoute, - AfterRefetchAppRoute, - AppRouterOnError, - PageRouterOnError -} from './handlers'; - -export { - AppRouterPageRouteOpts, - AppRouterPageRoute, - WithPageAuthRequiredPageRouter, - WithPageAuthRequiredAppRouter, - GetServerSidePropsResultWithSession, - WithPageAuthRequiredPageRouterOptions, - WithPageAuthRequiredAppRouterOptions, - PageRoute, - AppRouteHandlerFn, - WithApiAuthRequiredAppRoute, - WithApiAuthRequiredPageRoute -} from './helpers'; - -export { - AccessTokenRequest, - GetAccessTokenResult, - Claims, - AfterRefresh, - AfterRefreshPageRoute, - AfterRefreshAppRoute -} from './session'; - -export { - MissingStateCookieError, - MissingStateParamError, - IdentityProviderError, - ApplicationError -} from './auth0-session'; - -export { - ConfigParameters, - HandleAuth, - HandleLogin, - HandleProfile, - HandleLogout, - HandleCallback, - WithApiAuthRequired, - WithPageAuthRequired, - SessionCache, - GetSession, - TouchSession, - UpdateSession, - GetAccessToken, - Session -}; - -export type SessionStore = GenericSessionStore; -export type SessionStorePayload = SessionPayload; -/* c8 ignore stop */ +export * from './shared'; diff --git a/src/init.ts b/src/init.ts new file mode 100644 index 000000000..73cb5779f --- /dev/null +++ b/src/init.ts @@ -0,0 +1,84 @@ +import { + StatelessSession, + StatefulSession, + TransientStore, + loginHandler as baseLoginHandler, + logoutHandler as baseLogoutHandler, + callbackHandler as baseCallbackHandler, + AbstractClient +} from './auth0-session'; +import { handlerFactory, callbackHandler, loginHandler, logoutHandler, profileHandler } from './handlers'; +import { + sessionFactory, + accessTokenFactory, + SessionCache, + Session, + touchSessionFactory, + updateSessionFactory +} from './session/'; +import { withPageAuthRequiredFactory, withApiAuthRequiredFactory } from './helpers'; +import { ConfigParameters, BaseConfig, NextConfig } from './config'; +import { Auth0Server } from './shared'; +import withMiddlewareAuthRequiredFactory from './helpers/with-middleware-auth-required'; + +/** + * Initialise your own instance of the SDK. + * + * See {@link ConfigParameters}. + * + * @category Server + */ +export type InitAuth0 = (params?: ConfigParameters) => Auth0Server; + +export const _initAuth = ({ + baseConfig, + nextConfig, + client +}: { + baseConfig: BaseConfig; + nextConfig: NextConfig; + client: AbstractClient; +}): Auth0Server & { + sessionCache: SessionCache; +} => { + // Init base layer (with base config) + const transientStore = new TransientStore(baseConfig); + + const sessionStore = baseConfig.session.store + ? new StatefulSession(baseConfig) + : new StatelessSession(baseConfig); + const sessionCache = new SessionCache(baseConfig, sessionStore); + const baseHandleLogin = baseLoginHandler(baseConfig, client, transientStore); + const baseHandleLogout = baseLogoutHandler(baseConfig, client, sessionCache); + const baseHandleCallback = baseCallbackHandler(baseConfig, client, sessionCache, transientStore); + + // Init Next layer (with next config) + const getSession = sessionFactory(sessionCache); + const touchSession = touchSessionFactory(sessionCache); + const updateSession = updateSessionFactory(sessionCache); + const getAccessToken = accessTokenFactory(nextConfig, client, sessionCache); + const withApiAuthRequired = withApiAuthRequiredFactory(sessionCache); + const withPageAuthRequired = withPageAuthRequiredFactory(nextConfig.routes.login, () => sessionCache); + const handleLogin = loginHandler(baseHandleLogin, nextConfig, baseConfig); + const handleLogout = logoutHandler(baseHandleLogout); + const handleCallback = callbackHandler(baseHandleCallback, nextConfig); + const handleProfile = profileHandler(client, getAccessToken, sessionCache); + const handleAuth = handlerFactory({ handleLogin, handleLogout, handleCallback, handleProfile }); + const withMiddlewareAuthRequired = withMiddlewareAuthRequiredFactory(nextConfig.routes, () => sessionCache); + + return { + sessionCache, + getSession, + touchSession, + updateSession, + getAccessToken, + withApiAuthRequired, + withPageAuthRequired, + handleLogin, + handleLogout, + handleCallback, + handleProfile, + handleAuth, + withMiddlewareAuthRequired + }; +}; diff --git a/src/session/cache.ts b/src/session/cache.ts index 6bbc4f40c..4c7ac7c77 100644 --- a/src/session/cache.ts +++ b/src/session/cache.ts @@ -1,10 +1,10 @@ import { IncomingMessage, ServerResponse } from 'http'; import { NextApiRequest, NextApiResponse } from 'next'; import { NextRequest, NextResponse } from 'next/server'; -import type { TokenSet } from 'openid-client'; +import type { TokenEndpointResponse } from '../auth0-session'; import { Config, SessionCache as ISessionCache, AbstractSession } from '../auth0-session'; -import Session, { fromJson, fromTokenSet } from './session'; -import { NodeRequest, NodeResponse } from '../auth0-session/http'; +import Session, { fromJson, fromTokenEndpointResponse } from './session'; +import { Auth0Request, Auth0Response, NodeRequest, NodeResponse } from '../auth0-session/http'; import { Auth0NextApiRequest, Auth0NextApiResponse, @@ -18,24 +18,14 @@ import { isNextApiRequest, isRequest } from '../utils/req-helpers'; type Req = IncomingMessage | NextRequest | NextApiRequest; type Res = ServerResponse | NextResponse | NextApiResponse; -const getAuth0Req = (req: Req) => { +const getAuth0ReqRes = (req: Req, res: Res): [Auth0Request, Auth0Response] => { if (isRequest(req)) { - return new Auth0NextRequest(req as NextRequest); + return [new Auth0NextRequest(req as NextRequest), new Auth0NextResponse(res as NextResponse)]; } if (isNextApiRequest(req)) { - return new Auth0NextApiRequest(req as NextApiRequest); + return [new Auth0NextApiRequest(req as NextApiRequest), new Auth0NextApiResponse(res as NextApiResponse)]; } - return new NodeRequest(req as IncomingMessage); -}; - -const getAuth0Res = (res: Res) => { - if (typeof Response !== undefined && res instanceof Response) { - return new Auth0NextResponse(res); - } - if ('setPreviewData' in res) { - return new Auth0NextApiResponse(res); - } - return new NodeResponse(res as ServerResponse); + return [new NodeRequest(req as IncomingMessage), new NodeResponse(res as ServerResponse)]; }; export default class SessionCache implements ISessionCache { @@ -49,7 +39,8 @@ export default class SessionCache implements ISessionCache { private async init(req: Req, res: Res, autoSave = true): Promise { if (!this.cache.has(req)) { - const [json, iat] = await this.sessionStore.read(getAuth0Req(req)); + const [auth0Req] = getAuth0ReqRes(req, res); + const [json, iat] = await this.sessionStore.read(auth0Req); this.iatCache.set(req, iat); this.cache.set(req, fromJson(json)); if (this.config.session.rolling && this.config.session.autoSave && autoSave) { @@ -59,7 +50,8 @@ export default class SessionCache implements ISessionCache { } async save(req: Req, res: Res): Promise { - await this.sessionStore.save(getAuth0Req(req), getAuth0Res(res), this.cache.get(req), this.iatCache.get(req)); + const [auth0Req, auth0Res] = getAuth0ReqRes(req, res); + await this.sessionStore.save(auth0Req, auth0Res, this.cache.get(req), this.iatCache.get(req)); } async create(req: Req, res: Res, session: Session): Promise { @@ -96,8 +88,8 @@ export default class SessionCache implements ISessionCache { return this.cache.get(req); } - fromTokenSet(tokenSet: TokenSet): Session { - return fromTokenSet(tokenSet, this.config); + fromTokenEndpointResponse(tokenSet: TokenEndpointResponse): Session { + return fromTokenEndpointResponse(tokenSet, this.config); } } diff --git a/src/session/get-access-token.ts b/src/session/get-access-token.ts index f02f371b5..a25c85d96 100644 --- a/src/session/get-access-token.ts +++ b/src/session/get-access-token.ts @@ -1,10 +1,9 @@ import { IncomingMessage, ServerResponse } from 'http'; import { NextApiRequest, NextApiResponse } from 'next'; -import type { errors } from 'openid-client'; -import { ClientFactory, IdentityProviderError } from '../auth0-session'; +import { AbstractClient } from '../auth0-session'; import { AccessTokenError, AccessTokenErrorCode } from '../utils/errors'; import { intersect, match } from '../utils/array'; -import { Session, SessionCache, fromTokenSet, get, set } from '../session'; +import { Session, SessionCache, fromTokenEndpointResponse, get, set } from '../session'; import { AuthorizationParameters, NextConfig } from '../config'; import { NextRequest, NextResponse } from 'next/server'; @@ -120,7 +119,7 @@ export type GetAccessToken = ( */ export default function accessTokenFactory( config: NextConfig, - getClient: ClientFactory, + client: AbstractClient, sessionCache: SessionCache ): GetAccessToken { return async (reqOrOpts?, res?, accessTokenRequest?): Promise => { @@ -192,22 +191,12 @@ export default function accessTokenFactory( (session.refreshToken && session.accessTokenExpiresAt * 1000 - 60000 < Date.now()) || (session.refreshToken && options && options.refresh) ) { - const client = await getClient(); - let tokenSet; - try { - tokenSet = await client.refresh(session.refreshToken, { - exchangeBody: options?.authorizationParams - }); - } catch (e) { - throw new AccessTokenError( - AccessTokenErrorCode.FAILED_REFRESH_GRANT, - 'The request to refresh the access token failed.', - new IdentityProviderError(e as errors.OPError) - ); - } + const tokenSet = await client.refresh(session.refreshToken, { + exchangeBody: options?.authorizationParams + }); // Update the session. - const newSession = fromTokenSet(tokenSet, config); + const newSession = fromTokenEndpointResponse(tokenSet, config); Object.assign(session, { ...newSession, refreshToken: newSession.refreshToken || session.refreshToken, diff --git a/src/session/index.ts b/src/session/index.ts index c18849590..694e25462 100644 --- a/src/session/index.ts +++ b/src/session/index.ts @@ -1,4 +1,4 @@ -export { default as Session, Claims, fromJson, fromTokenSet } from './session'; +export { default as Session, Claims, fromJson, fromTokenEndpointResponse } from './session'; export { default as sessionFactory, GetSession } from './get-session'; export { default as accessTokenFactory, diff --git a/src/session/session.ts b/src/session/session.ts index c5d98c584..057334952 100644 --- a/src/session/session.ts +++ b/src/session/session.ts @@ -1,4 +1,5 @@ -import type { TokenSet } from 'openid-client'; +import * as jose from 'jose'; +import type { TokenEndpointResponse } from '../auth0-session/client/abstract-client'; import { Config } from '../auth0-session'; import { NextConfig } from '../config'; @@ -60,14 +61,17 @@ export default class Session { /** * @ignore */ -export function fromTokenSet(tokenSet: TokenSet, config: Config | NextConfig): Session { +export function fromTokenEndpointResponse( + tokenEndpointResponse: TokenEndpointResponse, + config: Config | NextConfig +): Session { // Get the claims without any OIDC-specific claim. - const claims = tokenSet.claims(); + const claims = jose.decodeJwt(tokenEndpointResponse.id_token as string); config.identityClaimFilter.forEach((claim) => { delete claims[claim]; }); - const { id_token, access_token, scope, expires_at, refresh_token, ...remainder } = tokenSet; + const { id_token, access_token, scope, expires_in, expires_at, refresh_token, ...remainder } = tokenEndpointResponse; const storeIDToken = config.session.storeIDToken; return Object.assign( @@ -75,7 +79,7 @@ export function fromTokenSet(tokenSet: TokenSet, config: Config | NextConfig): S { accessToken: access_token, accessTokenScope: scope, - accessTokenExpiresAt: expires_at, + accessTokenExpiresAt: Math.floor(Date.now() / 1000) + Number(expires_in), refreshToken: refresh_token, ...(storeIDToken && { idToken: id_token }) }, diff --git a/src/shared.ts b/src/shared.ts new file mode 100644 index 000000000..2bf7aa76a --- /dev/null +++ b/src/shared.ts @@ -0,0 +1,160 @@ +import { SessionStore as GenericSessionStore, SessionPayload } from './auth0-session'; +import { HandleAuth, HandleLogin, HandleProfile, HandleLogout, HandleCallback } from './handlers'; +import { SessionCache, GetSession, GetAccessToken, Session, TouchSession, UpdateSession } from './session/'; +import { WithApiAuthRequired, WithPageAuthRequired } from './helpers'; +import { ConfigParameters } from './config'; +import { WithMiddlewareAuthRequired } from './helpers/with-middleware-auth-required'; +import version from './version'; + +export const telemetry = { name: 'nextjs-auth0', version }; + +/** + * The SDK server instance. + * + * This is created for you when you use the named exports, or you can create your own using {@link InitAuth0}. + * + * See {@link ConfigParameters} for more info. + * + * @category Server + */ +export interface Auth0Server { + /** + * Session getter. + */ + getSession: GetSession; + + /** + * Update the expiry of a rolling session when autoSave is disabled. + */ + touchSession: TouchSession; + + /** + * Append properties to the user. + */ + updateSession: UpdateSession; + + /** + * Access token getter. + */ + getAccessToken: GetAccessToken; + + /** + * Login handler which will redirect the user to Auth0. + */ + handleLogin: HandleLogin; + + /** + * Callback handler which will complete the transaction and create a local session. + */ + handleCallback: HandleCallback; + + /** + * Logout handler which will clear the local session and the Auth0 session. + */ + handleLogout: HandleLogout; + + /** + * Profile handler which return profile information about the user. + */ + handleProfile: HandleProfile; + + /** + * Helper that adds auth to an API route. + */ + withApiAuthRequired: WithApiAuthRequired; + + /** + * Helper that adds auth to a Page route. + */ + withPageAuthRequired: WithPageAuthRequired; + + /** + * Create the main handlers for your api routes. + */ + handleAuth: HandleAuth; + + /** + * Add auth to your middleware functions. + */ + withMiddlewareAuthRequired: WithMiddlewareAuthRequired; +} + +export { + AuthError, + AccessTokenErrorCode, + AccessTokenError, + HandlerError, + CallbackHandlerError, + LoginHandlerError, + LogoutHandlerError, + ProfileHandlerError +} from './utils/errors'; + +export { + Handlers, + LoginOptions, + LogoutOptions, + GetLoginState, + GetLoginStatePageRoute, + GetLoginStateAppRoute, + ProfileOptions, + CallbackOptions, + AfterCallback, + AfterCallbackPageRoute, + AfterCallbackAppRoute, + AfterRefetch, + AfterRefetchPageRoute, + AfterRefetchAppRoute, + AppRouterOnError, + PageRouterOnError +} from './handlers'; + +export { + AppRouterPageRouteOpts, + AppRouterPageRoute, + WithPageAuthRequiredPageRouter, + WithPageAuthRequiredAppRouter, + GetServerSidePropsResultWithSession, + WithPageAuthRequiredPageRouterOptions, + WithPageAuthRequiredAppRouterOptions, + PageRoute, + AppRouteHandlerFn, + WithApiAuthRequiredAppRoute, + WithApiAuthRequiredPageRoute +} from './helpers'; + +export { + AccessTokenRequest, + GetAccessTokenResult, + Claims, + AfterRefresh, + AfterRefreshPageRoute, + AfterRefreshAppRoute +} from './session'; + +export { + MissingStateCookieError, + MissingStateParamError, + IdentityProviderError, + ApplicationError +} from './auth0-session'; + +export { + ConfigParameters, + HandleAuth, + HandleLogin, + HandleProfile, + HandleLogout, + HandleCallback, + WithApiAuthRequired, + WithPageAuthRequired, + SessionCache, + GetSession, + TouchSession, + UpdateSession, + GetAccessToken, + Session +}; + +export type SessionStore = GenericSessionStore; +export type SessionStorePayload = SessionPayload; diff --git a/src/utils/errors.ts b/src/utils/errors.ts index cc7aca6dd..fd2bc53ab 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,5 +1,3 @@ -import { HttpError } from 'http-errors'; - /** * @ignore */ @@ -107,6 +105,14 @@ export class AccessTokenError extends AuthError { } } +/** + * @ignore + */ +interface HttpError extends Error { + status: number; + statusCode: number; +} + /** * @ignore */ diff --git a/src/utils/req-helpers.ts b/src/utils/req-helpers.ts index 90bdf52e4..c5b55c8dc 100644 --- a/src/utils/req-helpers.ts +++ b/src/utils/req-helpers.ts @@ -5,7 +5,7 @@ import { NextRequest } from 'next/server'; type Req = IncomingMessage | NextApiRequest | NextRequest | Request | Record; export const isRequest = (req: Req): boolean => { - return req instanceof Request || req.headers instanceof Headers; + return req instanceof Request || req.headers instanceof Headers || typeof (req as Request).bodyUsed === 'boolean'; }; export const isNextApiRequest = (req: Req) => { diff --git a/tests/auth0-session/client/edge-client.test.ts b/tests/auth0-session/client/edge-client.test.ts new file mode 100644 index 000000000..48b7805c9 --- /dev/null +++ b/tests/auth0-session/client/edge-client.test.ts @@ -0,0 +1,391 @@ +/** + * @jest-environment @edge-runtime/jest-environment + */ +import nock from 'nock'; +import * as jose from 'jose'; +import { getConfig, ConfigParameters } from '../../../src/auth0-session'; +import { jwks, makeIdToken } from '../fixtures/cert'; +import pkg from '../../../package.json'; +import wellKnown from '../fixtures/well-known.json'; +import version from '../../../src/version'; +import { EdgeClient } from '../../../src/auth0-session/client/edge-client'; +import { mockFetch } from '../../fixtures/app-router-helpers'; +import { Auth0Request } from '../../../src/auth0-session/http'; +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { UserInfoError } from '../../../src/auth0-session/utils/errors'; + +class TestReq extends Auth0Request { + constructor() { + super(null); + } + getBody() { + return { state: 'foo', code: 'bar' }; + } + getCookies() { + return {}; + } + getMethod() { + return 'POST'; + } + getUrl() { + return ''; + } +} + +const defaultConfig: ConfigParameters = { + secret: '__test_session_secret__', + clientID: '__test_client_id__', + clientSecret: '__test_client_secret__', + issuerBaseURL: 'https://op.example.com', + baseURL: 'https://example.org', + routes: { + callback: '/callback' + }, + authorizationParams: { + response_type: 'code', + scope: 'openid profile read:customer', + audience: 'https://api.acme.com' + } +}; + +const getClient = async (params: ConfigParameters = {}): Promise => { + return new EdgeClient(getConfig({ ...defaultConfig, ...params }), { + name: 'nextjs-auth0', + version + }); +}; + +describe('edge client', function () { + let headersSpy = jest.fn(); + + beforeEach(() => { + mockFetch(); + if (!nock.isActive()) { + nock.activate(); + } + nock('https://op.example.com').get('/.well-known/openid-configuration').reply(200, wellKnown); + nock('https://op.example.com').get('/.well-known/jwks.json').reply(200, jwks); + nock('https://op.example.com') + .get('/userinfo') + .reply(200, function () { + headersSpy(this.req.headers); + return { sub: 'foo' }; + }); + nock('https://op.example.com') + .post('/oauth/token', (body) => { + return !body.error; + }) + .reply(200, async function () { + return { + access_token: '__test_access_token__', + refresh_token: '__test_refresh_token__', + id_token: await makeIdToken({}), + token_type: 'Bearer', + expires_in: 86400 + }; + }); + }); + + afterEach(() => { + nock.restore(); + nock.cleanAll(); + }); + + it('should send the correct default headers', async function () { + const client = await getClient(); + const userinfo = await client.userinfo('__test_token__'); + const headers = headersSpy.mock.calls[0][0]; + const headerProps = Object.getOwnPropertyNames(headers); + + expect(headerProps).toContain('auth0-client'); + + const decodedTelemetry = JSON.parse(jose.base64url.decode(headers['auth0-client'][0]).toString()); + + expect(decodedTelemetry.name).toEqual('nextjs-auth0'); + expect(decodedTelemetry.version).toEqual(pkg.version); + expect(decodedTelemetry.env.edge).toEqual(true); + + expect(headerProps).toContain('user-agent'); + expect(headers['user-agent'][0]).toEqual(`nextjs-auth0/${pkg.version}`); + expect(userinfo.sub).toBe('foo'); + }); + + it('should disable telemetry', async function () { + const client = await getClient({ enableTelemetry: false }); + const userinfo = await client.userinfo('__test_token__'); + const headers = headersSpy.mock.calls[0][0]; + const headerProps = Object.getOwnPropertyNames(headers); + + expect(headerProps).not.toContain('auth0-client'); + expect(userinfo.sub).toBe('foo'); + }); + + it('should not strip new headers', async function () { + const client = await getClient(); + const userinfo = await client.userinfo('__test_token__'); + const headers = headersSpy.mock.calls[0][0]; + const headerProps = Object.getOwnPropertyNames(headers); + + expect(headerProps).toContain('authorization'); + expect(userinfo.sub).toBe('foo'); + }); + + it('should prefer user configuration regardless of idP discovery', async function () { + nock('https://op2.example.com') + .get('/.well-known/openid-configuration') + .reply( + 200, + Object.assign({}, wellKnown, { + issuer: 'https://op2.example.com', + id_token_signing_alg_values_supported: ['none'] + }) + ); + + const client = await getClient({ + issuerBaseURL: 'https://op2.example.com', + idTokenSigningAlg: 'RS256' + }); + // @ts-ignore + expect((await client.getClient())[1].id_token_signed_response_alg).toEqual('RS256'); + }); + + it('should use discovered logout endpoint by default', async function () { + const client = await getClient({ ...defaultConfig, idpLogout: true }); + await expect(client.endSessionUrl({} as any)).resolves.toEqual( + 'https://op.example.com/session/end?client_id=__test_client_id__' + ); + }); + + it('should use auth0 logout endpoint if configured', async function () { + const client = await getClient({ ...defaultConfig, idpLogout: true, auth0Logout: true }); + await expect(client.endSessionUrl({} as any)).resolves.toEqual( + 'https://op.example.com/v2/logout?client_id=__test_client_id__' + ); + }); + + it('should use auth0 logout endpoint if domain is auth0.com', async function () { + nock('https://foo.auth0.com') + .get('/.well-known/openid-configuration') + .reply(200, { ...wellKnown, issuer: 'https://foo.auth0.com/' }); + const client = await getClient({ ...defaultConfig, idpLogout: true, issuerBaseURL: 'https://foo.auth0.com' }); + await expect(client.endSessionUrl({ post_logout_redirect_uri: '' })).resolves.toEqual( + 'https://foo.auth0.com/v2/logout?client_id=__test_client_id__' + ); + }); + + it('should use auth0 logout endpoint if domain is auth0.com and configured', async function () { + nock('https://foo.auth0.com') + .get('/.well-known/openid-configuration') + .reply(200, { ...wellKnown, issuer: 'https://foo.auth0.com/' }); + const client = await getClient({ + ...defaultConfig, + issuerBaseURL: 'https://foo.auth0.com', + idpLogout: true, + auth0Logout: true + }); + await expect(client.endSessionUrl({ post_logout_redirect_uri: '' })).resolves.toEqual( + 'https://foo.auth0.com/v2/logout?client_id=__test_client_id__' + ); + }); + + it('should use discovered logout endpoint if domain is auth0.com but configured with auth0logout false', async function () { + nock('https://foo.auth0.com') + .get('/.well-known/openid-configuration') + .reply(200, { + ...wellKnown, + issuer: 'https://foo.auth0.com/', + end_session_endpoint: 'https://foo.auth0.com/oidc/logout' + }); + const client = await getClient({ + ...defaultConfig, + issuerBaseURL: 'https://foo.auth0.com', + idpLogout: true, + auth0Logout: false + }); + await expect(client.endSessionUrl({} as any)).resolves.toEqual( + 'https://foo.auth0.com/oidc/logout?client_id=__test_client_id__' + ); + }); + + it('should create client with no end_session_endpoint', async function () { + nock('https://op2.example.com') + .get('/.well-known/openid-configuration') + .reply(200, { + ...wellKnown, + issuer: 'https://op2.example.com', + end_session_endpoint: undefined + }); + const client = await getClient({ ...defaultConfig, issuerBaseURL: 'https://op2.example.com' }); + await expect(client.endSessionUrl({ post_logout_redirect_uri: '' })).rejects.toThrowError(); + }); + + it('should create custom logout for auth0', async function () { + nock('https://test.eu.auth0.com') + .get('/.well-known/openid-configuration') + .reply(200, { ...wellKnown, issuer: 'https://test.eu.auth0.com/', end_session_endpoint: undefined }); + nock('https://test.eu.auth0.com').get('/.well-known/jwks.json').reply(200, jwks); + + const client = await getClient({ + issuerBaseURL: 'https://test.eu.auth0.com', + idpLogout: true + }); + await expect(client.endSessionUrl({ post_logout_redirect_uri: 'foo' })).resolves.toEqual( + 'https://test.eu.auth0.com/v2/logout?returnTo=foo&client_id=__test_client_id__' + ); + }); + + it('should remove null params from oidc logout endpoint', async function () { + const client = await getClient({ ...defaultConfig, idpLogout: true }); + await expect(client.endSessionUrl({ foo: null } as any)).resolves.toEqual( + 'https://op.example.com/session/end?client_id=__test_client_id__' + ); + }); + + it('should remove null params from auth0 logout endpoint', async function () { + const client = await getClient({ ...defaultConfig, idpLogout: true, auth0Logout: true }); + await expect(client.endSessionUrl({ foo: null } as any)).resolves.toEqual( + 'https://op.example.com/v2/logout?client_id=__test_client_id__' + ); + }); + + it('should handle limited openid-configuration', async function () { + nock('https://op2.example.com') + .get('/.well-known/openid-configuration') + .reply( + 200, + Object.assign({}, wellKnown, { + issuer: 'https://op2.example.com', + id_token_signing_alg_values_supported: undefined, + response_types_supported: undefined, + response_modes_supported: 'foo', + end_session_endpoint: undefined + }) + ); + + await expect( + ( + await getClient({ + issuerBaseURL: 'https://op2.example.com', + idpLogout: true + }) + ) + // @ts-ignore + .getClient() + ).resolves.not.toThrow(); + }); + + it('should throw DiscoveryError when discovery fails', async () => { + nock.cleanAll(); + nock('https://op.example.com').get('/.well-known/oauth-authorization-server').reply(500); + nock('https://op.example.com').get('/.well-known/openid-configuration').reply(500); + await expect((await getClient()).userinfo('token')).rejects.toThrow( + /Discovery requests failing for https:\/\/op.example.com/ + ); + }); + + it('should throw UserInfoError when userinfo fails', async () => { + nock.cleanAll(); + nock('https://op.example.com').get('/.well-known/openid-configuration').reply(200, wellKnown); + nock('https://op.example.com').get('/userinfo').reply(500, {}); + const client = await getClient(); + await expect(client.userinfo('__test_token__')).rejects.toThrow(UserInfoError); + }); + + it('should only support code flow', async () => { + await expect(getClient({ authorizationParams: { response_type: 'id_token' } })).rejects.toThrow( + 'This SDK only supports `response_type=code` when used in an Edge runtime.' + ); + }); + + it('should strip empty parameters from login url', async () => { + const client = await getClient(); + await expect(client.authorizationUrl({ foo: null })).resolves.toBe( + 'https://op.example.com/authorize?client_id=__test_client_id__' + ); + }); + + it('should get callback params from req body', async () => { + const client = await getClient(); + await expect(client.callbackParams(new TestReq(), 'foo')).resolves.toBeInstanceOf(URLSearchParams); + }); + + it('should support private key jwt', async () => { + const privateKey = readFileSync(join(__dirname, '..', 'fixtures', 'private-key.pem'), 'utf-8'); + + function pemToArrayBuffer(pem: string) { + const b64 = pem + .replace('\n', '') + .replace('-----BEGIN PRIVATE KEY-----', '') + .replace('-----END PRIVATE KEY-----', ''); + + const byteString = atob(b64); + const byteArray = new Uint8Array(byteString.length); + for (let i = 0; i < byteString.length; i++) { + byteArray[i] = byteString.charCodeAt(i); + } + return byteArray; + } + + const key = await crypto.subtle.importKey( + 'pkcs8', + pemToArrayBuffer(privateKey), + { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: 'SHA-256' } // or SHA-512 + }, + true, + ['sign'] + ); + + const client = await getClient({ clientAssertionSigningKey: key as any }); + const params = await client.callbackParams(new TestReq(), 'foo'); + const res = await client.callback( + 'https://example.org/callback', + params, + { response_type: 'code', code_verifier: 'bar', nonce: '__test_nonce__' }, + {} + ); + expect(res.access_token).toBe('__test_access_token__'); + }); + + it('should handle oauth errors from code exchange', async () => { + nock('https://op.example.com') + .post('/oauth/token', (body) => { + return !!body.error; + }) + .reply(400, async function () { + return { + error: 'foo', + error_description: 'bar' + }; + }); + const client = await getClient(); + const params = await client.callbackParams(new TestReq(), 'foo'); + await expect( + client.callback( + 'https://example.org/callback', + params, + { response_type: 'code', code_verifier: 'bar', nonce: '__test_nonce__' }, + { exchangeBody: { error: '1' } } + ) + ).rejects.toThrowError(expect.objectContaining({ error: 'foo', errorDescription: 'bar' })); + }); + + it('should handle oauth errors from token refresh', async () => { + nock('https://op.example.com') + .post('/oauth/token', (body) => { + return !!body.error; + }) + .reply(400, async function () { + return { + error: 'foo', + error_description: 'bar' + }; + }); + const client = await getClient(); + await expect(client.refresh('foo', { exchangeBody: { error: '1' } })).rejects.toThrow( + 'The request to refresh the access token failed. CAUSE: bar' + ); + }); +}); diff --git a/tests/auth0-session/client.test.ts b/tests/auth0-session/client/node-client.test.ts similarity index 70% rename from tests/auth0-session/client.test.ts rename to tests/auth0-session/client/node-client.test.ts index cf925fd4d..1aa983d51 100644 --- a/tests/auth0-session/client.test.ts +++ b/tests/auth0-session/client/node-client.test.ts @@ -1,10 +1,11 @@ import nock from 'nock'; -import { Client } from 'openid-client'; -import { getConfig, ConfigParameters } from '../../src/auth0-session'; -import { jwks } from './fixtures/cert'; -import pkg from '../../package.json'; -import wellKnown from './fixtures/well-known.json'; -import version from '../../src/version'; +import { getConfig, ConfigParameters } from '../../../src/auth0-session'; +import { jwks } from '../fixtures/cert'; +import pkg from '../../../package.json'; +import wellKnown from '../fixtures/well-known.json'; +import version from '../../../src/version'; +import { NodeClient } from '../../../src/auth0-session/client/node-client'; +import { UserInfoError } from '../../../src/auth0-session/utils/errors'; const defaultConfig = { secret: '__test_session_secret__', @@ -17,15 +18,14 @@ const defaultConfig = { } }; -const getClient = async (params: ConfigParameters = {}): Promise => { - const { default: clientFactory } = await import('../../src/auth0-session/client'); - return clientFactory(getConfig({ ...defaultConfig, ...params }), { +const getClient = async (params: ConfigParameters = {}): Promise => { + return new NodeClient(getConfig({ ...defaultConfig, ...params }), { name: 'nextjs-auth0', version - })(); + }); }; -describe('clientFactory', function () { +describe('node client', function () { beforeEach(() => { if (!nock.isActive()) { nock.activate(); @@ -33,7 +33,7 @@ describe('clientFactory', function () { nock('https://op.example.com').get('/.well-known/openid-configuration').reply(200, wellKnown); nock('https://op.example.com').get('/.well-known/jwks.json').reply(200, jwks); nock('https://op.example.com') - .post('/introspection') + .get('/userinfo') .reply(200, function () { return this.req.headers; }); @@ -44,15 +44,9 @@ describe('clientFactory', function () { nock.cleanAll(); }); - it('should save the passed values', async function () { - const client = await getClient(); - expect(client.client_id).toEqual('__test_client_id__'); - expect(client.client_secret).toEqual('__test_client_secret__'); - }); - it('should send the correct default headers', async function () { const client = await getClient(); - const headers = await client.introspect('__test_token__', '__test_hint__'); + const headers = await client.userinfo('__test_token__'); const headerProps = Object.getOwnPropertyNames(headers); expect(headerProps).toContain('auth0-client'); @@ -69,7 +63,7 @@ describe('clientFactory', function () { it('should disable telemetry', async function () { const client = await getClient({ enableTelemetry: false }); - const headers = await client.introspect('__test_token__', '__test_hint__'); + const headers = await client.userinfo('__test_token__'); const headerProps = Object.getOwnPropertyNames(headers); expect(headerProps).not.toContain('auth0-client'); @@ -77,13 +71,8 @@ describe('clientFactory', function () { it('should not strip new headers', async function () { const client = await getClient(); - const response = await client.requestResource('https://op.example.com/introspection', 'token', { - method: 'POST', - headers: { - Authorization: 'Bearer foo' - } - }); - const headerProps = Object.getOwnPropertyNames(JSON.parse((response.body as Buffer).toString())); + const response = await client.userinfo('__test_token__'); + const headerProps = Object.getOwnPropertyNames(response); expect(headerProps).toContain('authorization'); }); @@ -102,17 +91,22 @@ describe('clientFactory', function () { issuerBaseURL: 'https://op2.example.com', idTokenSigningAlg: 'RS256' }); - expect(client.id_token_signed_response_alg).toEqual('RS256'); + // @ts-ignore + expect((await client.getClient()).id_token_signed_response_alg).toEqual('RS256'); }); it('should use discovered logout endpoint by default', async function () { const client = await getClient({ ...defaultConfig, idpLogout: true }); - expect(client.endSessionUrl({})).toEqual('https://op.example.com/session/end?client_id=__test_client_id__'); + await expect(client.endSessionUrl({})).resolves.toEqual( + 'https://op.example.com/session/end?client_id=__test_client_id__' + ); }); it('should use auth0 logout endpoint if configured', async function () { const client = await getClient({ ...defaultConfig, idpLogout: true, auth0Logout: true }); - expect(client.endSessionUrl({})).toEqual('https://op.example.com/v2/logout?client_id=__test_client_id__'); + await expect(client.endSessionUrl({})).resolves.toEqual( + 'https://op.example.com/v2/logout?client_id=__test_client_id__' + ); }); it('should use auth0 logout endpoint if domain is auth0.com', async function () { @@ -120,7 +114,9 @@ describe('clientFactory', function () { .get('/.well-known/openid-configuration') .reply(200, { ...wellKnown, issuer: 'https://foo.auth0.com/' }); const client = await getClient({ ...defaultConfig, idpLogout: true, issuerBaseURL: 'https://foo.auth0.com' }); - expect(client.endSessionUrl({})).toEqual('https://foo.auth0.com/v2/logout?client_id=__test_client_id__'); + await expect(client.endSessionUrl({})).resolves.toEqual( + 'https://foo.auth0.com/v2/logout?client_id=__test_client_id__' + ); }); it('should use auth0 logout endpoint if domain is auth0.com and configured', async function () { @@ -133,7 +129,9 @@ describe('clientFactory', function () { idpLogout: true, auth0Logout: true }); - expect(client.endSessionUrl({})).toEqual('https://foo.auth0.com/v2/logout?client_id=__test_client_id__'); + await expect(client.endSessionUrl({})).resolves.toEqual( + 'https://foo.auth0.com/v2/logout?client_id=__test_client_id__' + ); }); it('should use discovered logout endpoint if domain is auth0.com but configured with auth0logout false', async function () { @@ -150,7 +148,9 @@ describe('clientFactory', function () { idpLogout: true, auth0Logout: false }); - expect(client.endSessionUrl({})).toEqual('https://foo.auth0.com/oidc/logout?client_id=__test_client_id__'); + await expect(client.endSessionUrl({})).resolves.toEqual( + 'https://foo.auth0.com/oidc/logout?client_id=__test_client_id__' + ); }); it('should create client with no end_session_endpoint', async function () { @@ -162,7 +162,7 @@ describe('clientFactory', function () { end_session_endpoint: undefined }); const client = await getClient({ ...defaultConfig, issuerBaseURL: 'https://op2.example.com' }); - expect(() => client.endSessionUrl({})).toThrowError(); + await expect(client.endSessionUrl({})).rejects.toThrowError(); }); it('should create custom logout for auth0', async function () { @@ -175,8 +175,8 @@ describe('clientFactory', function () { issuerBaseURL: 'https://test.eu.auth0.com', idpLogout: true }); - expect(client.endSessionUrl({ post_logout_redirect_uri: 'foo' })).toEqual( - 'https://test.eu.auth0.com/v2/logout?returnTo=foo&client_id=__test_client_id__' + await expect(client.endSessionUrl({ post_logout_redirect_uri: 'foo' })).resolves.toEqual( + 'https://test.eu.auth0.com/v2/logout?client_id=__test_client_id__&returnTo=foo' ); }); @@ -194,10 +194,14 @@ describe('clientFactory', function () { ); await expect( - getClient({ - issuerBaseURL: 'https://op2.example.com', - idpLogout: true - }) + ( + await getClient({ + issuerBaseURL: 'https://op2.example.com', + idpLogout: true + }) + ) + // @ts-ignore + .getClient() ).resolves.not.toThrow(); }); @@ -205,8 +209,15 @@ describe('clientFactory', function () { nock.cleanAll(); nock('https://op.example.com').get('/.well-known/oauth-authorization-server').reply(500); nock('https://op.example.com').get('/.well-known/openid-configuration').reply(500); - await expect(getClient()).rejects.toThrow( + await expect((await getClient()).userinfo('token')).rejects.toThrow( 'Discovery requests failing for https://op.example.com, expected 200 OK, got: 500 Internal Server Error' ); }); + + it('should throw UserInfoError when userinfo fails', async () => { + nock.cleanAll(); + nock('https://op.example.com').get('/.well-known/openid-configuration').reply(200, wellKnown); + nock('https://op.example.com').get('/userinfo').reply(500, {}); + await expect((await getClient()).userinfo('token')).rejects.toThrow(UserInfoError); + }); }); diff --git a/tests/auth0-session/fixtures/helpers.ts b/tests/auth0-session/fixtures/helpers.ts index a4f368675..e448eeef8 100644 --- a/tests/auth0-session/fixtures/helpers.ts +++ b/tests/auth0-session/fixtures/helpers.ts @@ -1,8 +1,8 @@ +import { IncomingMessage, request as nodeHttpRequest } from 'http'; +import { request as nodeHttpsRequest } from 'https'; import { Cookie, CookieJar } from 'tough-cookie'; import { signing } from '../../../src/auth0-session/utils/hkdf'; import { generateCookieValue } from '../../../src/auth0-session/utils/signed-cookies'; -import { IncomingMessage, request as nodeHttpRequest } from 'http'; -import { request as nodeHttpsRequest } from 'https'; import { ConfigParameters } from '../../../src/auth0-session'; import { base64url } from 'jose'; diff --git a/tests/auth0-session/fixtures/server.ts b/tests/auth0-session/fixtures/server.ts index 083294dcc..5277bb960 100644 --- a/tests/auth0-session/fixtures/server.ts +++ b/tests/auth0-session/fixtures/server.ts @@ -9,7 +9,6 @@ import { loginHandler, getConfig, ConfigParameters, - clientFactory, TransientStore, StatelessSession, SessionCache, @@ -27,6 +26,7 @@ import { cert, key } from './https'; import { Claims } from '../../../src/session'; import version from '../../../src/version'; import { NodeRequest, NodeResponse } from '../../../src/auth0-session/http'; +import { NodeClient } from '../../../src/auth0-session/client/node-client'; export type SessionResponse = TokenSetParameters & { claims: Claims }; @@ -55,7 +55,7 @@ class TestSessionCache implements SessionCache const [session] = await this.cookieStore.read(new NodeRequest(req)); return session?.id_token; } - fromTokenSet(tokenSet: TokenSet): { [p: string]: any } { + fromTokenEndpointResponse(tokenSet: TokenSet): { [p: string]: any } { return tokenSet; } } @@ -69,15 +69,15 @@ type Handlers = { const createHandlers = (params: ConfigParameters): Handlers => { const config = getConfig(params); - const getClient = clientFactory(config, { name: 'nextjs-auth0', version }); + const client = new NodeClient(config, { name: 'nextjs-auth0', version }); const transientStore = new TransientStore(config); const cookieStore = params.session?.store ? new StatefulSession(config) : new StatelessSession(config); const sessionCache = new TestSessionCache(cookieStore); return { - handleLogin: loginHandler(config, getClient, transientStore), - handleLogout: logoutHandler(config, getClient, sessionCache), - handleCallback: callbackHandler(config, getClient, sessionCache, transientStore), + handleLogin: loginHandler(config, client, transientStore), + handleLogout: logoutHandler(config, client, sessionCache), + handleCallback: callbackHandler(config, client, sessionCache, transientStore), handleSession: async (req: IncomingMessage, res: ServerResponse) => { const nodeReq = new NodeRequest(req); const [json, iat] = await cookieStore.read(nodeReq); diff --git a/tests/auth0-session/handlers/callback.test.ts b/tests/auth0-session/handlers/callback.test.ts index bfed184e6..dc685355f 100644 --- a/tests/auth0-session/handlers/callback.test.ts +++ b/tests/auth0-session/handlers/callback.test.ts @@ -436,60 +436,6 @@ describe('callback', () => { expect(header.alg).toEqual('RS256'); }); - it('should use client secret jwt on token endpoint', async () => { - const idToken = await makeIdToken({ - c_hash: '77QmUPtjPfzWtF2AnpK9RQ' - }); - - const baseURL = await setup({ - ...defaultConfig, - authorizationParams: { - response_type: 'code' - }, - clientSecret: 'foo', - clientAuthMethod: 'client_secret_jwt' - }); - - let body: qs.ParsedUrlQuery = {}; - nock('https://op.example.com') - .post('/oauth/token') - .reply(200, function (_uri, requestBody) { - body = qs.parse(requestBody as string); - return { - access_token: '__test_access_token__', - refresh_token: '__test_refresh_token__', - id_token: idToken, - token_type: 'Bearer', - expires_in: 86400 - }; - }); - - const cookieJar = await toSignedCookieJar( - { - state: expectedDefaultState, - nonce: '__test_nonce__' - }, - baseURL - ); - - await post(baseURL, '/callback', { - body: { - state: expectedDefaultState, - id_token: idToken, - code: 'jHkWEdUXMU1BwAsC4vtUsZwnNvTIxEl0z9K3vx5KF0Y' - }, - cookieJar, - fullResponse: true - }); - - expect(body.client_assertion).not.toBeUndefined(); - expect(body.client_assertion_type).toEqual('urn:ietf:params:oauth:client-assertion-type:jwt-bearer'); - - const { header } = decodeJWT(body.client_assertion as string); - - expect(header.alg).toEqual('HS256'); - }); - it('should redirect to default base url', async () => { const baseURL = await setup(defaultConfig); diff --git a/tests/auth0-session/session/stateless-session.test.ts b/tests/auth0-session/session/stateless-session.test.ts index 3876ad598..7ac790dcf 100644 --- a/tests/auth0-session/session/stateless-session.test.ts +++ b/tests/auth0-session/session/stateless-session.test.ts @@ -262,7 +262,7 @@ describe('StatelessSession', () => { }); it('should expire after 1 day of inactivity by default', async () => { - const clock = jest.useFakeTimers('modern'); + const clock = jest.useFakeTimers(); const baseURL = await setup(defaultConfig); const appSession = await encrypted(); @@ -275,7 +275,7 @@ describe('StatelessSession', () => { }); it('should expire after 7 days regardless of activity by default', async () => { - const clock = jest.useFakeTimers('modern'); + const clock = jest.useFakeTimers(); let days = 7; const baseURL = await setup(defaultConfig); @@ -292,7 +292,7 @@ describe('StatelessSession', () => { }); it('should expire only after custom absoluteDuration', async () => { - const clock = jest.useFakeTimers('modern'); + const clock = jest.useFakeTimers(); const baseURL = await setup({ ...defaultConfig, @@ -313,7 +313,7 @@ describe('StatelessSession', () => { }); it('should expire only after defined rollingDuration period of inactivty', async () => { - const clock = jest.useFakeTimers('modern'); + const clock = jest.useFakeTimers(); const baseURL = await setup({ ...defaultConfig, session: { diff --git a/tests/auth0-session/transient-store.test.ts b/tests/auth0-session/transient-store.test.ts index e99602a52..426371aeb 100644 --- a/tests/auth0-session/transient-store.test.ts +++ b/tests/auth0-session/transient-store.test.ts @@ -83,10 +83,12 @@ describe('TransientStore', () => { expect(cookie?.secure).toBeFalsy(); }); - it('should set SameSite=None, Secure=False for fallback cookie by default for http', async () => { + it('should not set SameSite and set Secure=False for fallback cookie by default for http', async () => { const baseURL: string = await setup( defaultConfig, - (req: NodeRequest, res: NodeResponse) => transientStore.save('test_key', req, res, { value: 'foo' }), + (req: NodeRequest, res: NodeResponse) => { + return transientStore.save('test_key', req, res, { value: 'foo' }); + }, false ); const transientStore = new TransientStore(getConfig({ ...defaultConfig, baseURL })); @@ -95,7 +97,7 @@ describe('TransientStore', () => { const fallbackCookie = getCookie('_test_key', cookieJar, baseURL); expect(value).toEqual(expect.any(String)); expect(fallbackCookie).toMatchObject({ - sameSite: 'none', + sameSite: undefined, secure: false, httpOnly: true }); @@ -212,10 +214,4 @@ describe('TransientStore', () => { const { value } = await get(baseURL, '/', { cookieJar }); expect(value).toBeUndefined(); }); - - it('should generate a code verifier and challenge', async () => { - const transientStore = new TransientStore(getConfig({ ...defaultConfig, baseURL: 'http://example.com' })); - expect(transientStore.generateCodeVerifier()).toEqual(expect.any(String)); - expect(transientStore.calculateCodeChallenge('foo')).toEqual(expect.any(String)); - }); }); diff --git a/tests/auth0-session/utils/errors.test.ts b/tests/auth0-session/utils/errors.test.ts index 067d0549f..53e39aa88 100644 --- a/tests/auth0-session/utils/errors.test.ts +++ b/tests/auth0-session/utils/errors.test.ts @@ -3,7 +3,6 @@ import { IdentityProviderError } from '../../../src/auth0-session'; describe('IdentityProviderError', () => { test('should escape error fields', () => { const error = new IdentityProviderError({ - name: 'RPError', message: "", error: "", error_description: "" diff --git a/tests/fixtures/app-router-helpers.ts b/tests/fixtures/app-router-helpers.ts index abfc46c24..ffa3c29c2 100644 --- a/tests/fixtures/app-router-helpers.ts +++ b/tests/fixtures/app-router-helpers.ts @@ -1,23 +1,51 @@ import nock from 'nock'; +import { default as nodeFetch } from 'node-fetch'; +import { NextRequest, NextResponse } from 'next/server'; import { Auth0Server, CallbackOptions, Claims, ConfigParameters, - initAuth0, + initAuth0 as nodeInitAuth0, LoginOptions, LogoutOptions, ProfileOptions } from '../../src'; +import { initAuth0 as edgeInitAuth0 } from '../../src/edge'; import { withApi } from './default-settings'; import { setupNock } from './setup'; -import { NextRequest, NextResponse } from 'next/server'; import { StatelessSession } from '../../src/auth0-session'; import { getConfig } from '../../src/config'; import { Auth0NextRequest } from '../../src/http'; import { encodeState } from '../../src/auth0-session/utils/encoding'; import { signCookie } from '../auth0-session/fixtures/helpers'; +const isEdgeRuntime = + // @ts-ignore + typeof EdgeRuntime !== 'undefined'; + +export const initAuth0 = (config: ConfigParameters) => { + if (isEdgeRuntime) { + return edgeInitAuth0(config); + } + return nodeInitAuth0(config); +}; + +export const mockFetch = () => { + if (isEdgeRuntime) { + jest.spyOn(globalThis, 'fetch').mockImplementation((...args: any[]) => + (nodeFetch as any)(...args).then(async (res: any) => { + const res2 = new Response(await res.text(), { + headers: Object.fromEntries(res.headers.entries()), + status: res.status + }); + Object.defineProperty(res2, 'url', { value: args[0] }); + return res2; + }) + ); + } +}; + export type GetResponseOpts = { url: string; config?: ConfigParameters; @@ -93,14 +121,14 @@ export const getSession = async (config: any, res: NextResponse) => { export const login = async (opts: LoginOpts = {}) => { const state = encodeState({ returnTo: '/' }); - const res = await getResponse({ + return await getResponse({ ...opts, url: `/api/auth/callback?state=${state}&code=code`, cookies: { ...opts.cookies, state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') } }); - return res; }; diff --git a/tests/fixtures/oidc-nocks.ts b/tests/fixtures/oidc-nocks.ts index 843a24544..6b8d12b99 100644 --- a/tests/fixtures/oidc-nocks.ts +++ b/tests/fixtures/oidc-nocks.ts @@ -81,12 +81,13 @@ export function jwksEndpoint(params: ConfigParameters, keyset: JSONWebKeySet): n export function codeExchange(params: ConfigParameters, idToken: string, code = 'code'): nock.Scope { return nock(`${params.issuerBaseURL}`) - .post( - '/oauth/token', - `grant_type=authorization_code&code=${code}&redirect_uri=${encodeURIComponent( - `${params.baseURL}api/auth/callback` - )}` - ) + .post('/oauth/token', (body: any) => { + return ( + body.grant_type === 'authorization_code' && + body.code === code && + body.redirect_uri === `${params.baseURL}api/auth/callback` + ); + }) .reply(200, { access_token: 'eyJz93a...k4laUWw', expires_in: 750, @@ -110,7 +111,9 @@ export async function refreshTokenExchange( }); return nock(`${params.issuerBaseURL}`) - .post('/oauth/token', `grant_type=refresh_token&refresh_token=${refreshToken}`) + .post('/oauth/token', (body) => { + return body.grant_type === 'refresh_token' && body.refresh_token === refreshToken; + }) .reply(200, { access_token: newToken || 'eyJz93a...k4laUWw', id_token: idToken, @@ -145,7 +148,9 @@ export async function refreshTokenRotationExchange( }); return nock(`${params.issuerBaseURL}`) - .post('/oauth/token', `grant_type=refresh_token&refresh_token=${refreshToken}`) + .post('/oauth/token', (body) => { + return body.grant_type === 'refresh_token' && body.refresh_token === refreshToken; + }) .reply(200, { access_token: newToken || 'eyJz93a...k4laUWw', refresh_token: newrefreshToken || 'GEbRxBN...edjnXbL', diff --git a/tests/fixtures/setup.ts b/tests/fixtures/setup.ts index fa3bddb86..1ab24897d 100644 --- a/tests/fixtures/setup.ts +++ b/tests/fixtures/setup.ts @@ -37,7 +37,7 @@ export type SetupOptions = { withPageAuthRequiredOptions?: WithPageAuthRequiredPageRouterOptions; getAccessTokenOptions?: AccessTokenRequest; onError?: PageRouterOnError; - discoveryOptions?: Record; + discoveryOptions?: Record; userInfoPayload?: Record; userInfoToken?: string; asyncProps?: boolean; diff --git a/tests/frontend/with-page-auth-required.test.tsx b/tests/frontend/with-page-auth-required.test.tsx index eda022aa7..9a613f492 100644 --- a/tests/frontend/with-page-auth-required.test.tsx +++ b/tests/frontend/with-page-auth-required.test.tsx @@ -8,21 +8,17 @@ import { render, screen, waitFor } from '@testing-library/react'; import { fetchUserErrorMock, withUserProvider, user } from '../fixtures/frontend'; import { withPageAuthRequired } from '../../src/client'; -const windowLocation = window.location; - describe('with-page-auth-required csr', () => { beforeAll(() => { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore window.location is non-optional - delete window.location; - window.location = { - ...windowLocation, - assign: jest.fn(), - toString: jest.fn(() => 'https://example.com') - }; + Object.defineProperty(window, 'location', { + writable: true, + value: { + assign: jest.fn(), + toString: () => 'https://example.com' + } + }); }); afterEach(() => delete (global as any).fetch); - afterAll(() => (window.location = windowLocation)); it('should deny access to a CSR page when not authenticated', async () => { (global as any).fetch = fetchUserErrorMock; diff --git a/tests/handlers/auth-page-router.test.ts b/tests/handlers/auth-page-router.test.ts new file mode 100644 index 000000000..dcaffb593 --- /dev/null +++ b/tests/handlers/auth-page-router.test.ts @@ -0,0 +1,291 @@ +import { IncomingMessage, ServerResponse } from 'http'; +import { NextApiHandler } from 'next'; +import { withoutApi } from '../fixtures/default-settings'; +import { login, setup, teardown } from '../fixtures/setup'; +import { get } from '../auth0-session/fixtures/helpers'; +import { initAuth0 } from '../../src'; +import { LoginOptions, LogoutOptions, CallbackOptions, ProfileOptions } from '../../src/handlers'; +import * as baseLoginHandler from '../../src/auth0-session/handlers/login'; +import * as baseLogoutHandler from '../../src/auth0-session/handlers/logout'; +import * as baseCallbackHandler from '../../src/auth0-session/handlers/callback'; +import { Handler } from '../../src/handlers/router-helpers'; + +const handlerError = () => + expect.objectContaining({ + status: 400, + code: 'ERR_CALLBACK_HANDLER_FAILURE' + }); + +describe('auth handler (page router)', () => { + afterEach(teardown); + + test('return 500 for unexpected error', async () => { + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth; + delete global.onError; + jest.spyOn(console, 'error').mockImplementation((error) => { + delete error.status; + }); + await expect(get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo')).rejects.toThrow( + 'Internal Server Error' + ); + }); + + test('return 404 for unknown routes', async () => { + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth; + await expect(get(baseUrl, '/api/auth/foo')).rejects.toThrow('Not Found'); + }); + + test('return 404 for unknown routes including builtin props', async () => { + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth; + await expect(get(baseUrl, '/api/auth/__proto__')).rejects.toThrow('Not Found'); + }); + + test('return 404 when routes have extra parts', async () => { + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth; + await expect(get(baseUrl, '/api/auth/me.css')).rejects.toThrow('Not Found'); + await expect(get(baseUrl, '/api/auth/me/foo.css')).rejects.toThrow('Not Found'); + await expect(get(baseUrl, '/api/auth/me/foo/bar.css')).rejects.toThrow('Not Found'); + }); + + test('accept custom error handler', async () => { + const onError = jest.fn((_req, res) => res.end()); + const baseUrl = await setup(withoutApi, { onError }); + await get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo'); + expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError()); + }); + + test('use default error handler', async () => { + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth; + delete global.onError; + // eslint-disable-next-line @typescript-eslint/no-empty-function + jest.spyOn(console, 'error').mockImplementation(() => {}); + await expect(get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo')).rejects.toThrow( + 'Bad Request' + ); + expect(console.error).toHaveBeenCalledWith(handlerError()); + }); + + test('finish response if custom error does not', async () => { + const onError = jest.fn(); + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { onError }); + await expect( + get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo', { fullResponse: true }) + ).rejects.toThrow('Internal Server Error'); + expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError()); + }); + + test('finish response with custom error status', async () => { + const onError = jest.fn((_req, res) => res.status(418)); + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { onError }); + await expect( + get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo', { fullResponse: true }) + ).rejects.toThrow("I'm a Teapot"); + expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError()); + }); + + test('accept custom login handler', async () => { + const login = jest.fn(async (_req, res) => { + res.end(); + }) as NextApiHandler as Handler; + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { login }); + await get(baseUrl, '/api/auth/login'); + expect(login).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); + }); + + test('accept custom logout handler', async () => { + const logout = jest.fn(async (_req, res) => { + res.end(); + }) as NextApiHandler as Handler; + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { logout }); + await get(baseUrl, '/api/auth/logout'); + expect(logout).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); + }); + + test('accept custom callback handler', async () => { + const callback = jest.fn(async (_req, res) => { + res.end(); + }) as NextApiHandler as Handler; + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { callback }); + await get(baseUrl, '/api/auth/callback'); + expect(callback).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); + }); + + test('accept custom profile handler', async () => { + const profile = jest.fn(async (_req, res) => { + res.end(); + }) as NextApiHandler as Handler; + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { profile }); + await get(baseUrl, '/api/auth/me'); + expect(profile).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); + }); + + test('accept custom arbitrary handler', async () => { + const signup = jest.fn(async (_req, res) => { + res.end(); + }) as NextApiHandler as Handler; + const baseUrl = await setup(withoutApi); + global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { signup }); + await get(baseUrl, '/api/auth/signup'); + expect(signup).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); + }); + + test('accept custom login options', async () => { + const loginHandler = jest.fn(async (_req: any, res: any) => { + res.res.end(); + }); + jest.spyOn(baseLoginHandler, 'default').mockImplementation(() => loginHandler); + const options: LoginOptions = { authorizationParams: { scope: 'openid' } }; + const baseUrl = await setup(withoutApi); + const { handleLogin, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + login: handleLogin(options) + }); + await get(baseUrl, '/api/auth/login'); + expect(loginHandler).toHaveBeenCalledWith( + expect.objectContaining({ req: expect.any(IncomingMessage) }), + expect.objectContaining({ res: expect.any(ServerResponse) }), + options + ); + }); + + test('accept custom logout options', async () => { + const logoutHandler = jest.fn(async (_req: any, res: any) => { + res.res.end(); + }); + jest.spyOn(baseLogoutHandler, 'default').mockImplementation(() => logoutHandler); + const options: LogoutOptions = { returnTo: '/foo' }; + const baseUrl = await setup(withoutApi); + const { handleLogout, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + logout: handleLogout(options) + }); + await get(baseUrl, '/api/auth/logout'); + expect(logoutHandler).toHaveBeenCalledWith( + expect.objectContaining({ req: expect.any(IncomingMessage) }), + expect.objectContaining({ res: expect.any(ServerResponse) }), + options + ); + }); + + test('accept custom callback options', async () => { + const callbackHandler = jest.fn(async (_req: any, res: any) => { + res.res.end(); + }); + jest.spyOn(baseCallbackHandler, 'default').mockImplementation(() => callbackHandler); + const options: CallbackOptions = { redirectUri: '/foo' }; + const baseUrl = await setup(withoutApi); + const { handleCallback, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + callback: handleCallback(options) + }); + await get(baseUrl, '/api/auth/callback'); + expect(callbackHandler).toHaveBeenCalledWith( + expect.objectContaining({ req: expect.any(IncomingMessage) }), + expect.objectContaining({ res: expect.any(ServerResponse) }), + expect.objectContaining(options) + ); + }); + + test('accept custom profile options', async () => { + const afterRefetch = jest.fn(async (_req, _res, session) => session); + const options: ProfileOptions = { refetch: true, afterRefetch }; + const baseUrl = await setup(withoutApi); + const { handleProfile, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + profile: handleProfile(options) + }); + const cookieJar = await login(baseUrl); + await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(afterRefetch).toHaveBeenCalled(); + }); + + test('accept custom login options provider', async () => { + const loginHandler = jest.fn(async (_req: any, res: any) => { + res.res.end(); + }); + jest.spyOn(baseLoginHandler, 'default').mockImplementation(() => loginHandler); + const options = { authorizationParams: { scope: 'openid' } }; + const optionsProvider = jest.fn(() => options); + const baseUrl = await setup(withoutApi); + const { handleLogin, handleAuth } = initAuth0(withoutApi); + + global.handleAuth = handleAuth.bind(null, { + login: handleLogin(optionsProvider) + }); + await get(baseUrl, '/api/auth/login'); + expect(optionsProvider).toHaveBeenCalled(); + expect(loginHandler).toHaveBeenCalledWith( + expect.objectContaining({ req: expect.any(IncomingMessage) }), + expect.objectContaining({ res: expect.any(ServerResponse) }), + options + ); + }); + + test('accept custom logout options provider', async () => { + const logoutHandler = jest.fn(async (_req: any, res: any) => { + res.res.end(); + }); + jest.spyOn(baseLogoutHandler, 'default').mockImplementation(() => logoutHandler); + const options: LogoutOptions = { returnTo: '/foo' }; + const optionsProvider = jest.fn(() => options); + const baseUrl = await setup(withoutApi); + const { handleLogout, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + logout: handleLogout(optionsProvider) + }); + await get(baseUrl, '/api/auth/logout'); + expect(optionsProvider).toHaveBeenCalled(); + expect(logoutHandler).toHaveBeenCalledWith( + expect.objectContaining({ req: expect.any(IncomingMessage) }), + expect.objectContaining({ res: expect.any(ServerResponse) }), + options + ); + }); + + test('accept custom callback options provider', async () => { + const callbackHandler = jest.fn(async (_req: any, res: any) => { + res.res.end(); + }); + jest.spyOn(baseCallbackHandler, 'default').mockImplementation(() => callbackHandler); + const options: CallbackOptions = { redirectUri: '/foo' }; + const optionsProvider = jest.fn(() => options); + const baseUrl = await setup(withoutApi); + const { handleCallback, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + callback: handleCallback(optionsProvider) + }); + await get(baseUrl, '/api/auth/callback'); + expect(optionsProvider).toHaveBeenCalled(); + expect(callbackHandler).toHaveBeenCalledWith( + expect.objectContaining({ req: expect.any(IncomingMessage) }), + expect.objectContaining({ res: expect.any(ServerResponse) }), + expect.objectContaining(options) + ); + }); + + test('accept custom profile options provider', async () => { + const afterRefetch = jest.fn(async (_req, _res, session) => session); + const options: ProfileOptions = { refetch: true, afterRefetch }; + const optionsProvider = jest.fn(() => options); + const baseUrl = await setup(withoutApi); + const { handleProfile, handleAuth } = initAuth0(withoutApi); + global.handleAuth = handleAuth.bind(null, { + profile: handleProfile(optionsProvider) + }); + const cookieJar = await login(baseUrl); + await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(optionsProvider).toHaveBeenCalled(); + expect(afterRefetch).toHaveBeenCalled(); + }); +}); diff --git a/tests/handlers/auth.test.ts b/tests/handlers/auth.test.ts index 2f80610f8..a1da472e8 100644 --- a/tests/handlers/auth.test.ts +++ b/tests/handlers/auth.test.ts @@ -1,361 +1,70 @@ -import { IncomingMessage, ServerResponse } from 'http'; -import { ArgumentsOf } from 'ts-jest'; -import { withoutApi } from '../fixtures/default-settings'; -import { login, setup, teardown } from '../fixtures/setup'; -import { get } from '../auth0-session/fixtures/helpers'; -import { initAuth0, PageRouterOnError as OnError } from '../../src'; -import { LoginOptions, LogoutOptions, CallbackOptions, ProfileOptions } from '../../src/handlers'; -import * as baseLoginHandler from '../../src/auth0-session/handlers/login'; -import * as baseLogoutHandler from '../../src/auth0-session/handlers/logout'; -import * as baseCallbackHandler from '../../src/auth0-session/handlers/callback'; -import { Handler } from '../../src/handlers/router-helpers'; -import { NextApiHandler } from 'next'; +/** + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment + */ import { getResponse } from '../fixtures/app-router-helpers'; -const handlerError = () => - expect.objectContaining({ - status: 400, - code: 'ERR_CALLBACK_HANDLER_FAILURE' - }); - -describe('auth handler', () => { - describe('app router', () => { - test('return 500 for unexpected error', async () => { - await expect( - getResponse({ - url: '/api/auth/foo', - extraHandlers: { - foo: () => { - throw new Error(); - } - } - }) - ).resolves.toMatchObject({ status: 500 }); - }); - - test('return 404 for unknown routes', async () => { - await expect(getResponse({ url: '/api/auth/foo' })).resolves.toMatchObject({ status: 404 }); - }); - - test('return 404 for unknown routes including builtin props', async () => { - await expect(getResponse({ url: '/api/auth/__proto__' })).resolves.toMatchObject({ status: 404 }); - }); - - test('return 404 when routes have extra parts', async () => { - await expect(getResponse({ url: '/api/auth/me/foo.css' })).resolves.toMatchObject({ status: 404 }); - }); - - test('use default error handler', async () => { - jest.spyOn(console, 'error').mockImplementation(() => {}); - await expect( - getResponse({ - url: '/api/auth/foo', - extraHandlers: { foo: jest.fn().mockRejectedValue(new Error()), onError: undefined } - }) - ).resolves.toMatchObject({ status: 500 }); - expect(console.error).toHaveBeenCalledWith(expect.any(Error)); - }); - - test('accept custom error handler', async () => { - const onError = jest.fn(); - await expect( - getResponse({ - url: '/api/auth/foo', - extraHandlers: { - foo: jest.fn().mockRejectedValue(new Error()), - onError +describe('auth handler (app router)', () => { + test('return 500 for unexpected error', async () => { + await expect( + getResponse({ + url: '/api/auth/foo', + extraHandlers: { + foo: () => { + throw new Error(); } - }) - ).resolves.toMatchObject({ status: 500 }); - expect(onError).toHaveBeenCalledWith(expect.any(Request), expect.any(Error)); - }); - - test('accept custom error handler response', async () => { - const onError = jest.fn().mockReturnValue(new Response(null, { status: 418 })); - await expect( - getResponse({ - url: '/api/auth/foo', - extraHandlers: { - foo: jest.fn().mockRejectedValue(new Error()), - onError - } - }) - ).resolves.toMatchObject({ status: 418 }); - expect(onError).toHaveBeenCalled(); - }); + } + }) + ).resolves.toMatchObject({ status: 500 }); }); - describe('page router', () => { - afterEach(teardown); - - test('return 500 for unexpected error', async () => { - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth; - delete global.onError; - jest.spyOn(console, 'error').mockImplementation((error) => { - delete error.status; - }); - await expect(get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo')).rejects.toThrow( - 'Internal Server Error' - ); - }); - - test('return 404 for unknown routes', async () => { - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth; - await expect(get(baseUrl, '/api/auth/foo')).rejects.toThrow('Not Found'); - }); - - test('return 404 for unknown routes including builtin props', async () => { - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth; - await expect(get(baseUrl, '/api/auth/__proto__')).rejects.toThrow('Not Found'); - }); - - test('return 404 when routes have extra parts', async () => { - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth; - await expect(get(baseUrl, '/api/auth/me.css')).rejects.toThrow('Not Found'); - await expect(get(baseUrl, '/api/auth/me/foo.css')).rejects.toThrow('Not Found'); - await expect(get(baseUrl, '/api/auth/me/foo/bar.css')).rejects.toThrow('Not Found'); - }); - - test('accept custom error handler', async () => { - const onError = jest.fn>((_req, res) => res.end()); - const baseUrl = await setup(withoutApi, { onError }); - await get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo'); - expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError()); - }); - - test('use default error handler', async () => { - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth; - delete global.onError; - // eslint-disable-next-line @typescript-eslint/no-empty-function - jest.spyOn(console, 'error').mockImplementation(() => {}); - await expect(get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo')).rejects.toThrow( - 'Bad Request' - ); - expect(console.error).toHaveBeenCalledWith(handlerError()); - }); - - test('finish response if custom error does not', async () => { - const onError = jest.fn(); - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { onError }); - await expect( - get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo', { fullResponse: true }) - ).rejects.toThrow('Internal Server Error'); - expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError()); - }); - - test('finish response with custom error status', async () => { - const onError = jest.fn>((_req, res) => res.status(418)); - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { onError }); - await expect( - get(baseUrl, '/api/auth/callback?error=foo&error_description=bar&state=foo', { fullResponse: true }) - ).rejects.toThrow("I'm a Teapot"); - expect(onError).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse), handlerError()); - }); - - test('accept custom login handler', async () => { - const login = jest.fn(async (_req, res) => { - res.end(); - }) as NextApiHandler as Handler; - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { login }); - await get(baseUrl, '/api/auth/login'); - expect(login).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); - }); - - test('accept custom logout handler', async () => { - const logout = jest.fn(async (_req, res) => { - res.end(); - }) as NextApiHandler as Handler; - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { logout }); - await get(baseUrl, '/api/auth/logout'); - expect(logout).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); - }); - - test('accept custom callback handler', async () => { - const callback = jest.fn(async (_req, res) => { - res.end(); - }) as NextApiHandler as Handler; - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { callback }); - await get(baseUrl, '/api/auth/callback'); - expect(callback).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); - }); - - test('accept custom profile handler', async () => { - const profile = jest.fn(async (_req, res) => { - res.end(); - }) as NextApiHandler as Handler; - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { profile }); - await get(baseUrl, '/api/auth/me'); - expect(profile).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); - }); - - test('accept custom arbitrary handler', async () => { - const signup = jest.fn(async (_req, res) => { - res.end(); - }) as NextApiHandler as Handler; - const baseUrl = await setup(withoutApi); - global.handleAuth = initAuth0(withoutApi).handleAuth.bind(null, { signup }); - await get(baseUrl, '/api/auth/signup'); - expect(signup).toHaveBeenCalledWith(expect.any(IncomingMessage), expect.any(ServerResponse)); - }); - - test('accept custom login options', async () => { - const loginHandler = jest.fn(async (_req: any, res: any) => { - res.res.end(); - }); - jest.spyOn(baseLoginHandler, 'default').mockImplementation(() => loginHandler); - const options: LoginOptions = { authorizationParams: { scope: 'openid' } }; - const baseUrl = await setup(withoutApi); - const { handleLogin, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - login: handleLogin(options) - }); - await get(baseUrl, '/api/auth/login'); - expect(loginHandler).toHaveBeenCalledWith( - expect.objectContaining({ req: expect.any(IncomingMessage) }), - expect.objectContaining({ res: expect.any(ServerResponse) }), - options - ); - }); - - test('accept custom logout options', async () => { - const logoutHandler = jest.fn(async (_req: any, res: any) => { - res.res.end(); - }); - jest.spyOn(baseLogoutHandler, 'default').mockImplementation(() => logoutHandler); - const options: LogoutOptions = { returnTo: '/foo' }; - const baseUrl = await setup(withoutApi); - const { handleLogout, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - logout: handleLogout(options) - }); - await get(baseUrl, '/api/auth/logout'); - expect(logoutHandler).toHaveBeenCalledWith( - expect.objectContaining({ req: expect.any(IncomingMessage) }), - expect.objectContaining({ res: expect.any(ServerResponse) }), - options - ); - }); - - test('accept custom callback options', async () => { - const callbackHandler = jest.fn(async (_req: any, res: any) => { - res.res.end(); - }); - jest.spyOn(baseCallbackHandler, 'default').mockImplementation(() => callbackHandler); - const options: CallbackOptions = { redirectUri: '/foo' }; - const baseUrl = await setup(withoutApi); - const { handleCallback, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - callback: handleCallback(options) - }); - await get(baseUrl, '/api/auth/callback'); - expect(callbackHandler).toHaveBeenCalledWith( - expect.objectContaining({ req: expect.any(IncomingMessage) }), - expect.objectContaining({ res: expect.any(ServerResponse) }), - expect.objectContaining(options) - ); - }); - - test('accept custom profile options', async () => { - const afterRefetch = jest.fn(async (_req, _res, session) => session); - const options: ProfileOptions = { refetch: true, afterRefetch }; - const baseUrl = await setup(withoutApi); - const { handleProfile, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - profile: handleProfile(options) - }); - const cookieJar = await login(baseUrl); - await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(afterRefetch).toHaveBeenCalled(); - }); + test('return 404 for unknown routes', async () => { + await expect(getResponse({ url: '/api/auth/foo' })).resolves.toMatchObject({ status: 404 }); + }); - test('accept custom login options provider', async () => { - const loginHandler = jest.fn(async (_req: any, res: any) => { - res.res.end(); - }); - jest.spyOn(baseLoginHandler, 'default').mockImplementation(() => loginHandler); - const options = { authorizationParams: { scope: 'openid' } }; - const optionsProvider = jest.fn(() => options); - const baseUrl = await setup(withoutApi); - const { handleLogin, handleAuth } = initAuth0(withoutApi); + test('return 404 for unknown routes including builtin props', async () => { + await expect(getResponse({ url: '/api/auth/__proto__' })).resolves.toMatchObject({ status: 404 }); + }); - global.handleAuth = handleAuth.bind(null, { - login: handleLogin(optionsProvider) - }); - await get(baseUrl, '/api/auth/login'); - expect(optionsProvider).toHaveBeenCalled(); - expect(loginHandler).toHaveBeenCalledWith( - expect.objectContaining({ req: expect.any(IncomingMessage) }), - expect.objectContaining({ res: expect.any(ServerResponse) }), - options - ); - }); + test('return 404 when routes have extra parts', async () => { + await expect(getResponse({ url: '/api/auth/me/foo.css' })).resolves.toMatchObject({ status: 404 }); + }); - test('accept custom logout options provider', async () => { - const logoutHandler = jest.fn(async (_req: any, res: any) => { - res.res.end(); - }); - jest.spyOn(baseLogoutHandler, 'default').mockImplementation(() => logoutHandler); - const options: LogoutOptions = { returnTo: '/foo' }; - const optionsProvider = jest.fn(() => options); - const baseUrl = await setup(withoutApi); - const { handleLogout, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - logout: handleLogout(optionsProvider) - }); - await get(baseUrl, '/api/auth/logout'); - expect(optionsProvider).toHaveBeenCalled(); - expect(logoutHandler).toHaveBeenCalledWith( - expect.objectContaining({ req: expect.any(IncomingMessage) }), - expect.objectContaining({ res: expect.any(ServerResponse) }), - options - ); - }); + test('use default error handler', async () => { + jest.spyOn(console, 'error').mockImplementation(() => {}); + await expect( + getResponse({ + url: '/api/auth/foo', + extraHandlers: { foo: jest.fn().mockRejectedValue(new Error()), onError: undefined } + }) + ).resolves.toMatchObject({ status: 500 }); + expect(console.error).toHaveBeenCalledWith(expect.any(Error)); + }); - test('accept custom callback options provider', async () => { - const callbackHandler = jest.fn(async (_req: any, res: any) => { - res.res.end(); - }); - jest.spyOn(baseCallbackHandler, 'default').mockImplementation(() => callbackHandler); - const options: CallbackOptions = { redirectUri: '/foo' }; - const optionsProvider = jest.fn(() => options); - const baseUrl = await setup(withoutApi); - const { handleCallback, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - callback: handleCallback(optionsProvider) - }); - await get(baseUrl, '/api/auth/callback'); - expect(optionsProvider).toHaveBeenCalled(); - expect(callbackHandler).toHaveBeenCalledWith( - expect.objectContaining({ req: expect.any(IncomingMessage) }), - expect.objectContaining({ res: expect.any(ServerResponse) }), - expect.objectContaining(options) - ); - }); + test('accept custom error handler', async () => { + const onError = jest.fn(); + await expect( + getResponse({ + url: '/api/auth/foo', + extraHandlers: { + foo: jest.fn().mockRejectedValue(new Error()), + onError + } + }) + ).resolves.toMatchObject({ status: 500 }); + expect(onError).toHaveBeenCalledWith(expect.any(Request), expect.any(Error)); + }); - test('accept custom profile options provider', async () => { - const afterRefetch = jest.fn(async (_req, _res, session) => session); - const options: ProfileOptions = { refetch: true, afterRefetch }; - const optionsProvider = jest.fn(() => options); - const baseUrl = await setup(withoutApi); - const { handleProfile, handleAuth } = initAuth0(withoutApi); - global.handleAuth = handleAuth.bind(null, { - profile: handleProfile(optionsProvider) - }); - const cookieJar = await login(baseUrl); - await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(optionsProvider).toHaveBeenCalled(); - expect(afterRefetch).toHaveBeenCalled(); - }); + test('accept custom error handler response', async () => { + const onError = jest.fn().mockReturnValue(new Response(null, { status: 418 })); + await expect( + getResponse({ + url: '/api/auth/foo', + extraHandlers: { + foo: jest.fn().mockRejectedValue(new Error()), + onError + } + }) + ).resolves.toMatchObject({ status: 418 }); + expect(onError).toHaveBeenCalled(); }); }); diff --git a/tests/handlers/callback-page-router.test.ts b/tests/handlers/callback-page-router.test.ts new file mode 100644 index 000000000..cf22fd689 --- /dev/null +++ b/tests/handlers/callback-page-router.test.ts @@ -0,0 +1,460 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { CookieJar } from 'tough-cookie'; +import * as jose from 'jose'; +import timekeeper from 'timekeeper'; +import { withApi, withoutApi } from '../fixtures/default-settings'; +import { makeIdToken } from '../auth0-session/fixtures/cert'; +import { defaultConfig, get, post, toSignedCookieJar } from '../auth0-session/fixtures/helpers'; +import { encodeState } from '../../src/auth0-session/utils/encoding'; +import { defaultOnError, setup, teardown } from '../fixtures/setup'; +import { Session, AfterCallbackPageRoute, MissingStateCookieError } from '../../src'; +import nock from 'nock'; +import { signing } from '../../src/auth0-session/utils/hkdf'; + +const callback = (baseUrl: string, body: any, cookieJar?: CookieJar): Promise => + post(baseUrl, `/api/auth/callback`, { + body, + cookieJar, + fullResponse: true + }); + +const generateSignature = async (cookie: string, value: string): Promise => { + const key = await signing(defaultConfig.secret as string); + const { signature } = await new jose.FlattenedSign(new TextEncoder().encode(`${cookie}=${value}`)) + .setProtectedHeader({ alg: 'HS256', b64: false, crit: ['b64'] }) + .sign(key); + return signature; +}; + +describe('callback handler (page router)', () => { + afterEach(teardown); + + test('should require a state', async () => { + expect.assertions(2); + const baseUrl = await setup(withoutApi, { + onError(req, res, err) { + expect(err.cause).toBeInstanceOf(MissingStateCookieError); + defaultOnError(req, res, err); + } + }); + await expect( + callback(baseUrl, { + state: '__test_state__' + }) + ).rejects.toThrow( + 'Callback handler failed. CAUSE: Missing state cookie from login request (check login URL, callback URL and cookie config).' + ); + }); + + test('should validate the state', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = await toSignedCookieJar( + { + state: '__other_state__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state: '__test_state__' + }, + cookieJar + ) + ).rejects.toThrow('state mismatch, expected __other_state__, got: __test_state__'); + }); + + test('should validate the audience', async () => { + const baseUrl = await setup(withoutApi, { idTokenClaims: { aud: 'bar' } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ) + ).rejects.toThrow('aud mismatch, expected __test_client_id__, got: bar'); + }); + + test('should validate the issuer', async () => { + const baseUrl = await setup(withoutApi, { idTokenClaims: { aud: 'bar', iss: 'other-issuer' } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ) + ).rejects.toThrow('unexpected iss value, expected https://acme.auth0.local/, got: other-issuer'); + }); + + test('should escape html in error qp', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = await toSignedCookieJar( + { + state: `foo.${await generateSignature('state', 'foo')}` + }, + baseUrl + ); + await expect( + get(baseUrl, `/api/auth/callback?error=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E&state=foo`, { cookieJar }) + ).rejects.toThrow('<script>alert('xss')</script>'); + }); + + test('should create the session without OIDC claims', async () => { + const baseUrl = await setup(withoutApi); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const { res } = await callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ); + expect(res.statusCode).toBe(302); + const body = await get(baseUrl, `/api/session`, { cookieJar }); + expect(body.user).toStrictEqual({ + nickname: '__test_nickname__', + sub: '__test_sub__' + }); + }); + + test('should set the correct expiration', async () => { + timekeeper.freeze(0); + const baseUrl = await setup(withoutApi); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const { res } = await post(baseUrl, `/api/auth/callback`, { + fullResponse: true, + cookieJar, + body: { + state, + code: 'code' + } + }); + expect(res.statusCode).toBe(302); + + const [sessionCookie] = cookieJar.getCookiesSync(baseUrl); + const expiryInHrs = new Date(sessionCookie.expires).getTime() / 1000 / 60 / 60; + expect(expiryInHrs).toBe(24); + timekeeper.reset(); + }); + + test('should create the session without OIDC claims with api config', async () => { + timekeeper.freeze(0); + const baseUrl = await setup(withApi); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const { res } = await callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ); + expect(res.statusCode).toBe(302); + const session = await get(baseUrl, `/api/session`, { cookieJar }); + + expect(session).toStrictEqual({ + accessToken: 'eyJz93a...k4laUWw', + accessTokenExpiresAt: 750, + accessTokenScope: 'read:foo delete:foo', + token_type: 'Bearer', + refreshToken: 'GEbRxBN...edjnXbL', + idToken: await makeIdToken({ iss: 'https://acme.auth0.local/' }), + user: { + nickname: '__test_nickname__', + sub: '__test_sub__' + } + }); + timekeeper.reset(); + }); + + test('remove properties from session with afterCallback hook', async () => { + timekeeper.freeze(0); + const afterCallback: AfterCallbackPageRoute = ( + _req: NextApiRequest, + _res: NextApiResponse, + session: Session + ): Session => { + delete session.accessToken; + delete session.refreshToken; + return session; + }; + const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const { res } = await callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ); + expect(res.statusCode).toBe(302); + const session = await get(baseUrl, `/api/session`, { cookieJar }); + + expect(session).toStrictEqual({ + accessTokenExpiresAt: 750, + accessTokenScope: 'read:foo delete:foo', + idToken: await makeIdToken({ iss: 'https://acme.auth0.local/' }), + token_type: 'Bearer', + user: { + nickname: '__test_nickname__', + sub: '__test_sub__' + } + }); + timekeeper.reset(); + }); + + test('add properties to session with afterCallback hook', async () => { + timekeeper.freeze(0); + const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { + session.foo = 'bar'; + return session; + }; + const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const { res } = await callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ); + expect(res.statusCode).toBe(302); + const session = await get(baseUrl, '/api/session', { cookieJar }); + + expect(session).toMatchObject({ + foo: 'bar', + user: { + nickname: '__test_nickname__', + sub: '__test_sub__' + } + }); + timekeeper.reset(); + }); + + test('throws from afterCallback hook', async () => { + const afterCallback = (): Session => { + throw new Error('some validation error.'); + }; + const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ) + ).rejects.toThrow('some validation error.'); + }); + + test('throws for missing org_id claim', async () => { + const baseUrl = await setup({ ...withApi, organization: 'foo' }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ) + ).rejects.toThrow('Organization Id (org_id) claim must be a string present in the ID token'); + }); + + test('throws for org_id claim mismatch', async () => { + const baseUrl = await setup({ ...withApi, organization: 'foo' }, { idTokenClaims: { org_id: 'bar' } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ) + ).rejects.toThrow('Organization Id (org_id) claim value mismatch in the ID token; expected "foo", found "bar"'); + }); + + test('accepts a valid organization', async () => { + const baseUrl = await setup(withApi, { + idTokenClaims: { org_id: 'foo' }, + callbackOptions: { organization: 'foo' } + }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + await expect( + callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ) + ).resolves.not.toThrow(); + const session = await get(baseUrl, '/api/session', { cookieJar }); + + expect(session.user.org_id).toEqual('foo'); + }); + + test('should pass custom params to the token exchange', async () => { + const baseUrl = await setup(withoutApi, { + callbackOptions: { + authorizationParams: { foo: 'bar' } + } + }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const spy = jest.fn(); + + nock(`${withoutApi.issuerBaseURL}`) + .post('/oauth/token', /grant_type=authorization_code/) + .reply(200, async (_, body) => { + spy(body); + return { + access_token: 'eyJz93a...k4laUWw', + expires_in: 750, + scope: 'read:foo delete:foo', + refresh_token: 'GEbRxBN...edjnXbL', + id_token: await makeIdToken({ iss: `${withoutApi.issuerBaseURL}/` }), + token_type: 'Bearer' + }; + }); + + const { res } = await callback( + baseUrl, + { + state, + code: 'foobar' + }, + cookieJar + ); + expect(res.statusCode).toBe(302); + expect(spy).toHaveBeenCalledWith(expect.stringContaining('foo=bar')); + }); + + test('redirects from afterCallback hook', async () => { + const afterCallback = (_req: NextApiRequest, res: NextApiResponse): undefined => { + res.writeHead(302, '', { location: '/foo' }); + res.end(); + return; + }; + const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); + const state = encodeState({ returnTo: baseUrl }); + const cookieJar = await toSignedCookieJar( + { + state, + nonce: '__test_nonce__' + }, + baseUrl + ); + const { res } = await callback( + baseUrl, + { + state, + code: 'code' + }, + cookieJar + ); + expect(res.statusCode).toBe(302); + expect(res.headers.location).toBe('/foo'); + }); +}); diff --git a/tests/handlers/callback.test.ts b/tests/handlers/callback.test.ts index da7ea91db..eed9c33af 100644 --- a/tests/handlers/callback.test.ts +++ b/tests/handlers/callback.test.ts @@ -1,710 +1,260 @@ -import { NextApiRequest, NextApiResponse } from 'next'; +/** + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment + */ import { NextRequest, NextResponse } from 'next/server'; -import { CookieJar } from 'tough-cookie'; -import * as jose from 'jose'; -import timekeeper from 'timekeeper'; -import { withApi, withoutApi } from '../fixtures/default-settings'; -import { makeIdToken } from '../auth0-session/fixtures/cert'; -import { defaultConfig, get, post, signCookie, toSignedCookieJar } from '../auth0-session/fixtures/helpers'; +import { withApi } from '../fixtures/default-settings'; +import { signCookie } from '../auth0-session/fixtures/helpers'; import { encodeState } from '../../src/auth0-session/utils/encoding'; -import { defaultOnError, setup, teardown } from '../fixtures/setup'; -import { Session, AfterCallbackPageRoute, MissingStateCookieError } from '../../src'; -import nock from 'nock'; -import { signing } from '../../src/auth0-session/utils/hkdf'; -import { getResponse, getSession as getSessionFromRes } from '../fixtures/app-router-helpers'; - -const callback = (baseUrl: string, body: any, cookieJar?: CookieJar): Promise => - post(baseUrl, `/api/auth/callback`, { - body, - cookieJar, - fullResponse: true +import type { Session } from '../../src'; +import { getResponse, mockFetch, getSession as getSessionFromRes } from '../fixtures/app-router-helpers'; + +describe('callback handler (app router)', () => { + beforeEach(mockFetch); + + test('should require a state parameter', async () => { + const res = await getResponse({ + url: '/api/auth/callback', + cookies: { + state: await signCookie('state', 'foo') + } + }); + expect(res.status).toBe(400); + expect(res.statusText).toMatch(/Missing state parameter|response parameter "state" missing/); }); -const generateSignature = async (cookie: string, value: string): Promise => { - const key = await signing(defaultConfig.secret as string); - const { signature } = await new jose.FlattenedSign(new TextEncoder().encode(`${cookie}=${value}`)) - .setProtectedHeader({ alg: 'HS256', b64: false, crit: ['b64'] }) - .sign(key); - return signature; -}; - -describe('callback handler', () => { - describe('app router', () => { - test('should require a state parameter', async () => { - await expect(getResponse({ url: '/api/auth/callback' })).resolves.toMatchObject({ - status: 404, - statusText: expect.stringMatching(/Missing state parameter/) - }); + test('should require a state cookie', async () => { + const res = await getResponse({ + url: '/api/auth/callback?state=__test_state__' }); + expect(res.status).toBe(400); + expect(res.statusText).toMatch(/Missing state cookie from login request/); + }); - test('should require a state cookie', async () => { - await expect( - getResponse({ - url: '/api/auth/callback?state=__test_state__' - }) - ).resolves.toMatchObject({ - status: 400, - statusText: expect.stringMatching(/Missing state cookie from login request/) - }); + test('should validate the state', async () => { + const res = await getResponse({ + url: '/api/auth/callback?state=__test_state__', + cookies: { + state: await signCookie('state', 'other_state') + } }); + expect(res.status).toBe(400); + expect(res.statusText).toMatch( + /state mismatch, expected other_state, got: __test_state__|unexpected "state" response parameter value/ + ); + }); - test('should validate the state', async () => { - await expect( - getResponse({ - url: '/api/auth/callback?state=__test_state__', - cookies: { - state: await signCookie('state', 'other_state') - } - }) - ).resolves.toMatchObject({ - status: 400, - statusText: expect.stringMatching(/state mismatch, expected other_state, got: __test_state__/) - }); + test('should validate the audience', async () => { + const state = encodeState({ returnTo: 'https://example.com' }); + const res = await getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') + }, + idTokenClaims: { aud: 'bar' } }); + expect(res.status).toBe(400); + expect(res.statusText).toMatch( + /aud mismatch, expected __test_client_id__, got: bar|unexpected JWT "aud" \(audience\) claim value/ + ); + }); - test('should validate the audience', async () => { - const state = encodeState({ returnTo: 'https://example.com' }); - await expect( - getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - idTokenClaims: { aud: 'bar' } - }) - ).resolves.toMatchObject({ - status: 400, - statusText: expect.stringMatching(/aud mismatch, expected __test_client_id__, got: bar/) - }); + test('should validate the issuer', async () => { + const state = encodeState({ returnTo: 'https://example.com' }); + const res = await getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') + }, + idTokenClaims: { iss: 'other-issuer' } }); + expect(res.status).toBe(400); + expect(res.statusText).toMatch( + /unexpected iss value, expected https:\/\/acme.auth0.local\/, got: other-issuer|unexpected JWT "iss" \(issuer\) claim value/ + ); + }); - test('should validate the issuer', async () => { - const state = encodeState({ returnTo: 'https://example.com' }); - await expect( - getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - idTokenClaims: { iss: 'other-issuer' } - }) - ).resolves.toMatchObject({ - status: 400, - statusText: expect.stringMatching( - /unexpected iss value, expected https:\/\/acme.auth0.local\/, got: other-issuer/ - ) - }); + test('should escape html in error qp', async () => { + const res = await getResponse({ + url: '/api/auth/callback?error=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E&state=foo', + cookies: { + state: await signCookie('state', 'foo') + } }); + expect(res.status).toBe(400); + expect(res.statusText).toMatch(/<script>alert\('xss'\)<\/script>/); + }); - test('should escape html in error qp', async () => { - await expect( - getResponse({ - url: '/api/auth/callback?error=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E&state=foo', - cookies: { - state: await signCookie('state', 'foo') - } - }) - ).resolves.toMatchObject({ - status: 400, - statusText: expect.stringMatching(/<script>alert\('xss'\)<\/script>/) - }); + test('should create session and strip OIDC claims', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + const res = await getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') + } }); - - test('should create session and strip OIDC claims', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - const res = await getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - } - }); - expect(res.status).toEqual(302); - expect(res.headers.get('location')).toEqual('https://example.com/foo'); - const session = await getSessionFromRes(withApi, res); - expect(session).toMatchObject({ - user: { sub: '__test_sub__' }, - accessToken: expect.any(String) - }); - expect(session?.user).not.toHaveProperty('iss'); + expect(res.status).toEqual(302); + expect(res.headers.get('location')).toEqual('https://example.com/foo'); + const session = await getSessionFromRes(withApi, res); + expect(session).toMatchObject({ + user: { sub: '__test_sub__' }, + accessToken: expect.any(String) }); + expect(session?.user).not.toHaveProperty('iss'); + }); - test('remove properties from session with afterCallback hook', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - const res = await getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - delete session.accessToken; - return session; - } + test('remove properties from session with afterCallback hook', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + const res = await getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') + }, + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + delete session.accessToken; + return session; } - }); - expect(res.status).toEqual(302); - expect(res.headers.get('location')).toEqual('https://example.com/foo'); - const session = await getSessionFromRes(withApi, res); - expect(session).toMatchObject({ - user: { sub: '__test_sub__' } - }); - expect(session).not.toHaveProperty('accessToken'); + } + }); + expect(res.status).toEqual(302); + expect(res.headers.get('location')).toEqual('https://example.com/foo'); + const session = await getSessionFromRes(withApi, res); + expect(session).toMatchObject({ + user: { sub: '__test_sub__' } }); + expect(session).not.toHaveProperty('accessToken'); + }); - test('add properties to session with afterCallback hook', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - const res = await getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - return { ...session, foo: 'bar' }; - } + test('add properties to session with afterCallback hook', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + const res = await getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') + }, + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + return { ...session, foo: 'bar' }; } - }); - expect(res.status).toEqual(302); - expect(res.headers.get('location')).toEqual('https://example.com/foo'); - const session = await getSessionFromRes(withApi, res); - expect(session).toMatchObject({ - user: { sub: '__test_sub__' }, - foo: 'bar' - }); + } }); - - test('throws from afterCallback hook', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - await expect( - getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - callbackOpts: { - afterCallback() { - throw new Error('some validation error.'); - } - } - }) - ).resolves.toMatchObject({ status: 500, statusText: expect.stringMatching(/some validation error/) }); + expect(res.status).toEqual(302); + expect(res.headers.get('location')).toEqual('https://example.com/foo'); + const session = await getSessionFromRes(withApi, res); + expect(session).toMatchObject({ + user: { sub: '__test_sub__' }, + foo: 'bar' }); + }); - test('redirect from afterCallback hook', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - const res = await getResponse({ + test('throws from afterCallback hook', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + await expect( + getResponse({ url: `/api/auth/callback?state=${state}&code=code`, cookies: { state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') }, callbackOpts: { afterCallback() { - return NextResponse.redirect('https://example.com/foo'); + throw new Error('some validation error.'); } } - }); - expect(res.status).toBe(302); - expect(res.headers.get('location')).toBe('https://example.com/foo'); - }); - - test('throws for missing org_id claim', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - await expect( - getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - callbackOpts: { - organization: 'foo' - } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/Organization Id \(org_id\) claim must be a string present in the ID token/) - }); - }); - - test('throws for org_id claim mismatch', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - await expect( - getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - callbackOpts: { - organization: 'foo' - }, - idTokenClaims: { org_id: 'bar' } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching( - /Organization Id \(org_id\) claim value mismatch in the ID token; expected "foo", found "bar"/ - ) - }); - }); - - test('accepts a valid organization', async () => { - const state = encodeState({ returnTo: 'https://example.com/foo' }); - await expect( - getResponse({ - url: `/api/auth/callback?state=${state}&code=code`, - cookies: { - state: await signCookie('state', state), - nonce: await signCookie('nonce', '__test_nonce__') - }, - callbackOpts: { - organization: 'foo' - }, - idTokenClaims: { org_id: 'foo' } - }) - ).resolves.toMatchObject({ - status: 302 - }); - }); + }) + ).resolves.toMatchObject({ status: 500, statusText: expect.stringMatching(/some validation error/) }); }); - describe('page router', () => { - afterEach(teardown); - - test('should require a state', async () => { - expect.assertions(2); - const baseUrl = await setup(withoutApi, { - onError(req, res, err) { - expect(err.cause).toBeInstanceOf(MissingStateCookieError); - defaultOnError(req, res, err); - } - }); - await expect( - callback(baseUrl, { - state: '__test_state__' - }) - ).rejects.toThrow( - 'Callback handler failed. CAUSE: Missing state cookie from login request (check login URL, callback URL and cookie config).' - ); - }); - - test('should validate the state', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = await toSignedCookieJar( - { - state: '__other_state__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state: '__test_state__' - }, - cookieJar - ) - ).rejects.toThrow('state mismatch, expected __other_state__, got: __test_state__'); - }); - - test('should validate the audience', async () => { - const baseUrl = await setup(withoutApi, { idTokenClaims: { aud: 'bar' } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ) - ).rejects.toThrow('aud mismatch, expected __test_client_id__, got: bar'); - }); - - test('should validate the issuer', async () => { - const baseUrl = await setup(withoutApi, { idTokenClaims: { aud: 'bar', iss: 'other-issuer' } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ) - ).rejects.toThrow('unexpected iss value, expected https://acme.auth0.local/, got: other-issuer'); - }); - - test('should escape html in error qp', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = await toSignedCookieJar( - { - state: `foo.${await generateSignature('state', 'foo')}` - }, - baseUrl - ); - await expect( - get(baseUrl, `/api/auth/callback?error=%3Cscript%3Ealert(%27xss%27)%3C%2Fscript%3E&state=foo`, { cookieJar }) - ).rejects.toThrow('<script>alert('xss')</script>'); - }); - - test('should create the session without OIDC claims', async () => { - const baseUrl = await setup(withoutApi); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - const { res } = await callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ); - expect(res.statusCode).toBe(302); - const body = await get(baseUrl, `/api/session`, { cookieJar }); - expect(body.user).toStrictEqual({ - nickname: '__test_nickname__', - sub: '__test_sub__' - }); - }); - - test('should set the correct expiration', async () => { - timekeeper.freeze(0); - const baseUrl = await setup(withoutApi); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - const { res } = await post(baseUrl, `/api/auth/callback`, { - fullResponse: true, - cookieJar, - body: { - state, - code: 'code' + test('redirect from afterCallback hook', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + const res = await getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') + }, + callbackOpts: { + afterCallback() { + return NextResponse.redirect('https://example.com/foo'); } - }); - expect(res.statusCode).toBe(302); - - const [sessionCookie] = cookieJar.getCookiesSync(baseUrl); - const expiryInHrs = new Date(sessionCookie.expires).getTime() / 1000 / 60 / 60; - expect(expiryInHrs).toBe(24); - timekeeper.reset(); - }); - - test('should create the session without OIDC claims with api config', async () => { - timekeeper.freeze(0); - const baseUrl = await setup(withApi); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - const { res } = await callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ); - expect(res.statusCode).toBe(302); - const session = await get(baseUrl, `/api/session`, { cookieJar }); - - expect(session).toStrictEqual({ - accessToken: 'eyJz93a...k4laUWw', - accessTokenExpiresAt: 750, - accessTokenScope: 'read:foo delete:foo', - token_type: 'Bearer', - refreshToken: 'GEbRxBN...edjnXbL', - idToken: await makeIdToken({ iss: 'https://acme.auth0.local/' }), - user: { - nickname: '__test_nickname__', - sub: '__test_sub__' - } - }); - timekeeper.reset(); - }); - - test('remove properties from session with afterCallback hook', async () => { - timekeeper.freeze(0); - const afterCallback: AfterCallbackPageRoute = ( - _req: NextApiRequest, - _res: NextApiResponse, - session: Session - ): Session => { - delete session.accessToken; - delete session.refreshToken; - return session; - }; - const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - const { res } = await callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ); - expect(res.statusCode).toBe(302); - const session = await get(baseUrl, `/api/session`, { cookieJar }); - - expect(session).toStrictEqual({ - accessTokenExpiresAt: 750, - accessTokenScope: 'read:foo delete:foo', - idToken: await makeIdToken({ iss: 'https://acme.auth0.local/' }), - token_type: 'Bearer', - user: { - nickname: '__test_nickname__', - sub: '__test_sub__' - } - }); - timekeeper.reset(); + } }); + expect(res.status).toBe(302); + expect(res.headers.get('location')).toBe('https://example.com/foo'); + }); - test('add properties to session with afterCallback hook', async () => { - timekeeper.freeze(0); - const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { - session.foo = 'bar'; - return session; - }; - const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - const { res } = await callback( - baseUrl, - { - state, - code: 'code' + test('throws for missing org_id claim', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + await expect( + getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') }, - cookieJar - ); - expect(res.statusCode).toBe(302); - const session = await get(baseUrl, '/api/session', { cookieJar }); - - expect(session).toMatchObject({ - foo: 'bar', - user: { - nickname: '__test_nickname__', - sub: '__test_sub__' + callbackOpts: { + organization: 'foo' } - }); - timekeeper.reset(); - }); - - test('throws from afterCallback hook', async () => { - const afterCallback = (): Session => { - throw new Error('some validation error.'); - }; - const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ) - ).rejects.toThrow('some validation error.'); - }); - - test('throws for missing org_id claim', async () => { - const baseUrl = await setup({ ...withApi, organization: 'foo' }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ) - ).rejects.toThrow('Organization Id (org_id) claim must be a string present in the ID token'); - }); - - test('throws for org_id claim mismatch', async () => { - const baseUrl = await setup({ ...withApi, organization: 'foo' }, { idTokenClaims: { org_id: 'bar' } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ) - ).rejects.toThrow('Organization Id (org_id) claim value mismatch in the ID token; expected "foo", found "bar"'); - }); - - test('accepts a valid organization', async () => { - const baseUrl = await setup(withApi, { - idTokenClaims: { org_id: 'foo' }, - callbackOptions: { organization: 'foo' } - }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' - }, - baseUrl - ); - await expect( - callback( - baseUrl, - { - state, - code: 'code' - }, - cookieJar - ) - ).resolves.not.toThrow(); - const session = await get(baseUrl, '/api/session', { cookieJar }); - - expect(session.user.org_id).toEqual('foo'); + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/Organization Id \(org_id\) claim must be a string present in the ID token/) }); + }); - test('should pass custom params to the token exchange', async () => { - const baseUrl = await setup(withoutApi, { - callbackOptions: { - authorizationParams: { foo: 'bar' } - } - }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' + test('throws for org_id claim mismatch', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + await expect( + getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') }, - baseUrl - ); - const spy = jest.fn(); - - nock(`${withoutApi.issuerBaseURL}`) - .post('/oauth/token', /grant_type=authorization_code/) - .reply(200, async (_, body) => { - spy(body); - return { - access_token: 'eyJz93a...k4laUWw', - expires_in: 750, - scope: 'read:foo delete:foo', - refresh_token: 'GEbRxBN...edjnXbL', - id_token: await makeIdToken({ iss: `${withoutApi.issuerBaseURL}/` }), - token_type: 'Bearer' - }; - }); - - const { res } = await callback( - baseUrl, - { - state, - code: 'foobar' + callbackOpts: { + organization: 'foo' }, - cookieJar - ); - expect(res.statusCode).toBe(302); - expect(spy).toHaveBeenCalledWith(expect.stringContaining('foo=bar')); + idTokenClaims: { org_id: 'bar' } + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching( + /Organization Id \(org_id\) claim value mismatch in the ID token; expected "foo", found "bar"/ + ) }); + }); - test('redirects from afterCallback hook', async () => { - const afterCallback = (_req: NextApiRequest, res: NextApiResponse): undefined => { - res.writeHead(302, '', { location: '/foo' }); - res.end(); - return; - }; - const baseUrl = await setup(withApi, { callbackOptions: { afterCallback } }); - const state = encodeState({ returnTo: baseUrl }); - const cookieJar = await toSignedCookieJar( - { - state, - nonce: '__test_nonce__' + test('accepts a valid organization', async () => { + const state = encodeState({ returnTo: 'https://example.com/foo' }); + await expect( + getResponse({ + url: `/api/auth/callback?state=${state}&code=code`, + cookies: { + state: await signCookie('state', state), + nonce: await signCookie('nonce', '__test_nonce__'), + code_verifier: await signCookie('code_verifier', '__test_code_verifier__') }, - baseUrl - ); - const { res } = await callback( - baseUrl, - { - state, - code: 'code' + callbackOpts: { + organization: 'foo' }, - cookieJar - ); - expect(res.statusCode).toBe(302); - expect(res.headers.location).toBe('/foo'); + idTokenClaims: { org_id: 'foo' } + }) + ).resolves.toMatchObject({ + status: 302 }); }); }); diff --git a/tests/handlers/login-page-router.test.ts b/tests/handlers/login-page-router.test.ts new file mode 100644 index 000000000..340b84ddf --- /dev/null +++ b/tests/handlers/login-page-router.test.ts @@ -0,0 +1,331 @@ +import { parse as urlParse } from 'url'; +import { withoutApi, withApi } from '../fixtures/default-settings'; +import { decodeState } from '../../src/auth0-session/utils/encoding'; +import { setup, teardown } from '../fixtures/setup'; +import { get, getCookie } from '../auth0-session/fixtures/helpers'; +import { Cookie, CookieJar } from 'tough-cookie'; + +describe('login handler (page router)', () => { + afterEach(teardown); + + test('should create a state, nonce, and code verifier', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login', { cookieJar }); + + expect(cookieJar.getCookiesSync(baseUrl)).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + key: 'nonce', + value: expect.any(String), + path: '/', + sameSite: 'lax' + }), + expect.objectContaining({ + key: 'state', + value: expect.any(String), + path: '/', + sameSite: 'lax' + }), + expect.objectContaining({ + key: 'code_verifier', + value: expect.any(String), + path: '/', + sameSite: 'lax' + }) + ]) + ); + }); + + test('should add returnTo to the state', async () => { + const baseUrl = await setup(withoutApi, { loginOptions: { returnTo: '/custom-url' } }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login', { cookieJar }); + + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + expect(state).toBeTruthy(); + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toEqual('/custom-url'); + }); + + test('should redirect to the identity provider', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = new CookieJar(); + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); + + expect(statusCode).toBe(302); + + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + expect(urlParse(headers.location, true)).toMatchObject({ + protocol: 'https:', + host: 'acme.auth0.local', + hash: null, + query: { + client_id: '__test_client_id__', + scope: 'openid profile email', + response_type: 'code', + redirect_uri: 'http://www.acme.com/api/auth/callback', + nonce: expect.any(String), + state: state.split('.')[0], + code_challenge: expect.any(String), + code_challenge_method: 'S256' + }, + pathname: '/authorize' + }); + }); + + test('should allow sending custom parameters to the authorization server', async () => { + const loginOptions = { + authorizationParams: { + max_age: 123, + login_hint: 'foo@acme.com', + ui_locales: 'nl', + scope: 'some other scope openid', + foo: 'bar', + organization: 'foo', + invitation: 'bar' + } + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); + + expect(statusCode).toBe(302); + expect(urlParse(headers.location, true)).toMatchObject({ + query: { + ...loginOptions.authorizationParams, + max_age: '123' + } + }); + }); + + test('should pass organization config to the authorization server', async () => { + const baseUrl = await setup({ ...withoutApi, organization: 'foo' }); + const cookieJar = new CookieJar(); + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); + + expect(statusCode).toBe(302); + expect(urlParse(headers.location, true)).toMatchObject({ + query: { + organization: 'foo' + } + }); + }); + + test('should prefer organization auth param to config', async () => { + const baseUrl = await setup( + { ...withoutApi, organization: 'foo' }, + { loginOptions: { authorizationParams: { organization: 'bar' } } } + ); + const cookieJar = new CookieJar(); + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); + + expect(statusCode).toBe(302); + expect(urlParse(headers.location, true)).toMatchObject({ + query: { + organization: 'bar' + } + }); + }); + + test('should allow adding custom data to the state', async () => { + const loginOptions = { + getLoginState: (): Record => { + return { + foo: 'bar' + }; + } + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login', { cookieJar }); + + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + foo: 'bar', + returnTo: 'http://www.acme.com/' + }); + }); + + test('should merge returnTo and state', async () => { + const loginOptions = { + returnTo: '/profile', + getLoginState: (): Record => { + return { + foo: 'bar' + }; + } + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login', { cookieJar }); + + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + foo: 'bar', + returnTo: '/profile' + }); + }); + + test('should allow the getState method to overwrite returnTo', async () => { + const loginOptions = { + returnTo: '/profile', + getLoginState: (): Record => { + return { + foo: 'bar', + returnTo: '/foo' + }; + } + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login', { cookieJar }); + + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + foo: 'bar', + returnTo: '/foo' + }); + }); + + test('should allow the returnTo url to be provided in the querystring', async () => { + const loginOptions = { + returnTo: '/profile' + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login?returnTo=/foo', { cookieJar }); + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + returnTo: new URL('/foo', withoutApi.baseURL).toString() + }); + }); + + test('should take the first returnTo url provided in the querystring', async () => { + const loginOptions = { + returnTo: '/profile' + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login?returnTo=/foo&returnTo=/bar', { cookieJar }); + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + returnTo: new URL('/foo', withoutApi.baseURL).toString() + }); + }); + + test('should not allow absolute urls to be provided in the querystring', async () => { + const loginOptions = { + returnTo: '/default-redirect' + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login?returnTo=https://www.google.com', { cookieJar }); + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({}); + }); + + test('should allow absolute urls in params of returnTo urls', async () => { + const loginOptions = { + returnTo: '/default-redirect' + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login?returnTo=/foo?url=https://www.google.com', { cookieJar }); + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + returnTo: new URL('/foo?url=https://www.google.com', withoutApi.baseURL).toString() + }); + }); + + test('should redirect relative to the redirect_uri over the base url', async () => { + const loginOptions = { + returnTo: '/default-redirect', + authorizationParams: { + redirect_uri: 'https://other-org.acme.com/api/auth/callback' + } + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login?returnTo=/foo', { cookieJar }); + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + returnTo: 'https://other-org.acme.com/foo' + }); + }); + + test('should allow the returnTo to be be overwritten by getState() when provided in the querystring', async () => { + const loginOptions = { + returnTo: '/profile', + getLoginState: (): Record => { + return { + returnTo: '/foo' + }; + } + }; + const baseUrl = await setup(withoutApi, { loginOptions }); + const cookieJar = new CookieJar(); + await get(baseUrl, '/api/auth/login', { cookieJar }); + const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + returnTo: '/foo' + }); + }); + + test('should redirect to the identity provider with scope and audience', async () => { + const baseUrl = await setup(withApi); + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/login', { fullResponse: true }); + + expect(statusCode).toBe(302); + + expect(urlParse(headers.location, true).query).toMatchObject({ + scope: 'openid profile read:customer', + audience: 'https://api.acme.com' + }); + }); + + test('should handle login errors', async () => { + const baseUrl = await setup(withApi, { + loginOptions: { + getLoginState() { + return 1 as any; + } + } + }); + await expect(get(baseUrl, '/api/auth/login', { fullResponse: true })).rejects.toThrowError( + /Login handler failed. CAUSE: Custom state value must be an object/ + ); + }); +}); diff --git a/tests/handlers/login.test.ts b/tests/handlers/login.test.ts index 0ae67ec9b..1a77e6d74 100644 --- a/tests/handlers/login.test.ts +++ b/tests/handlers/login.test.ts @@ -1,556 +1,256 @@ +/** + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment + */ import { parse as urlParse } from 'url'; -import { withoutApi, withApi } from '../fixtures/default-settings'; import { decodeState } from '../../src/auth0-session/utils/encoding'; -import { setup, teardown } from '../fixtures/setup'; -import { get, getCookie } from '../auth0-session/fixtures/helpers'; -import { Cookie, CookieJar } from 'tough-cookie'; -import { getResponse } from '../fixtures/app-router-helpers'; +import { getResponse, mockFetch } from '../fixtures/app-router-helpers'; -describe('login handler', () => { - describe('app router', () => { - test('should create a state', async () => { - const res = await getResponse({ - url: '/api/auth/login' - }); - expect(res.cookies.get('nonce')).toMatchObject({ - value: expect.any(String), - path: '/', - sameSite: 'lax' - }); - expect(res.cookies.get('state')).toMatchObject({ - value: expect.any(String), - path: '/', - sameSite: 'lax' - }); - expect(res.cookies.get('code_verifier')).toMatchObject({ - value: expect.any(String), - path: '/', - sameSite: 'lax' - }); - }); +describe('login handler (app router)', () => { + beforeEach(mockFetch); - test('should add returnTo to the state', async () => { - const res = await getResponse({ - url: '/api/auth/login', - loginOpts: { returnTo: '/custom-url' } - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toEqual('/custom-url'); + test('should create a state', async () => { + const res = await getResponse({ + url: '/api/auth/login' }); - - test('should redirect to the identity provider', async () => { - const res = await getResponse({ - url: '/api/auth/login' - }); - const { value: state } = res.cookies.get('state'); - expect(urlParse(res.headers.get('location'), true)).toMatchObject({ - protocol: 'https:', - host: 'acme.auth0.local', - hash: null, - query: { - client_id: '__test_client_id__', - scope: 'openid profile read:customer', - response_type: 'code', - redirect_uri: 'http://www.acme.com/api/auth/callback', - nonce: expect.any(String), - state: state.split('.')[0], - code_challenge: expect.any(String), - code_challenge_method: 'S256' - }, - pathname: '/authorize' - }); + expect(res.cookies.get('nonce')).toMatchObject({ + value: expect.any(String), + path: '/', + sameSite: 'lax' }); - - test('should allow sending custom parameters to the authorization server', async () => { - const loginOpts = { - authorizationParams: { - max_age: 123, - login_hint: 'foo@acme.com', - ui_locales: 'nl', - scope: 'some other scope openid', - foo: 'bar', - organization: 'foo', - invitation: 'bar' - } - }; - const res = await getResponse({ - url: '/api/auth/login', - loginOpts - }); - expect(res.status).toBe(302); - expect(urlParse(res.headers.get('location'), true)).toMatchObject({ - query: { - ...loginOpts.authorizationParams, - max_age: '123' - } - }); + expect(res.cookies.get('state')).toMatchObject({ + value: expect.any(String), + path: '/', + sameSite: 'lax' }); - - test('should pass organization config to the authorization server', async () => { - const res = await getResponse({ - url: '/api/auth/login', - config: { organization: 'foo' } - }); - expect(res.status).toBe(302); - expect(urlParse(res.headers.get('location'), true).query).toMatchObject({ - organization: 'foo' - }); - }); - - test('should prefer organization auth param to config', async () => { - const res = await getResponse({ - url: '/api/auth/login', - config: { organization: 'foo' }, - loginOpts: { authorizationParams: { organization: 'bar' } } - }); - expect(res.status).toBe(302); - expect(urlParse(res.headers.get('location'), true).query).toMatchObject({ - organization: 'bar' - }); + expect(res.cookies.get('code_verifier')).toMatchObject({ + value: expect.any(String), + path: '/', + sameSite: 'lax' }); + }); - test('should allow adding custom data to the state', async () => { - const res = await getResponse({ - url: '/api/auth/login', - loginOpts: { - getLoginState() { - return { foo: 'bar' }; - } - } - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - foo: 'bar', - returnTo: 'http://www.acme.com/' - }); + test('should add returnTo to the state', async () => { + const res = await getResponse({ + url: '/api/auth/login', + loginOpts: { returnTo: '/custom-url' } }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toEqual('/custom-url'); + }); - test('should merge returnTo and state', async () => { - const res = await getResponse({ - url: '/api/auth/login', - loginOpts: { - returnTo: '/profile', - getLoginState() { - return { foo: 'bar' }; - } - } - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - foo: 'bar', - returnTo: '/profile' - }); + test('should redirect to the identity provider', async () => { + const res = await getResponse({ + url: '/api/auth/login' + }); + const { value: state } = res.cookies.get('state'); + expect(urlParse(res.headers.get('location'), true)).toMatchObject({ + protocol: 'https:', + host: 'acme.auth0.local', + hash: null, + query: { + client_id: '__test_client_id__', + scope: 'openid profile read:customer', + response_type: 'code', + redirect_uri: 'http://www.acme.com/api/auth/callback', + nonce: expect.any(String), + state: state.split('.')[0], + code_challenge: expect.any(String), + code_challenge_method: 'S256' + }, + pathname: '/authorize' }); + }); - test('should allow the getState method to overwrite returnTo', async () => { - const res = await getResponse({ - url: '/api/auth/login', - loginOpts: { - returnTo: '/profile', - getLoginState() { - return { foo: 'bar', returnTo: '/bar' }; - } - } - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ + test('should allow sending custom parameters to the authorization server', async () => { + const loginOpts = { + authorizationParams: { + max_age: 123, + login_hint: 'foo@acme.com', + ui_locales: 'nl', + scope: 'some other scope openid', foo: 'bar', - returnTo: '/bar' - }); + organization: 'foo', + invitation: 'bar' + } + }; + const res = await getResponse({ + url: '/api/auth/login', + loginOpts + }); + expect(res.status).toBe(302); + expect(urlParse(res.headers.get('location'), true)).toMatchObject({ + query: { + ...loginOpts.authorizationParams, + max_age: '123' + } }); + }); - test('should allow the returnTo url to be provided in the querystring', async () => { - const res = await getResponse({ - url: '/api/auth/login?returnTo=/from-query' - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toEqual('http://www.acme.com/from-query'); + test('should pass organization config to the authorization server', async () => { + const res = await getResponse({ + url: '/api/auth/login', + config: { organization: 'foo' } }); - - test('should take the first returnTo url provided in the querystring', async () => { - const res = await getResponse({ - url: '/api/auth/login?returnTo=/foo&returnTo=bar' - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toEqual('http://www.acme.com/foo'); - }); - - test('should not allow absolute urls to be provided in the querystring', async () => { - const res = await getResponse({ - url: '/api/auth/login?returnTo=https://evil.com' - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toBeUndefined(); + expect(res.status).toBe(302); + expect(urlParse(res.headers.get('location'), true).query).toMatchObject({ + organization: 'foo' }); + }); - test('should allow absolute urls in params of returnTo urls', async () => { - const res = await getResponse({ - url: '/api/auth/login', - loginOpts: { returnTo: 'https://google.com' } - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toBe('https://google.com'); + test('should prefer organization auth param to config', async () => { + const res = await getResponse({ + url: '/api/auth/login', + config: { organization: 'foo' }, + loginOpts: { authorizationParams: { organization: 'bar' } } }); - - test('should redirect relative to the redirect_uri over the base url', async () => { - const loginOpts = { - authorizationParams: { - redirect_uri: 'https://other-org.acme.com/api/auth/callback' - } - }; - const res = await getResponse({ - url: '/api/auth/login?returnTo=/bar', - loginOpts - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toBe('https://other-org.acme.com/bar'); + expect(res.status).toBe(302); + expect(urlParse(res.headers.get('location'), true).query).toMatchObject({ + organization: 'bar' }); + }); - test('should allow the returnTo to be be overwritten by getState() when provided in the querystring', async () => { - const res = await getResponse({ - url: '/api/auth/login?returnTo=/foo', - loginOpts: { - getLoginState() { - return { returnTo: '/bar' }; - } + test('should allow adding custom data to the state', async () => { + const res = await getResponse({ + url: '/api/auth/login', + loginOpts: { + getLoginState() { + return { foo: 'bar' }; } - }); - const { value: state } = res.cookies.get('state'); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toBe('/bar'); + } }); - - test('should redirect to the identity provider with scope and audience', async () => { - const res = await getResponse({ - config: { authorizationParams: { scope: 'openid profile foobar', audience: 'https://api.acme.com/foo' } }, - url: '/api/auth/login' - }); - expect(res.status).toBe(302); - expect(urlParse(res.headers.get('location'), true).query).toMatchObject({ - scope: 'openid profile foobar', - audience: 'https://api.acme.com/foo' - }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + foo: 'bar', + returnTo: 'http://www.acme.com/' }); }); - describe('page router', () => { - afterEach(teardown); - - test('should create a state', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login', { cookieJar }); - - expect(cookieJar.getCookiesSync(baseUrl)).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - key: 'nonce', - value: expect.any(String), - path: '/', - sameSite: 'lax' - }), - expect.objectContaining({ - key: 'state', - value: expect.any(String), - path: '/', - sameSite: 'lax' - }), - expect.objectContaining({ - key: 'code_verifier', - value: expect.any(String), - path: '/', - sameSite: 'lax' - }) - ]) - ); - }); - - test('should add returnTo to the state', async () => { - const baseUrl = await setup(withoutApi, { loginOptions: { returnTo: '/custom-url' } }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login', { cookieJar }); - - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - expect(state).toBeTruthy(); - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState?.returnTo).toEqual('/custom-url'); - }); - - test('should redirect to the identity provider', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = new CookieJar(); - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); - - expect(statusCode).toBe(302); - - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - expect(urlParse(headers.location, true)).toMatchObject({ - protocol: 'https:', - host: 'acme.auth0.local', - hash: null, - query: { - client_id: '__test_client_id__', - scope: 'openid profile email', - response_type: 'code', - redirect_uri: 'http://www.acme.com/api/auth/callback', - nonce: expect.any(String), - state: state.split('.')[0], - code_challenge: expect.any(String), - code_challenge_method: 'S256' - }, - pathname: '/authorize' - }); - }); - - test('should allow sending custom parameters to the authorization server', async () => { - const loginOptions = { - authorizationParams: { - max_age: 123, - login_hint: 'foo@acme.com', - ui_locales: 'nl', - scope: 'some other scope openid', - foo: 'bar', - organization: 'foo', - invitation: 'bar' - } - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); - - expect(statusCode).toBe(302); - expect(urlParse(headers.location, true)).toMatchObject({ - query: { - ...loginOptions.authorizationParams, - max_age: '123' + test('should merge returnTo and state', async () => { + const res = await getResponse({ + url: '/api/auth/login', + loginOpts: { + returnTo: '/profile', + getLoginState() { + return { foo: 'bar' }; } - }); + } }); - - test('should pass organization config to the authorization server', async () => { - const baseUrl = await setup({ ...withoutApi, organization: 'foo' }); - const cookieJar = new CookieJar(); - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); - - expect(statusCode).toBe(302); - expect(urlParse(headers.location, true)).toMatchObject({ - query: { - organization: 'foo' - } - }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + foo: 'bar', + returnTo: '/profile' }); + }); - test('should prefer organization auth param to config', async () => { - const baseUrl = await setup( - { ...withoutApi, organization: 'foo' }, - { loginOptions: { authorizationParams: { organization: 'bar' } } } - ); - const cookieJar = new CookieJar(); - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/login', { cookieJar, fullResponse: true }); - - expect(statusCode).toBe(302); - expect(urlParse(headers.location, true)).toMatchObject({ - query: { - organization: 'bar' + test('should allow the getState method to overwrite returnTo', async () => { + const res = await getResponse({ + url: '/api/auth/login', + loginOpts: { + returnTo: '/profile', + getLoginState() { + return { foo: 'bar', returnTo: '/bar' }; } - }); + } }); - - test('should allow adding custom data to the state', async () => { - const loginOptions = { - getLoginState: (): Record => { - return { - foo: 'bar' - }; - } - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login', { cookieJar }); - - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - foo: 'bar', - returnTo: 'http://www.acme.com/' - }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState).toEqual({ + foo: 'bar', + returnTo: '/bar' }); + }); - test('should merge returnTo and state', async () => { - const loginOptions = { - returnTo: '/profile', - getLoginState: (): Record => { - return { - foo: 'bar' - }; - } - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login', { cookieJar }); - - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - foo: 'bar', - returnTo: '/profile' - }); + test('should allow the returnTo url to be provided in the querystring', async () => { + const res = await getResponse({ + url: '/api/auth/login?returnTo=/from-query' }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toEqual('http://www.acme.com/from-query'); + }); - test('should allow the getState method to overwrite returnTo', async () => { - const loginOptions = { - returnTo: '/profile', - getLoginState: (): Record => { - return { - foo: 'bar', - returnTo: '/foo' - }; - } - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login', { cookieJar }); - - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - foo: 'bar', - returnTo: '/foo' - }); + test('should take the first returnTo url provided in the querystring', async () => { + const res = await getResponse({ + url: '/api/auth/login?returnTo=/foo&returnTo=bar' }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toEqual('http://www.acme.com/foo'); + }); - test('should allow the returnTo url to be provided in the querystring', async () => { - const loginOptions = { - returnTo: '/profile' - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login?returnTo=/foo', { cookieJar }); - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - returnTo: new URL('/foo', withoutApi.baseURL).toString() - }); + test('should not allow absolute urls to be provided in the querystring', async () => { + const res = await getResponse({ + url: '/api/auth/login?returnTo=https://evil.com' }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toBeUndefined(); + }); - test('should take the first returnTo url provided in the querystring', async () => { - const loginOptions = { - returnTo: '/profile' - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login?returnTo=/foo&returnTo=/bar', { cookieJar }); - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - returnTo: new URL('/foo', withoutApi.baseURL).toString() - }); + test('should allow absolute urls in params of returnTo urls', async () => { + const res = await getResponse({ + url: '/api/auth/login', + loginOpts: { returnTo: 'https://google.com' } }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toBe('https://google.com'); + }); - test('should not allow absolute urls to be provided in the querystring', async () => { - const loginOptions = { - returnTo: '/default-redirect' - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login?returnTo=https://www.google.com', { cookieJar }); - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; + test('should redirect relative to the redirect_uri over the base url', async () => { + const loginOpts = { + authorizationParams: { + redirect_uri: 'https://other-org.acme.com/api/auth/callback' + } + }; + const res = await getResponse({ + url: '/api/auth/login?returnTo=/bar', + loginOpts + }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toBe('https://other-org.acme.com/bar'); + }); - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({}); + test('should allow the returnTo to be be overwritten by getState() when provided in the querystring', async () => { + const res = await getResponse({ + url: '/api/auth/login?returnTo=/foo', + loginOpts: { + getLoginState() { + return { returnTo: '/bar' }; + } + } }); + const { value: state } = res.cookies.get('state'); + const decodedState = decodeState(state.split('.')[0]); + expect(decodedState?.returnTo).toBe('/bar'); + }); - test('should allow absolute urls in params of returnTo urls', async () => { - const loginOptions = { - returnTo: '/default-redirect' - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login?returnTo=/foo?url=https://www.google.com', { cookieJar }); - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - returnTo: new URL('/foo?url=https://www.google.com', withoutApi.baseURL).toString() - }); + test('should redirect to the identity provider with scope and audience', async () => { + const res = await getResponse({ + config: { authorizationParams: { scope: 'openid profile foobar', audience: 'https://api.acme.com/foo' } }, + url: '/api/auth/login' }); - - test('should redirect relative to the redirect_uri over the base url', async () => { - const loginOptions = { - returnTo: '/default-redirect', - authorizationParams: { - redirect_uri: 'https://other-org.acme.com/api/auth/callback' - } - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login?returnTo=/foo', { cookieJar }); - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - returnTo: 'https://other-org.acme.com/foo' - }); + expect(res.status).toBe(302); + expect(urlParse(res.headers.get('location'), true).query).toMatchObject({ + scope: 'openid profile foobar', + audience: 'https://api.acme.com/foo' }); + }); - test('should allow the returnTo to be be overwritten by getState() when provided in the querystring', async () => { - const loginOptions = { - returnTo: '/profile', - getLoginState: (): Record => { - return { - returnTo: '/foo' - }; + test('should handle login errors', async () => { + const res = await getResponse({ + loginOpts: { + getLoginState() { + return 1 as any; } - }; - const baseUrl = await setup(withoutApi, { loginOptions }); - const cookieJar = new CookieJar(); - await get(baseUrl, '/api/auth/login', { cookieJar }); - const { value: state } = getCookie('state', cookieJar, baseUrl) as Cookie; - - const decodedState = decodeState(state.split('.')[0]); - expect(decodedState).toEqual({ - returnTo: '/foo' - }); - }); - - test('should redirect to the identity provider with scope and audience', async () => { - const baseUrl = await setup(withApi); - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/login', { fullResponse: true }); - - expect(statusCode).toBe(302); - - expect(urlParse(headers.location, true).query).toMatchObject({ - scope: 'openid profile read:customer', - audience: 'https://api.acme.com' - }); + }, + url: '/api/auth/login' }); + expect(res.status).toBe(500); + expect(res.statusText).toMatch(/Login handler failed. CAUSE: Custom state value must be an object/); }); }); diff --git a/tests/handlers/logout-page-router.test.ts b/tests/handlers/logout-page-router.test.ts new file mode 100644 index 000000000..d595c72f5 --- /dev/null +++ b/tests/handlers/logout-page-router.test.ts @@ -0,0 +1,152 @@ +import { parse } from 'cookie'; +import { parse as parseUrl } from 'url'; +import { withoutApi } from '../fixtures/default-settings'; +import { get } from '../auth0-session/fixtures/helpers'; +import { setup, teardown, login } from '../fixtures/setup'; +import { ServerResponse } from 'http'; + +describe('logout handler (page router)', () => { + afterEach(teardown); + + test('should redirect to auth0', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = await login(baseUrl); + + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/logout', { + cookieJar, + fullResponse: true + }); + + expect(statusCode).toBe(302); + expect(parseUrl(headers['location'], true)).toMatchObject({ + protocol: 'https:', + host: 'acme.auth0.local', + query: { + returnTo: 'http://www.acme.com', + client_id: '__test_client_id__' + }, + pathname: '/v2/logout' + }); + }); + + test('should pass logout params to auth0', async () => { + const baseUrl = await setup(withoutApi, { logoutOptions: { logoutParams: { foo: 'bar' } } }); + const cookieJar = await login(baseUrl); + + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/logout', { + cookieJar, + fullResponse: true + }); + + expect(statusCode).toBe(302); + expect(parseUrl(headers['location'], true)).toMatchObject({ + protocol: 'https:', + host: 'acme.auth0.local', + query: { + returnTo: 'http://www.acme.com', + client_id: '__test_client_id__', + foo: 'bar' + }, + pathname: '/v2/logout' + }); + }); + + test('should return to the custom path', async () => { + const customReturnTo = 'https://www.foo.bar'; + const baseUrl = await setup(withoutApi, { + logoutOptions: { returnTo: customReturnTo } + }); + const cookieJar = await login(baseUrl); + + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/logout', { + cookieJar, + fullResponse: true + }); + + expect(statusCode).toBe(302); + expect(parseUrl(headers['location'], true).query).toMatchObject({ + returnTo: 'https://www.foo.bar' + }); + }); + + test('should use end_session_endpoint when configured', async () => { + const baseUrl = await setup( + { ...withoutApi, auth0Logout: false }, + { + discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } + } + ); + const cookieJar = await login(baseUrl); + + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/logout', { + cookieJar, + fullResponse: true + }); + + expect(statusCode).toBe(302); + expect(parseUrl(headers['location'])).toMatchObject({ + host: 'my-end-session-endpoint', + pathname: '/logout' + }); + }); + + test('should use auth0 logout by default even when end_session_endpoint is discovered', async () => { + const baseUrl = await setup(withoutApi, { + discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } + }); + const cookieJar = await login(baseUrl); + + const { + res: { statusCode, headers } + } = await get(baseUrl, '/api/auth/logout', { + cookieJar, + fullResponse: true + }); + + expect(statusCode).toBe(302); + expect(parseUrl(headers['location'])).toMatchObject({ + host: 'acme.auth0.local', + pathname: '/v2/logout' + }); + }); + + test('should delete the session', async () => { + const baseUrl = await setup(withoutApi, { + discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } + }); + const cookieJar = await login(baseUrl); + + const { + res: { headers } + } = await get(baseUrl, '/api/auth/logout', { + cookieJar, + fullResponse: true + }); + + expect(parse(headers['set-cookie'][0])).toMatchObject({ + appSession: '', + 'Max-Age': '0', + Path: '/' + }); + }); + + test('should delete tshe session', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = await login(baseUrl); + + jest.spyOn(ServerResponse.prototype, 'writeHead').mockImplementationOnce(() => { + throw new Error('write err'); + }); + await expect(get(baseUrl, '/api/auth/logout', { cookieJar })).rejects.toThrowError( + /Logout handler failed. CAUSE: write err/ + ); + }); +}); diff --git a/tests/handlers/logout.test.ts b/tests/handlers/logout.test.ts index 9b4810029..4949ac07d 100644 --- a/tests/handlers/logout.test.ts +++ b/tests/handlers/logout.test.ts @@ -1,229 +1,108 @@ -import { parse } from 'cookie'; +/** + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment + */ import { parse as parseUrl } from 'url'; -import { withoutApi } from '../fixtures/default-settings'; -import { get } from '../auth0-session/fixtures/helpers'; -import { setup, teardown, login } from '../fixtures/setup'; -import { getResponse, login as appRouterLogin } from '../fixtures/app-router-helpers'; - -describe('logout handler', () => { - describe('app router', () => { - test('should redirect to auth0', async () => { - const loginRes = await appRouterLogin(); - const cookies = { appSession: loginRes.cookies.get('appSession').value }; - const res = await getResponse({ url: '/api/auth/logout', cookies }); - expect(res.status).toBe(302); - expect(parseUrl(res.headers.get('location'), true)).toMatchObject({ - protocol: 'https:', - host: 'acme.auth0.local', - query: { - returnTo: 'http://www.acme.com', - client_id: '__test_client_id__' - }, - pathname: '/v2/logout' - }); - }); - - test('should pass logout params to auth0', async () => { - const loginRes = await appRouterLogin(); - const cookies = { appSession: loginRes.cookies.get('appSession').value }; - const res = await getResponse({ - url: '/api/auth/logout', - cookies, - logoutOpts: { logoutParams: { foo: 'bar' } } - }); - expect(res.status).toBe(302); - expect(parseUrl(res.headers.get('location'), true).query).toMatchObject({ +import { withApi } from '../fixtures/default-settings'; +import { getResponse, login as appRouterLogin, mockFetch } from '../fixtures/app-router-helpers'; +import nock from 'nock'; +import { discovery } from '../fixtures/oidc-nocks'; + +describe('logout handler (app router)', () => { + beforeEach(mockFetch); + + test('should redirect to auth0', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + const res = await getResponse({ url: '/api/auth/logout', cookies }); + expect(res.status).toBe(302); + expect(parseUrl(res.headers.get('location'), true)).toMatchObject({ + protocol: 'https:', + host: 'acme.auth0.local', + query: { returnTo: 'http://www.acme.com', - client_id: '__test_client_id__', - foo: 'bar' - }); + client_id: '__test_client_id__' + }, + pathname: '/v2/logout' }); + }); - test('should return to the custom path', async () => { - const loginRes = await appRouterLogin(); - const cookies = { appSession: loginRes.cookies.get('appSession').value }; - const res = await getResponse({ - url: '/api/auth/logout', - cookies, - logoutOpts: { returnTo: 'https://www.google.com' } - }); - expect(res.status).toBe(302); - expect(parseUrl(res.headers.get('location'), true).query).toMatchObject({ - returnTo: 'https://www.google.com' - }); + test('should pass logout params to auth0', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + const res = await getResponse({ + url: '/api/auth/logout', + cookies, + logoutOpts: { logoutParams: { foo: 'bar' } } }); - - test('should use end_session_endpoint when configured', async () => { - const loginRes = await appRouterLogin(); - const cookies = { appSession: loginRes.cookies.get('appSession').value }; - const res = await getResponse({ - url: '/api/auth/logout', - cookies, - config: { auth0Logout: false }, - discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } - }); - expect(res.status).toBe(302); - expect(parseUrl(res.headers.get('location'))).toMatchObject({ - host: 'my-end-session-endpoint', - pathname: '/logout' - }); + expect(res.status).toBe(302); + expect(parseUrl(res.headers.get('location'), true).query).toMatchObject({ + returnTo: 'http://www.acme.com', + client_id: '__test_client_id__', + foo: 'bar' }); + }); - test('should use auth0 logout by default even when end_session_endpoint is discovered', async () => { - const loginRes = await appRouterLogin(); - const cookies = { appSession: loginRes.cookies.get('appSession').value }; - const res = await getResponse({ - url: '/api/auth/logout', - cookies, - discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } - }); - expect(res.status).toBe(302); - expect(parseUrl(res.headers.get('location'))).toMatchObject({ - host: 'acme.auth0.local', - pathname: '/v2/logout' - }); + test('should return to the custom path', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + const res = await getResponse({ + url: '/api/auth/logout', + cookies, + logoutOpts: { returnTo: 'https://www.google.com' } }); - - test('should delete the session', async () => { - const loginRes = await appRouterLogin(); - const cookies = { appSession: loginRes.cookies.get('appSession').value }; - const res = await getResponse({ url: '/api/auth/logout', cookies }); - expect(res.status).toBe(302); - expect(new Date(res.cookies.get('appSession').expires).getTime()).toBe(0); + expect(res.status).toBe(302); + expect(parseUrl(res.headers.get('location'), true).query).toMatchObject({ + returnTo: 'https://www.google.com' }); }); - describe('page router', () => { - afterEach(teardown); - - test('should redirect to auth0', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = await login(baseUrl); - - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/logout', { - cookieJar, - fullResponse: true - }); - - expect(statusCode).toBe(302); - expect(parseUrl(headers['location'], true)).toMatchObject({ - protocol: 'https:', - host: 'acme.auth0.local', - query: { - returnTo: 'http://www.acme.com', - client_id: '__test_client_id__' - }, - pathname: '/v2/logout' - }); - }); - - test('should pass logout params to auth0', async () => { - const baseUrl = await setup(withoutApi, { logoutOptions: { logoutParams: { foo: 'bar' } } }); - const cookieJar = await login(baseUrl); - - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/logout', { - cookieJar, - fullResponse: true - }); - - expect(statusCode).toBe(302); - expect(parseUrl(headers['location'], true)).toMatchObject({ - protocol: 'https:', - host: 'acme.auth0.local', - query: { - returnTo: 'http://www.acme.com', - client_id: '__test_client_id__', - foo: 'bar' - }, - pathname: '/v2/logout' - }); + test('should use end_session_endpoint when configured', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + const res = await getResponse({ + url: '/api/auth/logout', + cookies, + config: { auth0Logout: false }, + discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } }); - - test('should return to the custom path', async () => { - const customReturnTo = 'https://www.foo.bar'; - const baseUrl = await setup(withoutApi, { - logoutOptions: { returnTo: customReturnTo } - }); - const cookieJar = await login(baseUrl); - - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/logout', { - cookieJar, - fullResponse: true - }); - - expect(statusCode).toBe(302); - expect(parseUrl(headers['location'], true).query).toMatchObject({ - returnTo: 'https://www.foo.bar' - }); + expect(res.status).toBe(302); + expect(parseUrl(res.headers.get('location'))).toMatchObject({ + host: 'my-end-session-endpoint', + pathname: '/logout' }); + }); - test('should use end_session_endpoint when configured', async () => { - const baseUrl = await setup( - { ...withoutApi, auth0Logout: false }, - { - discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } - } - ); - const cookieJar = await login(baseUrl); - - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/logout', { - cookieJar, - fullResponse: true - }); - - expect(statusCode).toBe(302); - expect(parseUrl(headers['location'])).toMatchObject({ - host: 'my-end-session-endpoint', - pathname: '/logout' - }); + test('should use auth0 logout by default even when end_session_endpoint is discovered', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + const res = await getResponse({ + url: '/api/auth/logout', + cookies, + discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } }); - - test('should use auth0 logout by default even when end_session_endpoint is discovered', async () => { - const baseUrl = await setup(withoutApi, { - discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } - }); - const cookieJar = await login(baseUrl); - - const { - res: { statusCode, headers } - } = await get(baseUrl, '/api/auth/logout', { - cookieJar, - fullResponse: true - }); - - expect(statusCode).toBe(302); - expect(parseUrl(headers['location'])).toMatchObject({ - host: 'acme.auth0.local', - pathname: '/v2/logout' - }); + expect(res.status).toBe(302); + expect(parseUrl(res.headers.get('location'))).toMatchObject({ + host: 'acme.auth0.local', + pathname: '/v2/logout' }); + }); - test('should delete the session', async () => { - const baseUrl = await setup(withoutApi, { - discoveryOptions: { end_session_endpoint: 'https://my-end-session-endpoint/logout' } - }); - const cookieJar = await login(baseUrl); + test('should delete the session', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + const res = await getResponse({ url: '/api/auth/logout', cookies }); + expect(res.status).toBe(302); + expect(new Date(res.cookies.get('appSession').expires).getTime()).toBe(0); + }); - const { - res: { headers } - } = await get(baseUrl, '/api/auth/logout', { - cookieJar, - fullResponse: true - }); + test('should handle logout errors', async () => { + const loginRes = await appRouterLogin(); + const cookies = { appSession: loginRes.cookies.get('appSession').value }; + nock.cleanAll(); + discovery(withApi, { error: true }); - expect(parse(headers['set-cookie'][0])).toMatchObject({ - appSession: '', - 'Max-Age': '0', - Path: '/' - }); - }); + const res = await getResponse({ url: '/api/auth/logout', cookies, clearNock: false }); + expect(res.status).toBe(500); + expect(res.statusText).toMatch(/Logout handler failed. CAUSE: Discovery requests failing/); }); }); diff --git a/tests/handlers/profile-page-router.test.ts b/tests/handlers/profile-page-router.test.ts new file mode 100644 index 000000000..4e7fdc10b --- /dev/null +++ b/tests/handlers/profile-page-router.test.ts @@ -0,0 +1,148 @@ +import nock from 'nock'; +import { withApi, withoutApi } from '../fixtures/default-settings'; +import { refreshTokenRotationExchange, userInfo } from '../fixtures/oidc-nocks'; +import { get } from '../auth0-session/fixtures/helpers'; +import { setup, teardown, login } from '../fixtures/setup'; +import { Session, AfterCallbackPageRoute } from '../../src'; +import { makeIdToken } from '../auth0-session/fixtures/cert'; + +describe('profile handler (page router)', () => { + afterEach(teardown); + + test('should throw an error when not logged in', async () => { + const baseUrl = await setup(withoutApi); + + await expect(get(baseUrl, '/api/auth/me')).resolves.toBe(''); + }); + + test('should return the profile when logged in', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = await login(baseUrl); + + const profile = await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(profile).toStrictEqual({ nickname: '__test_nickname__', sub: '__test_sub__' }); + }); + + test('should not allow caching the profile response', async () => { + const baseUrl = await setup(withoutApi); + const cookieJar = await login(baseUrl); + + const { res } = await get(baseUrl, '/api/auth/me', { cookieJar, fullResponse: true }); + expect(res.headers['cache-control']).toEqual('no-store'); + }); + + test('should not allow caching the profile response when refetch is true', async () => { + const baseUrl = await setup(withoutApi, { profileOptions: { refetch: true } }); + const cookieJar = await login(baseUrl); + + const { res } = await get(baseUrl, '/api/auth/me', { cookieJar, fullResponse: true }); + expect(res.headers['cache-control']).toEqual('no-store'); + }); + + test('should throw if re-fetching with no access token', async () => { + const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { + delete session.accessToken; + return session; + }; + const baseUrl = await setup(withoutApi, { + profileOptions: { refetch: true }, + callbackOptions: { afterCallback } + }); + const cookieJar = await login(baseUrl); + + await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrow( + 'The user does not have a valid access token.' + ); + }); + + test('should refetch the user and update the session', async () => { + const baseUrl = await setup(withoutApi, { profileOptions: { refetch: true }, userInfoPayload: { foo: 'bar' } }); + const cookieJar = await login(baseUrl); + + const profile = await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(profile).toMatchObject({ foo: 'bar', nickname: '__test_nickname__', sub: '__test_sub__' }); + // check that the session is saved + userInfo(withoutApi, 'eyJz93a...k4laUWw', {}); + const profile2 = await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(profile2).toMatchObject({ foo: 'bar', nickname: '__test_nickname__', sub: '__test_sub__' }); + }); + + test("should refetch the user and fail if it can't get an access token", async () => { + const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { + session.accessTokenExpiresAt = -60; + return session; + }; + const baseUrl = await setup(withoutApi, { + profileOptions: { refetch: true }, + userInfoPayload: { foo: 'bar' }, + callbackOptions: { + afterCallback + } + }); + const cookieJar = await login(baseUrl); + + nock(`${withoutApi.issuerBaseURL}`) + .post('/oauth/token', `grant_type=refresh_token&refresh_token=GEbRxBN...edjnXbL`) + .reply(200, { + id_token: await makeIdToken({ iss: 'https://acme.auth0.local/' }), + token_type: 'Bearer', + expires_in: 750, + scope: 'read:foo write:foo' + }); + await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrow( + 'No access token available to refetch the profile' + ); + }); + + test('should refetch the user and preserve new tokens', async () => { + const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { + session.accessTokenExpiresAt = -60; + return session; + }; + const baseUrl = await setup(withApi, { + profileOptions: { refetch: true }, + userInfoPayload: { foo: 'bar' }, + callbackOptions: { + afterCallback + }, + userInfoToken: 'new-access-token' + }); + await refreshTokenRotationExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-access-token', 'new-refresh-token'); + const cookieJar = await login(baseUrl); + const profile = await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(profile).toMatchObject({ foo: 'bar' }); + const session = await get(baseUrl, '/api/session', { cookieJar }); + expect(session.accessToken).toEqual('new-access-token'); + expect(session.refreshToken).toEqual('new-refresh-token'); + }); + + test('should update the session in the afterRefetch hook', async () => { + const baseUrl = await setup(withoutApi, { + profileOptions: { + refetch: true, + afterRefetch(_req, _res, session) { + session.user.foo = 'bar'; + return session; + } + } + }); + const cookieJar = await login(baseUrl); + + const user = await get(baseUrl, '/api/auth/me', { cookieJar }); + expect(user.foo).toEqual('bar'); + }); + + test('should throw from the afterRefetch hook', async () => { + const baseUrl = await setup(withoutApi, { + profileOptions: { + refetch: true, + afterRefetch() { + throw new Error('some validation error'); + } + } + }); + const cookieJar = await login(baseUrl); + + await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrowError('some validation error'); + }); +}); diff --git a/tests/handlers/profile.test.ts b/tests/handlers/profile.test.ts index cdae40721..d253510a4 100644 --- a/tests/handlers/profile.test.ts +++ b/tests/handlers/profile.test.ts @@ -1,316 +1,181 @@ +/** + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment + */ import nock from 'nock'; -import { withApi, withoutApi } from '../fixtures/default-settings'; -import { refreshTokenRotationExchange, userInfo } from '../fixtures/oidc-nocks'; -import { get } from '../auth0-session/fixtures/helpers'; -import { setup, teardown, login } from '../fixtures/setup'; -import { Session, AfterCallbackPageRoute } from '../../src'; +import { withApi } from '../fixtures/default-settings'; +import { refreshTokenRotationExchange } from '../fixtures/oidc-nocks'; +import { Session } from '../../src'; import { makeIdToken } from '../auth0-session/fixtures/cert'; import { getResponse, login as appRouterLogin, - getSession as appRouterGetSession + getSession as appRouterGetSession, + mockFetch } from '../fixtures/app-router-helpers'; import { NextRequest } from 'next/server'; -jest.mock('next/headers'); +describe('profile handler (app router)', () => { + beforeEach(mockFetch); -describe('profile handler', () => { - describe('app router', () => { - test('should be empty when not logged in', async () => { - await expect(getResponse({ url: '/api/auth/me' })).resolves.toMatchObject({ status: 204 }); - }); + test('should be empty when not logged in', async () => { + await expect(getResponse({ url: '/api/auth/me' })).resolves.toMatchObject({ status: 204 }); + }); - test('should return the profile when logged in', async () => { - const loginRes = await appRouterLogin(); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ nickname: '__test_nickname__', sub: '__test_sub__' }); + test('should return the profile when logged in', async () => { + const loginRes = await appRouterLogin(); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value } }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ nickname: '__test_nickname__', sub: '__test_sub__' }); + }); - test('should not allow caching the profile response', async () => { - const loginRes = await appRouterLogin(); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value } - }); - expect(res.headers.get('cache-control')).toBe('no-store'); + test('should not allow caching the profile response', async () => { + const loginRes = await appRouterLogin(); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value } }); + expect(res.headers.get('cache-control')).toBe('no-store'); + }); - test('should not allow caching the profile response when refetch is true', async () => { - const loginRes = await appRouterLogin(); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { refetch: true } - }); - expect(res.headers.get('cache-control')).toBe('no-store'); + test('should not allow caching the profile response when refetch is true', async () => { + const loginRes = await appRouterLogin(); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + profileOpts: { refetch: true }, + userInfoPayload: { sub: 'foo' } }); + expect(res.headers.get('cache-control')).toBe('no-store'); + }); - test('should throw if re-fetching with no access token', async () => { - const loginRes = await appRouterLogin({ - callbackOpts: { - afterCallback(_req: any, session: any): Session { - delete session.accessToken; - return session; - } + test('should throw if re-fetching with no access token', async () => { + const loginRes = await appRouterLogin({ + callbackOpts: { + afterCallback(_req: any, session: any): Session { + delete session.accessToken; + return session; } - }); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { refetch: true } - }); - expect(res.status).toBe(500); - expect(res.statusText).toMatch(/The user does not have a valid access token/); - }); - - test('should refetch the user and update the session', async () => { - const loginRes = await appRouterLogin(); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { refetch: true }, - userInfoPayload: { foo: 'bar' } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ foo: 'bar' }); + } }); - - test("should refetch the user and fail if it can't get an access token", async () => { - const loginRes = await appRouterLogin({ - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - session.accessTokenExpiresAt = -60; - return session; - } - } - }); - nock.cleanAll(); - nock(`${withApi.issuerBaseURL}`) - .post('/oauth/token', `grant_type=refresh_token&refresh_token=GEbRxBN...edjnXbL`) - .reply(200, { - id_token: await makeIdToken({ iss: 'https://acme.auth0.local/' }), - token_type: 'Bearer', - expires_in: 750, - scope: 'read:foo write:foo' - }); - - await expect( - getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { refetch: true }, - userInfoPayload: { foo: 'bar' }, - clearNock: false, - userInfoToken: 'new-access-token' - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/No access token available to refetch the profile/) - }); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + profileOpts: { refetch: true } }); + expect(res.status).toBe(500); + expect(res.statusText).toMatch(/The user does not have a valid access token/); + }); - test('should refetch the user and preserve new tokens', async () => { - const loginRes = await appRouterLogin({ - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - session.accessTokenExpiresAt = -60; - return session; - } - } - }); - nock.cleanAll(); - await refreshTokenRotationExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-access-token', 'new-refresh-token'); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { refetch: true }, - userInfoPayload: { foo: 'bar' }, - clearNock: false, - userInfoToken: 'new-access-token' - }); - expect(res.status).toBe(200); - await expect(appRouterGetSession(withApi, res)).resolves.toMatchObject({ - user: expect.objectContaining({ foo: 'bar' }), - accessToken: 'new-access-token', - refreshToken: 'new-refresh-token' - }); - await expect(res.json()).resolves.toMatchObject({ foo: 'bar' }); + test('should refetch the user and update the session', async () => { + const loginRes = await appRouterLogin(); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + profileOpts: { refetch: true }, + userInfoPayload: { foo: 'bar', sub: 'foo' } }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ foo: 'bar' }); + }); - test('should update the session in the afterRefetch hook', async () => { - const loginRes = await appRouterLogin(); - const res = await getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { - refetch: true, - afterRefetch(_req: NextRequest, session: Session) { - return { ...session, user: { ...session.user, foo: 'baz' } }; - } + test("should refetch the user and fail if it can't get an access token", async () => { + const loginRes = await appRouterLogin({ + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + session.accessTokenExpiresAt = -60; + return session; } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ foo: 'baz' }); - }); - - test('should throw from the afterRefetch hook', async () => { - const loginRes = await appRouterLogin(); - await expect( - getResponse({ - url: '/api/auth/me', - cookies: { appSession: loginRes.cookies.get('appSession').value }, - profileOpts: { - refetch: true, - afterRefetch() { - throw new Error('some validation error'); - } - } - }) - ).resolves.toMatchObject({ status: 500, statusText: expect.stringMatching(/some validation error/) }); - }); + } + }); + nock.cleanAll(); + nock(`${withApi.issuerBaseURL}`) + .post('/oauth/token', (body) => { + //`grant_type=refresh_token&refresh_token=GEbRxBN...edjnXbL` + return body.grant_type === 'refresh_token' && body.refresh_token === 'GEbRxBN...edjnXbL'; + }) + .reply(200, { + id_token: await makeIdToken({ iss: 'https://acme.auth0.local/' }), + token_type: 'Bearer', + expires_in: 750, + scope: 'read:foo write:foo' + }); + + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + profileOpts: { refetch: true }, + userInfoPayload: { foo: 'bar' }, + clearNock: false, + userInfoToken: 'new-access-token' + }); + expect(res.status).toBe(500); + expect(res.statusText).toMatch( + /No access token available to refetch the profile|"access_token" property must be a non-empty string/ + ); }); - describe('page router', () => { - afterEach(teardown); - - test('should throw an error when not logged in', async () => { - const baseUrl = await setup(withoutApi); - - await expect(get(baseUrl, '/api/auth/me')).resolves.toBe(''); - }); - - test('should return the profile when logged in', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = await login(baseUrl); - - const profile = await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(profile).toStrictEqual({ nickname: '__test_nickname__', sub: '__test_sub__' }); - }); - - test('should not allow caching the profile response', async () => { - const baseUrl = await setup(withoutApi); - const cookieJar = await login(baseUrl); - - const { res } = await get(baseUrl, '/api/auth/me', { cookieJar, fullResponse: true }); - expect(res.headers['cache-control']).toEqual('no-store'); - }); - - test('should not allow caching the profile response when refetch is true', async () => { - const baseUrl = await setup(withoutApi, { profileOptions: { refetch: true } }); - const cookieJar = await login(baseUrl); - - const { res } = await get(baseUrl, '/api/auth/me', { cookieJar, fullResponse: true }); - expect(res.headers['cache-control']).toEqual('no-store'); - }); - - test('should throw if re-fetching with no access token', async () => { - const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { - delete session.accessToken; - return session; - }; - const baseUrl = await setup(withoutApi, { - profileOptions: { refetch: true }, - callbackOptions: { afterCallback } - }); - const cookieJar = await login(baseUrl); - - await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrow( - 'The user does not have a valid access token.' - ); - }); - test('should refetch the user and update the session', async () => { - const baseUrl = await setup(withoutApi, { profileOptions: { refetch: true }, userInfoPayload: { foo: 'bar' } }); - const cookieJar = await login(baseUrl); - - const profile = await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(profile).toMatchObject({ foo: 'bar', nickname: '__test_nickname__', sub: '__test_sub__' }); - // check that the session is saved - userInfo(withoutApi, 'eyJz93a...k4laUWw', {}); - const profile2 = await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(profile2).toMatchObject({ foo: 'bar', nickname: '__test_nickname__', sub: '__test_sub__' }); - }); - - test("should refetch the user and fail if it can't get an access token", async () => { - const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { - session.accessTokenExpiresAt = -60; - return session; - }; - const baseUrl = await setup(withoutApi, { - profileOptions: { refetch: true }, - userInfoPayload: { foo: 'bar' }, - callbackOptions: { - afterCallback + test('should refetch the user and preserve new tokens', async () => { + const loginRes = await appRouterLogin({ + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + session.accessTokenExpiresAt = -60; + return session; } - }); - const cookieJar = await login(baseUrl); - - nock(`${withoutApi.issuerBaseURL}`) - .post('/oauth/token', `grant_type=refresh_token&refresh_token=GEbRxBN...edjnXbL`) - .reply(200, { - id_token: await makeIdToken({ iss: 'https://acme.auth0.local/' }), - token_type: 'Bearer', - expires_in: 750, - scope: 'read:foo write:foo' - }); - await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrow( - 'No access token available to refetch the profile' - ); - }); - - test('should refetch the user and preserve new tokens', async () => { - const afterCallback: AfterCallbackPageRoute = (_req, _res, session: Session): Session => { - session.accessTokenExpiresAt = -60; - return session; - }; - const baseUrl = await setup(withApi, { - profileOptions: { refetch: true }, - userInfoPayload: { foo: 'bar' }, - callbackOptions: { - afterCallback - }, - userInfoToken: 'new-access-token' - }); - await refreshTokenRotationExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-access-token', 'new-refresh-token'); - const cookieJar = await login(baseUrl); - const profile = await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(profile).toMatchObject({ foo: 'bar' }); - const session = await get(baseUrl, '/api/session', { cookieJar }); - expect(session.accessToken).toEqual('new-access-token'); - expect(session.refreshToken).toEqual('new-refresh-token'); - }); + } + }); + nock.cleanAll(); + await refreshTokenRotationExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-access-token', 'new-refresh-token'); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + profileOpts: { refetch: true }, + userInfoPayload: { foo: 'bar', sub: 'foo' }, + clearNock: false, + userInfoToken: 'new-access-token' + }); + expect(res.status).toBe(200); + await expect(appRouterGetSession(withApi, res)).resolves.toMatchObject({ + user: expect.objectContaining({ foo: 'bar' }), + accessToken: 'new-access-token', + refreshToken: 'new-refresh-token' + }); + await expect(res.json()).resolves.toMatchObject({ foo: 'bar' }); + }); - test('should update the session in the afterRefetch hook', async () => { - const baseUrl = await setup(withoutApi, { - profileOptions: { - refetch: true, - afterRefetch(_req, _res, session) { - session.user.foo = 'bar'; - return session; - } + test('should update the session in the afterRefetch hook', async () => { + const loginRes = await appRouterLogin(); + const res = await getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + userInfoPayload: { sub: 'foo' }, + profileOpts: { + refetch: true, + afterRefetch(_req: NextRequest, session: Session) { + return { ...session, user: { ...session.user, foo: 'baz' } }; } - }); - const cookieJar = await login(baseUrl); - - const user = await get(baseUrl, '/api/auth/me', { cookieJar }); - expect(user.foo).toEqual('bar'); + } }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ foo: 'baz' }); + }); - test('should throw from the afterRefetch hook', async () => { - const baseUrl = await setup(withoutApi, { - profileOptions: { + test('should throw from the afterRefetch hook', async () => { + const loginRes = await appRouterLogin(); + await expect( + getResponse({ + url: '/api/auth/me', + cookies: { appSession: loginRes.cookies.get('appSession').value }, + userInfoPayload: { sub: 'foo' }, + profileOpts: { refetch: true, afterRefetch() { throw new Error('some validation error'); } } - }); - const cookieJar = await login(baseUrl); - - await expect(get(baseUrl, '/api/auth/me', { cookieJar })).rejects.toThrowError('some validation error'); - }); + }) + ).resolves.toMatchObject({ status: 500, statusText: expect.stringMatching(/some validation error/) }); }); }); diff --git a/tests/helpers/testing.test.ts b/tests/helpers/testing.test.ts index f88f841ef..95c7764d0 100644 --- a/tests/helpers/testing.test.ts +++ b/tests/helpers/testing.test.ts @@ -60,7 +60,7 @@ describe('generate-session-cookie', () => { test('use the current time for the header values', async () => { const now = Date.now(); const current = (now / 1000) | 0; - const clock = jest.useFakeTimers('modern'); + const clock = jest.useFakeTimers(); clock.setSystemTime(now); await generateSessionCookie({}, { secret: '' }); expect(encryptMock).toHaveBeenCalledWith(expect.anything(), { diff --git a/tests/helpers/with-middleware-auth-required.test.ts b/tests/helpers/with-middleware-auth-required.test.ts index 86d6a2cd0..372e701bf 100644 --- a/tests/helpers/with-middleware-auth-required.test.ts +++ b/tests/helpers/with-middleware-auth-required.test.ts @@ -1,6 +1,3 @@ -/** - * @jest-environment @edge-runtime/jest-environment - */ import { NextRequest, NextResponse } from 'next/server'; import { NextFetchEvent } from 'next/dist/server/web/spec-extension/fetch-event'; import { initAuth0 } from '../../src/edge'; @@ -10,6 +7,7 @@ import { encryption } from '../../src/auth0-session/utils/hkdf'; import { defaultConfig } from '../auth0-session/fixtures/helpers'; import { makeIdToken } from '../auth0-session/fixtures/cert'; import * as jose from 'jose'; +import { getSession } from '../fixtures/app-router-helpers'; const encrypted = async (claims: Partial = { sub: '__test_sub__' }): Promise => { const key = await encryption(defaultConfig.secret as string); @@ -34,8 +32,8 @@ const encrypted = async (claims: Partial = { sub: '__test_sub__' .encrypt(key); }; -const setup = async ({ url = 'http://example.com', config = withoutApi, user, middleware }: any = {}) => { - const mw = initAuth0(config).withMiddlewareAuthRequired(middleware); +const setup = async ({ url = 'http://example.com', config = withoutApi, user, middleware, instance }: any = {}) => { + const mw = (instance || initAuth0(config)).withMiddlewareAuthRequired(middleware); const request = new NextRequest(new URL(url)); if (user) { request.cookies.set('appSession', await encrypted({ sub: 'foo' })); @@ -178,8 +176,6 @@ describe('with-middleware-auth-required', () => { }; const res = await setup({ user: { name: 'dave' }, middleware }); expect(res.status).toEqual(200); - // @ts-expect-errors ts dom doesn't have getAll - expect(res.headers.getAll('set-cookie')).toHaveLength(2); expect(res.headers.get('set-cookie')).toMatch(/appSession=/); expect(res.headers.get('set-cookie')).toMatch(/foo=bar;/); }); @@ -212,8 +208,6 @@ describe('with-middleware-auth-required', () => { const res = await setup({ user: { name: 'dave' }, middleware }); expect(res.status).toEqual(200); await expect(res.json()).resolves.toEqual({ foo: 'bar' }); - // @ts-expect-errors ts dom doesn't have getAll - expect(res.headers.getAll('set-cookie')).toHaveLength(2); expect(res.headers.get('set-cookie')).toMatch(/appSession=/); expect(res.headers.get('set-cookie')).toMatch(/foo=bar;/); }); @@ -259,4 +253,38 @@ describe('with-middleware-auth-required', () => { expect(res.status).toEqual(200); expect(res.headers.get('foo')).toBe('bar'); }); + + test('should update session from custom middleware', async () => { + const instance = initAuth0(withoutApi); + const middleware = async (req: NextRequest) => { + const res = NextResponse.next(); + const session = await instance.getSession(req, res); + await instance.updateSession(req, res, { ...session, user: { ...session?.user, baz: 'bar' } }); + return res; + }; + const res = await setup({ + instance, + user: { name: 'dave' }, + middleware + }); + await expect(getSession(withoutApi, res)).resolves.toMatchObject({ user: { sub: 'foo', baz: 'bar' } }); + }); + + test('should update session with a large claim from middleware', async () => { + const instance = initAuth0(withoutApi); + const middleware = async (req: NextRequest) => { + const res = NextResponse.next(); + const session = await instance.getSession(req, res); + await instance.updateSession(req, res, { ...session, user: { ...session?.user, baz: 'bar'.repeat(2000) } }); + return res; + }; + const res = await setup({ + instance, + user: { name: 'dave' }, + middleware + }); + await expect(getSession(withoutApi, res)).resolves.toMatchObject({ user: { baz: expect.any(String) } }); + expect(res.headers.get('set-cookie')).toMatch(/appSession=;/); + expect(res.headers.get('set-cookie')).toMatch(/appSession.0=/); + }); }); diff --git a/tests/helpers/with-page-auth-required.test.ts b/tests/helpers/with-page-auth-required.test.ts index 6ff93ce4a..2cbdde16d 100644 --- a/tests/helpers/with-page-auth-required.test.ts +++ b/tests/helpers/with-page-auth-required.test.ts @@ -3,7 +3,6 @@ import ReactDOMServer from 'react-dom/server'; import { cookies as nextCookies } from 'next/headers'; import * as navigation from 'next/navigation'; import { NextResponse } from 'next/server'; -import { mocked } from 'ts-jest/utils'; import { URL } from 'url'; import { login, setup, teardown } from '../fixtures/setup'; import { login as appRouterLogin } from '../fixtures/app-router-helpers'; @@ -24,7 +23,7 @@ describe('with-page-auth-required ssr', () => { describe('app route', () => { const getPageResponse = ({ config, cookies, returnTo, loginRes, params, searchParams }: any = {}) => { const res = loginRes || new NextResponse(); - mocked(nextCookies).mockImplementation(() => res.cookies as any); + jest.mocked(nextCookies).mockImplementation(() => res.cookies as any); const opts = { ...withApi, ...config }; const instance = initAuth0(opts); let headers = new Headers(); diff --git a/tests/http/auth0-next-request.test.ts b/tests/http/auth0-next-request.test.ts index dc16abc3c..5045294f6 100644 --- a/tests/http/auth0-next-request.test.ts +++ b/tests/http/auth0-next-request.test.ts @@ -1,5 +1,5 @@ /** - * @jest-environment @edge-runtime/jest-environment + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment */ import Auth0NextRequest from '../../src/http/auth0-next-request'; import { NextRequest, NextResponse } from 'next/server'; diff --git a/tests/http/auth0-next-response-cookies.test.ts b/tests/http/auth0-next-response-cookies.test.ts index eeef8679b..f9b62bff6 100644 --- a/tests/http/auth0-next-response-cookies.test.ts +++ b/tests/http/auth0-next-response-cookies.test.ts @@ -1,5 +1,4 @@ import { cookies as nextCookies } from 'next/headers'; -import { mocked } from 'ts-jest/utils'; import { Auth0NextResponseCookies } from '../../src/http'; import { NextResponse } from 'next/server'; @@ -9,7 +8,7 @@ describe('auth0-next-response', () => { it('should set a cookie', async () => { const cookies = new Auth0NextResponseCookies(); const res = new NextResponse(); - mocked(nextCookies).mockImplementation(() => res.cookies as any); + jest.mocked(nextCookies).mockImplementation(() => res.cookies as any); cookies.setCookie('foo', 'bar'); expect(res.cookies.get('foo')?.value).toEqual('bar'); }); @@ -17,7 +16,7 @@ describe('auth0-next-response', () => { it('should delete cookies', async () => { const cookies = new Auth0NextResponseCookies(); const res = new NextResponse(); - mocked(nextCookies).mockImplementation(() => res.cookies as any); + jest.mocked(nextCookies).mockImplementation(() => res.cookies as any); cookies.clearCookie('foo'); expect(res.headers.get('set-cookie')).toEqual('foo=; Path=/; Expires=Thu, 01 Jan 1970 00:00:00 GMT'); }); diff --git a/tests/http/auth0-next-response.test.ts b/tests/http/auth0-next-response.test.ts index 20b275c0b..808de8612 100644 --- a/tests/http/auth0-next-response.test.ts +++ b/tests/http/auth0-next-response.test.ts @@ -1,5 +1,5 @@ /** - * @jest-environment @edge-runtime/jest-environment + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment */ import Auth0NextResponse from '../../src/http/auth0-next-response'; import { NextRequest, NextResponse } from 'next/server'; diff --git a/tests/session/cache.test.ts b/tests/session/cache.test.ts index aa50b4b57..cf4c3ad6c 100644 --- a/tests/session/cache.test.ts +++ b/tests/session/cache.test.ts @@ -1,6 +1,5 @@ import { IncomingMessage, ServerResponse } from 'http'; import { Socket } from 'net'; -import { mocked } from 'ts-jest/utils'; import { StatelessSession, getConfig } from '../../src/auth0-session'; import { get, set } from '../../src/session/cache'; import { ConfigParameters, Session, SessionCache } from '../../src'; @@ -15,13 +14,13 @@ describe('SessionCache', () => { const setup = (conf: ConfigParameters) => { const config = getConfig(conf); - sessionStore = mocked(new StatelessSession(config)); + sessionStore = jest.mocked(new StatelessSession(config)); sessionStore.save = jest.fn(); session = new Session({ sub: '__test_user__' }); session.idToken = '__test_id_token__'; cache = new SessionCache(config, sessionStore); - req = mocked(new IncomingMessage(new Socket())); - res = mocked(new ServerResponse(req)); + req = jest.mocked(new IncomingMessage(new Socket())); + res = jest.mocked(new ServerResponse(req)); }; beforeEach(() => { diff --git a/tests/session/get-access-token-app-router-rsc.test.ts b/tests/session/get-access-token-app-router-rsc.test.ts new file mode 100644 index 000000000..600463673 --- /dev/null +++ b/tests/session/get-access-token-app-router-rsc.test.ts @@ -0,0 +1,108 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { cookies as nextCookies } from 'next/headers'; +import nock from 'nock'; +import { withApi } from '../fixtures/default-settings'; +import { AccessTokenRequest, initAuth0, Session } from '../../src'; +import { refreshTokenExchange } from '../fixtures/oidc-nocks'; +import { + getResponse, + GetResponseOpts, + LoginOpts, + login as appRouterLogin, + mockFetch +} from '../fixtures/app-router-helpers'; + +jest.mock('next/headers'); + +const getAccessTokenResponse = async ({ + authenticated = false, + getResOpts = {}, + loginOpts = {}, + getAccessTokenOpts +}: { + authenticated?: boolean; + getResOpts?: Omit; + loginOpts?: LoginOpts; + getAccessTokenOpts?: AccessTokenRequest; +} = {}) => { + const auth0Instance = initAuth0(withApi); + let cookies: { appSession?: string } = {}; + if (authenticated) { + const loginRes = await appRouterLogin(loginOpts); + cookies.appSession = loginRes.cookies.get('appSession').value; + jest.mocked(nextCookies).mockImplementation(() => loginRes.cookies); + } + await refreshTokenExchange( + withApi, + 'GEbRxBN...edjnXbL', + { + email: 'john@test.com', + name: 'john doe', + sub: '123' + }, + 'new-token' + ); + return getResponse({ + auth0Instance, + url: '/api/auth/access-token', + extraHandlers: { + async 'access-token'() { + const at = await auth0Instance.getAccessToken(getAccessTokenOpts); + const session = await auth0Instance.getSession(); + return NextResponse.json({ at, session }); + } + }, + cookies, + clearNock: false, + ...getResOpts + }).finally(() => nock.cleanAll()); +}; + +describe('get access token (app router rsc)', () => { + beforeEach(mockFetch); + + test('should return an access token', async () => { + const res = await getAccessTokenResponse({ + authenticated: true + }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'eyJz93a...k4laUWw' } + }); + }); + + test('should retrieve a new access token if the old one is expired and update the profile', async () => { + const res = await getAccessTokenResponse({ + authenticated: true, + loginOpts: { + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + return { ...session, accessTokenExpiresAt: -60 }; + } + } + } + }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'new-token' }, + session: expect.objectContaining({ user: expect.objectContaining({ email: 'john@test.com' }) }) + }); + }); + + test('should retrieve a new access token and update the session based on afterRefresh', async () => { + const res = await getAccessTokenResponse({ + authenticated: true, + getAccessTokenOpts: { + refresh: true, + afterRefresh(_req, _res, session) { + return { ...session, foo: 'baz' }; + } + } + }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'new-token' }, + session: expect.objectContaining({ foo: 'baz' }) + }); + }); +}); diff --git a/tests/session/get-access-token-page-router.test.ts b/tests/session/get-access-token-page-router.test.ts new file mode 100644 index 000000000..56a7668d5 --- /dev/null +++ b/tests/session/get-access-token-page-router.test.ts @@ -0,0 +1,347 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import nock from 'nock'; +import { login, setup, teardown } from '../fixtures/setup'; +import { withApi } from '../fixtures/default-settings'; +import { get } from '../auth0-session/fixtures/helpers'; +import { Session } from '../../src'; +import { failedRefreshTokenExchange, refreshTokenExchange, refreshTokenRotationExchange } from '../fixtures/oidc-nocks'; +import { makeIdToken } from '../auth0-session/fixtures/cert'; + +describe('get access token (page router)', () => { + afterEach(teardown); + + test('should fail if the session is missing', async () => { + const baseUrl = await setup(withApi); + + await expect(get(baseUrl, '/api/access-token')).rejects.toThrow('The user does not have a valid session.'); + }); + + test('should fail if access_token and refresh_token are missing', async () => { + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + delete session.accessToken; + delete session.refreshToken; + return session; + } + } + }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'The user does not have a valid access token.' + ); + }); + + test('should fail if access_token expiry is missing', async () => { + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + delete session.accessTokenExpiresAt; + return session; + } + } + }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'Expiration information for the access token is not available. The user will need to sign in again.' + ); + }); + + test('should fail if access_token scope is missing', async () => { + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + delete session.accessTokenScope; + return session; + } + }, + getAccessTokenOptions: { + scopes: ['read:foo'] + } + }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'An access token with the requested scopes could not be provided. The user will need to sign in again.' + ); + }); + + test("should fail if access_token scope doesn't match requested scope", async () => { + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + session.accessTokenScope = 'read:bar'; + return session; + } + }, + getAccessTokenOptions: { + scopes: ['read:foo'] + } + }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'Could not retrieve an access token with scopes "read:foo". The user will need to sign in again.' + ); + }); + + test('should fail if the access token is expired', async () => { + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + delete session.refreshToken; + session.accessTokenExpiresAt = -60; + return session; + } + } + }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'The access token expired and a refresh token is not available. The user will need to sign in again.' + ); + }); + + test('should fail if you try to refresh the access token without a refresh token', async () => { + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + delete session.refreshToken; + return session; + } + }, + getAccessTokenOptions: { refresh: true } + }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'A refresh token is required to refresh the access token, but none is present.' + ); + }); + + test('should return an access token', async () => { + const baseUrl = await setup(withApi); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('eyJz93a...k4laUWw'); + }); + + test('should retrieve a new access token if the old one is expired and update the profile', async () => { + await refreshTokenExchange( + withApi, + 'GEbRxBN...edjnXbL', + { + email: 'john@test.com', + name: 'john doe', + sub: '123' + }, + 'new-token' + ); + const baseUrl = await setup(withApi, { + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + session.accessTokenExpiresAt = -60; + return session; + } + } + }); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + const { refreshToken } = await get(baseUrl, '/api/session', { cookieJar }); + expect(refreshToken).toEqual('GEbRxBN...edjnXbL'); + }); + + test('should retrieve a new access token if force refresh is set', async () => { + await refreshTokenExchange( + withApi, + 'GEbRxBN...edjnXbL', + { + email: 'john@test.com', + name: 'john doe', + sub: '123' + }, + 'new-token' + ); + const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + const { refreshToken } = await get(baseUrl, '/api/session', { cookieJar }); + expect(refreshToken).toEqual('GEbRxBN...edjnXbL'); + }); + + test('should fail when refresh grant fails', async () => { + await failedRefreshTokenExchange(withApi, 'GEbRxBN...edjnXbL', {}, 500); + const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'The request to refresh the access token failed. CAUSE: expected 200 OK, got: 500 Internal Server Error' + ); + }); + + test('should fail when refresh grant fails with oauth error', async () => { + await failedRefreshTokenExchange( + withApi, + 'GEbRxBN...edjnXbL', + { error: 'invalid_grant', error_description: 'Unknown or invalid refresh token.' }, + 401 + ); + const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'The request to refresh the access token failed. CAUSE: invalid_grant (Unknown or invalid refresh token.)' + ); + }); + + test('should escape oauth error', async () => { + await failedRefreshTokenExchange( + withApi, + 'GEbRxBN...edjnXbL', + { error: '', error_description: '' }, + 401 + ); + const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); + const cookieJar = await login(baseUrl); + await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( + 'The request to refresh the access token failed. CAUSE: <script>alert(1)</script> (<script>alert(2)</script>)' + ); + }); + + test('should retrieve a new access token and rotate the refresh token', async () => { + await refreshTokenRotationExchange( + withApi, + 'GEbRxBN...edjnXbL', + { + email: 'john@test.com', + name: 'john doe', + sub: '123' + }, + 'new-token', + 'new-refresh-token' + ); + const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + const { refreshToken } = await get(baseUrl, '/api/session', { cookieJar }); + expect(refreshToken).toEqual('new-refresh-token'); + }); + + test('should return an access token with the given scopes', async () => { + const baseUrl = await setup(withApi, { getAccessTokenOptions: { scopes: ['read:foo'] } }); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('eyJz93a...k4laUWw'); + }); + + test('should not overwrite custom session properties when applying a new access token', async () => { + await refreshTokenExchange( + withApi, + 'GEbRxBN...edjnXbL', + { + email: 'john@test.com', + name: 'john doe', + sub: '123' + }, + 'new-token' + ); + const baseUrl = await setup(withApi, { + getAccessTokenOptions: { refresh: true }, + callbackOptions: { + afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { + session.foo = 'bar'; + session.user.bar = 'baz'; + return session; + } + } + }); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + const session = await get(baseUrl, '/api/session', { cookieJar }); + expect(session).toMatchObject({ + foo: 'bar', + accessToken: 'new-token', + refreshToken: 'GEbRxBN...edjnXbL', + user: { + nickname: '__test_nickname__', + email: 'john@test.com', + name: 'john doe', + sub: '123', + bar: 'baz' + } + }); + }); + + test('should retrieve a new access token and update the session based on afterRefresh', async () => { + await refreshTokenExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-token'); + const baseUrl = await setup(withApi, { + getAccessTokenOptions: { + refresh: true, + afterRefresh(_req, _res, session) { + delete session.accessTokenScope; + return session as Session; + } + } + }); + const cookieJar = await login(baseUrl); + const { accessTokenScope } = await get(baseUrl, '/api/session', { cookieJar }); + expect(accessTokenScope).not.toBeUndefined(); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + const { accessTokenScope: newAccessTokenScope } = await get(baseUrl, '/api/session', { + cookieJar + }); + expect(newAccessTokenScope).toBeUndefined(); + }); + + test('should retrieve a new access token and update the session based on the storeIDToken config', async () => { + await refreshTokenExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-token'); + const baseUrl = await setup( + { ...withApi, session: { storeIDToken: false } }, + { + getAccessTokenOptions: { + refresh: true + } + } + ); + const cookieJar = await login(baseUrl); + const session = await get(baseUrl, '/api/session', { cookieJar }); + expect(session.idToken).toBeUndefined(); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + const newSession = await get(baseUrl, '/api/session', { + cookieJar + }); + expect(newSession.idToken).toBeUndefined(); + }); + + test('should pass custom auth params in refresh grant request body', async () => { + const idToken = await makeIdToken({ + iss: `${withApi.issuerBaseURL}/`, + aud: withApi.clientID, + email: 'john@test.com', + name: 'john doe', + sub: '123' + }); + + const spy = jest.fn(); + nock(`${withApi.issuerBaseURL}`) + .post('/oauth/token', /grant_type=refresh_token/) + .reply(200, (_, body) => { + spy(body); + return { + access_token: 'new-token', + id_token: idToken, + token_type: 'Bearer', + expires_in: 750, + scope: 'read:foo write:foo' + }; + }); + + const baseUrl = await setup(withApi, { + getAccessTokenOptions: { refresh: true, authorizationParams: { baz: 'qux' } } + }); + const cookieJar = await login(baseUrl); + const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); + expect(accessToken).toEqual('new-token'); + expect(spy).toHaveBeenCalledWith(expect.stringContaining('baz=qux')); + }); +}); diff --git a/tests/session/get-access-token.test.ts b/tests/session/get-access-token.test.ts index 54b535a61..364f58718 100644 --- a/tests/session/get-access-token.test.ts +++ b/tests/session/get-access-token.test.ts @@ -1,39 +1,36 @@ -import { NextApiRequest, NextApiResponse } from 'next'; +/** + * **REMOVE-TO-TEST-ON-EDGE**@jest-environment @edge-runtime/jest-environment + */ import { NextRequest, NextResponse } from 'next/server'; -import { cookies as nextCookies } from 'next/headers'; import nock from 'nock'; -import { mocked } from 'ts-jest/utils'; -import { login, setup, teardown } from '../fixtures/setup'; import { withApi } from '../fixtures/default-settings'; -import { get } from '../auth0-session/fixtures/helpers'; -import { AccessTokenRequest, initAuth0, Session } from '../../src'; -import { failedRefreshTokenExchange, refreshTokenExchange, refreshTokenRotationExchange } from '../fixtures/oidc-nocks'; -import { makeIdToken } from '../auth0-session/fixtures/cert'; -import { getResponse, GetResponseOpts, LoginOpts, login as appRouterLogin } from '../fixtures/app-router-helpers'; - -jest.mock('next/headers'); +import { AccessTokenRequest, Session } from '../../src'; +import { refreshTokenExchange } from '../fixtures/oidc-nocks'; +import { + getResponse, + GetResponseOpts, + LoginOpts, + login as appRouterLogin, + mockFetch, + initAuth0 +} from '../fixtures/app-router-helpers'; const getAccessTokenResponse = async ({ authenticated = false, getResOpts = {}, loginOpts = {}, - getAccessTokenOpts, - userRsc + getAccessTokenOpts }: { authenticated?: boolean; getResOpts?: Omit; loginOpts?: LoginOpts; getAccessTokenOpts?: AccessTokenRequest; - userRsc?: boolean; } = {}) => { const auth0Instance = initAuth0(withApi); let cookies: { appSession?: string } = {}; if (authenticated) { const loginRes = await appRouterLogin(loginOpts); cookies.appSession = loginRes.cookies.get('appSession').value; - if (userRsc) { - mocked(nextCookies).mockImplementation(() => loginRes.cookies); - } } await refreshTokenExchange( withApi, @@ -47,18 +44,13 @@ const getAccessTokenResponse = async ({ ); return getResponse({ auth0Instance, - url: userRsc ? '/api/auth/access-token-rsc' : '/api/auth/access-token', + url: '/api/auth/access-token', extraHandlers: { async 'access-token'(req: NextRequest) { const res = new NextResponse(); const at = await auth0Instance.getAccessToken(req, res, getAccessTokenOpts); const session = await auth0Instance.getSession(req, res); return NextResponse.json({ at, session }, res); - }, - async 'access-token-rsc'() { - const at = await auth0Instance.getAccessToken(getAccessTokenOpts); - const session = await auth0Instance.getSession(); - return NextResponse.json({ at, session }); } }, cookies, @@ -67,582 +59,208 @@ const getAccessTokenResponse = async ({ }).finally(() => nock.cleanAll()); }; -describe('get access token', () => { - describe('app router', () => { - test('should fail if the session is missing', async () => { - await expect(getAccessTokenResponse()).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/The user does not have a valid session/) - }); - }); - - test('should fail if access_token and refresh_token are missing', async () => { - await expect( - getAccessTokenResponse({ - authenticated: true, - loginOpts: { - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - delete session.accessToken; - delete session.refreshToken; - return session; - } - } - } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/The user does not have a valid access token/) - }); - }); +describe('get access token (api route)', () => { + beforeEach(mockFetch); - test('should fail if access_token expiry is missing', async () => { - await expect( - getAccessTokenResponse({ - authenticated: true, - loginOpts: { - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - delete session.accessTokenExpiresAt; - return session; - } - } - } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/Expiration information for the access token is not available/) - }); - }); - - test('should fail if access_token scope is missing', async () => { - await expect( - getAccessTokenResponse({ - authenticated: true, - loginOpts: { - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - delete session.accessTokenScope; - return session; - } - } - }, - getAccessTokenOpts: { - scopes: ['read:foo'] - } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/An access token with the requested scopes could not be provided/) - }); - }); - - test("should fail if access_token scope doesn't match requested scope", async () => { - await expect( - getAccessTokenResponse({ - authenticated: true, - loginOpts: { - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - return { ...session, accessTokenScope: 'read:bar' }; - } - } - }, - getAccessTokenOpts: { - scopes: ['read:foo'] - } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/Could not retrieve an access token with scopes "read:foo"/) - }); - }); - - test('should fail if the access token is expired', async () => { - await expect( - getAccessTokenResponse({ - authenticated: true, - loginOpts: { - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - delete session.refreshToken; - return { ...session, accessTokenExpiresAt: -60 }; - } - } - } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching(/The access token expired and a refresh token is not available/) - }); - }); - - test('should fail if you try to refresh the access token without a refresh token', async () => { - await expect( - getAccessTokenResponse({ - authenticated: true, - loginOpts: { - callbackOpts: { - afterCallback(_req: NextRequest, session: Session) { - delete session.refreshToken; - return session; - } - } - }, - getAccessTokenOpts: { refresh: true } - }) - ).resolves.toMatchObject({ - status: 500, - statusText: expect.stringMatching( - /A refresh token is required to refresh the access token, but none is present/ - ) - }); - }); - - test('should return an access token', async () => { - const res = await getAccessTokenResponse({ - authenticated: true - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'eyJz93a...k4laUWw' } - }); + test('should fail if the session is missing', async () => { + await expect(getAccessTokenResponse()).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/The user does not have a valid session/) }); + }); - test('should retrieve a new access token if the old one is expired and update the profile', async () => { - const res = await getAccessTokenResponse({ + test('should fail if access_token and refresh_token are missing', async () => { + await expect( + getAccessTokenResponse({ authenticated: true, loginOpts: { callbackOpts: { afterCallback(_req: NextRequest, session: Session) { - return { ...session, accessTokenExpiresAt: -60 }; + delete session.accessToken; + delete session.refreshToken; + return session; } } } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'new-token' }, - session: expect.objectContaining({ user: expect.objectContaining({ email: 'john@test.com' }) }) - }); - }); - - test('should retrieve a new access token if force refresh is set', async () => { - const res = await getAccessTokenResponse({ - authenticated: true, - getAccessTokenOpts: { refresh: true } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'new-token' }, - session: expect.objectContaining({ user: expect.objectContaining({ email: 'john@test.com' }) }) - }); - }); - - test('should retrieve a new access token and update the session based on afterRefresh', async () => { - const res = await getAccessTokenResponse({ - authenticated: true, - getAccessTokenOpts: { - refresh: true, - afterRefresh(_req, _res, session) { - return { ...session, foo: 'baz' }; - } - } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'new-token' }, - session: expect.objectContaining({ foo: 'baz' }) - }); + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/The user does not have a valid access token/) }); }); - describe('app router (server component)', () => { - test('should return an access token', async () => { - const res = await getAccessTokenResponse({ + test('should fail if access_token expiry is missing', async () => { + await expect( + getAccessTokenResponse({ authenticated: true, - userRsc: true - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'eyJz93a...k4laUWw' } - }); - }); - - test('should retrieve a new access token if the old one is expired and update the profile', async () => { - const res = await getAccessTokenResponse({ - authenticated: true, - userRsc: true, loginOpts: { callbackOpts: { afterCallback(_req: NextRequest, session: Session) { - return { ...session, accessTokenExpiresAt: -60 }; + delete session.accessTokenExpiresAt; + return session; } } } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'new-token' }, - session: expect.objectContaining({ user: expect.objectContaining({ email: 'john@test.com' }) }) - }); - }); - - test('should retrieve a new access token and update the session based on afterRefresh', async () => { - const res = await getAccessTokenResponse({ - authenticated: true, - userRsc: true, - getAccessTokenOpts: { - refresh: true, - afterRefresh(_req, _res, session) { - return { ...session, foo: 'baz' }; - } - } - }); - expect(res.status).toBe(200); - await expect(res.json()).resolves.toMatchObject({ - at: { accessToken: 'new-token' }, - session: expect.objectContaining({ foo: 'baz' }) - }); + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/Expiration information for the access token is not available/) }); }); - describe('page router', () => { - afterEach(teardown); - - test('should fail if the session is missing', async () => { - const baseUrl = await setup(withApi); - - await expect(get(baseUrl, '/api/access-token')).rejects.toThrow('The user does not have a valid session.'); - }); - - test('should fail if access_token and refresh_token are missing', async () => { - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - delete session.accessToken; - delete session.refreshToken; - return session; - } - } - }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'The user does not have a valid access token.' - ); - }); - - test('should fail if access_token expiry is missing', async () => { - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - delete session.accessTokenExpiresAt; - return session; - } - } - }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'Expiration information for the access token is not available. The user will need to sign in again.' - ); - }); - - test('should fail if access_token scope is missing', async () => { - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - delete session.accessTokenScope; - return session; + test('should fail if access_token scope is missing', async () => { + await expect( + getAccessTokenResponse({ + authenticated: true, + loginOpts: { + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + delete session.accessTokenScope; + return session; + } } }, - getAccessTokenOptions: { + getAccessTokenOpts: { scopes: ['read:foo'] } - }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'An access token with the requested scopes could not be provided. The user will need to sign in again.' - ); + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/An access token with the requested scopes could not be provided/) }); + }); - test("should fail if access_token scope doesn't match requested scope", async () => { - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - session.accessTokenScope = 'read:bar'; - return session; + test("should fail if access_token scope doesn't match requested scope", async () => { + await expect( + getAccessTokenResponse({ + authenticated: true, + loginOpts: { + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + return { ...session, accessTokenScope: 'read:bar' }; + } } }, - getAccessTokenOptions: { + getAccessTokenOpts: { scopes: ['read:foo'] } - }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'Could not retrieve an access token with scopes "read:foo". The user will need to sign in again.' - ); + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/Could not retrieve an access token with scopes "read:foo"/) }); + }); - test('should fail if the access token is expired', async () => { - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - delete session.refreshToken; - session.accessTokenExpiresAt = -60; - return session; + test('should fail if the access token is expired', async () => { + await expect( + getAccessTokenResponse({ + authenticated: true, + loginOpts: { + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + delete session.refreshToken; + return { ...session, accessTokenExpiresAt: -60 }; + } } } - }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'The access token expired and a refresh token is not available. The user will need to sign in again.' - ); + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/The access token expired and a refresh token is not available/) }); + }); - test('should fail if you try to refresh the access token without a refresh token', async () => { - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - delete session.refreshToken; - return session; + test('should fail if you try to refresh the access token without a refresh token', async () => { + await expect( + getAccessTokenResponse({ + authenticated: true, + loginOpts: { + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + delete session.refreshToken; + return session; + } } }, - getAccessTokenOptions: { refresh: true } - }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'A refresh token is required to refresh the access token, but none is present.' - ); + getAccessTokenOpts: { refresh: true } + }) + ).resolves.toMatchObject({ + status: 500, + statusText: expect.stringMatching(/A refresh token is required to refresh the access token, but none is present/) }); + }); - test('should return an access token', async () => { - const baseUrl = await setup(withApi); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('eyJz93a...k4laUWw'); + test('should return an access token', async () => { + const res = await getAccessTokenResponse({ + authenticated: true }); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'eyJz93a...k4laUWw' } + }); + }); - test('should retrieve a new access token if the old one is expired and update the profile', async () => { - await refreshTokenExchange( - withApi, - 'GEbRxBN...edjnXbL', - { - email: 'john@test.com', - name: 'john doe', - sub: '123' - }, - 'new-token' - ); - const baseUrl = await setup(withApi, { - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - session.accessTokenExpiresAt = -60; - return session; + test('should retrieve a new access token if the old one is expired and update the profile', async () => { + const res = await getAccessTokenResponse({ + authenticated: true, + loginOpts: { + callbackOpts: { + afterCallback(_req: NextRequest, session: Session) { + return { ...session, accessTokenExpiresAt: -60 }; } } - }); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - const { refreshToken } = await get(baseUrl, '/api/session', { cookieJar }); - expect(refreshToken).toEqual('GEbRxBN...edjnXbL'); - }); - - test('should retrieve a new access token if force refresh is set', async () => { - await refreshTokenExchange( - withApi, - 'GEbRxBN...edjnXbL', - { - email: 'john@test.com', - name: 'john doe', - sub: '123' - }, - 'new-token' - ); - const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - const { refreshToken } = await get(baseUrl, '/api/session', { cookieJar }); - expect(refreshToken).toEqual('GEbRxBN...edjnXbL'); - }); - - test('should fail when refresh grant fails', async () => { - await failedRefreshTokenExchange(withApi, 'GEbRxBN...edjnXbL', {}, 500); - const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'The request to refresh the access token failed. CAUSE: expected 200 OK, got: 500 Internal Server Error' - ); - }); - - test('should fail when refresh grant fails with oauth error', async () => { - await failedRefreshTokenExchange( - withApi, - 'GEbRxBN...edjnXbL', - { error: 'invalid_grant', error_description: 'Unknown or invalid refresh token.' }, - 401 - ); - const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'The request to refresh the access token failed. CAUSE: invalid_grant (Unknown or invalid refresh token.)' - ); + } }); - - test('should escape oauth error', async () => { - await failedRefreshTokenExchange( - withApi, - 'GEbRxBN...edjnXbL', - { error: '', error_description: '' }, - 401 - ); - const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); - const cookieJar = await login(baseUrl); - await expect(get(baseUrl, '/api/access-token', { cookieJar })).rejects.toThrow( - 'The request to refresh the access token failed. CAUSE: <script>alert(1)</script> (<script>alert(2)</script>)' - ); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'new-token' }, + session: expect.objectContaining({ user: expect.objectContaining({ email: 'john@test.com' }) }) }); + }); - test('should retrieve a new access token and rotate the refresh token', async () => { - await refreshTokenRotationExchange( - withApi, - 'GEbRxBN...edjnXbL', - { - email: 'john@test.com', - name: 'john doe', - sub: '123' - }, - 'new-token', - 'new-refresh-token' - ); - const baseUrl = await setup(withApi, { getAccessTokenOptions: { refresh: true } }); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - const { refreshToken } = await get(baseUrl, '/api/session', { cookieJar }); - expect(refreshToken).toEqual('new-refresh-token'); + test('should retrieve a new access token if force refresh is set', async () => { + const res = await getAccessTokenResponse({ + authenticated: true, + getAccessTokenOpts: { refresh: true } }); - - test('should return an access token with the given scopes', async () => { - const baseUrl = await setup(withApi, { getAccessTokenOptions: { scopes: ['read:foo'] } }); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('eyJz93a...k4laUWw'); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'new-token' }, + session: expect.objectContaining({ user: expect.objectContaining({ email: 'john@test.com' }) }) }); + }); - test('should not overwrite custom session properties when applying a new access token', async () => { - await refreshTokenExchange( - withApi, - 'GEbRxBN...edjnXbL', - { - email: 'john@test.com', - name: 'john doe', - sub: '123' - }, - 'new-token' - ); - const baseUrl = await setup(withApi, { - getAccessTokenOptions: { refresh: true }, - callbackOptions: { - afterCallback: (_req: NextApiRequest, _res: NextApiResponse, session: Session): Session => { - session.foo = 'bar'; - session.user.bar = 'baz'; - return session; - } - } - }); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - const session = await get(baseUrl, '/api/session', { cookieJar }); - expect(session).toMatchObject({ - foo: 'bar', - accessToken: 'new-token', - refreshToken: 'GEbRxBN...edjnXbL', - user: { - nickname: '__test_nickname__', - email: 'john@test.com', - name: 'john doe', - sub: '123', - bar: 'baz' + test('should retrieve a new access token and update the session based on afterRefresh', async () => { + const res = await getAccessTokenResponse({ + authenticated: true, + getAccessTokenOpts: { + refresh: true, + afterRefresh(_req, _res, session) { + return { ...session, foo: 'baz' }; } - }); + } }); - - test('should retrieve a new access token and update the session based on afterRefresh', async () => { - await refreshTokenExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-token'); - const baseUrl = await setup(withApi, { - getAccessTokenOptions: { - refresh: true, - afterRefresh(_req, _res, session) { - delete session.accessTokenScope; - return session as Session; - } - } - }); - const cookieJar = await login(baseUrl); - const { accessTokenScope } = await get(baseUrl, '/api/session', { cookieJar }); - expect(accessTokenScope).not.toBeUndefined(); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - const { accessTokenScope: newAccessTokenScope } = await get(baseUrl, '/api/session', { - cookieJar - }); - expect(newAccessTokenScope).toBeUndefined(); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'new-token' }, + session: expect.objectContaining({ foo: 'baz' }) }); + }); - test('should retrieve a new access token and update the session based on the storeIDToken config', async () => { - await refreshTokenExchange(withApi, 'GEbRxBN...edjnXbL', {}, 'new-token'); - const baseUrl = await setup( - { ...withApi, session: { storeIDToken: false } }, - { - getAccessTokenOptions: { - refresh: true - } + test('should fail when the refresh grant request fails', async () => { + const res = await getAccessTokenResponse({ + authenticated: true, + getAccessTokenOpts: { + refresh: true, + afterRefresh(_req, _res, session) { + return { ...session, foo: 'baz' }; } - ); - const cookieJar = await login(baseUrl); - const session = await get(baseUrl, '/api/session', { cookieJar }); - expect(session.idToken).toBeUndefined(); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - const newSession = await get(baseUrl, '/api/session', { - cookieJar - }); - expect(newSession.idToken).toBeUndefined(); + } }); - - test('should pass custom auth params in refresh grant request body', async () => { - const idToken = await makeIdToken({ - iss: `${withApi.issuerBaseURL}/`, - aud: withApi.clientID, - email: 'john@test.com', - name: 'john doe', - sub: '123' - }); - - const spy = jest.fn(); - nock(`${withApi.issuerBaseURL}`) - .post('/oauth/token', /grant_type=refresh_token/) - .reply(200, (_, body) => { - spy(body); - return { - access_token: 'new-token', - id_token: idToken, - token_type: 'Bearer', - expires_in: 750, - scope: 'read:foo write:foo' - }; - }); - - const baseUrl = await setup(withApi, { - getAccessTokenOptions: { refresh: true, authorizationParams: { baz: 'qux' } } - }); - const cookieJar = await login(baseUrl); - const { accessToken } = await get(baseUrl, '/api/access-token', { cookieJar }); - expect(accessToken).toEqual('new-token'); - expect(spy).toHaveBeenCalledWith(expect.stringContaining('baz=qux')); + expect(res.status).toBe(200); + await expect(res.json()).resolves.toMatchObject({ + at: { accessToken: 'new-token' }, + session: expect.objectContaining({ foo: 'baz' }) }); }); }); diff --git a/tests/session/session.test.ts b/tests/session/session.test.ts index 7947159a0..3c68c8498 100644 --- a/tests/session/session.test.ts +++ b/tests/session/session.test.ts @@ -1,5 +1,5 @@ import { TokenSet } from 'openid-client'; -import { fromJson, fromTokenSet } from '../../src/session'; +import { fromJson, fromTokenEndpointResponse } from '../../src/session'; import { makeIdToken } from '../auth0-session/fixtures/cert'; import { Session } from '../../src'; @@ -15,7 +15,7 @@ describe('session', () => { describe('from tokenSet', () => { test('should construct a session from a tokenSet', async () => { expect( - fromTokenSet(new TokenSet({ id_token: await makeIdToken({ foo: 'bar', bax: 'qux' }) }), { + fromTokenEndpointResponse(new TokenSet({ id_token: await makeIdToken({ foo: 'bar', bax: 'qux' }) }), { identityClaimFilter: ['baz'], routes, getLoginState, @@ -36,7 +36,7 @@ describe('session', () => { test('should store the ID Token by default', async () => { expect( - fromTokenSet(new TokenSet({ id_token: await makeIdToken({ foo: 'bar' }) }), { + fromTokenEndpointResponse(new TokenSet({ id_token: await makeIdToken({ foo: 'bar' }) }), { identityClaimFilter: ['baz'], routes, getLoginState, @@ -47,7 +47,7 @@ describe('session', () => { test('should not store the ID Token', async () => { expect( - fromTokenSet(new TokenSet({ id_token: await makeIdToken({ foo: 'bar' }) }), { + fromTokenEndpointResponse(new TokenSet({ id_token: await makeIdToken({ foo: 'bar' }) }), { session: { storeIDToken: false, name: '', diff --git a/tests/session/update-session.test.ts b/tests/session/update-session.test.ts index 2091ded5d..537f63c3c 100644 --- a/tests/session/update-session.test.ts +++ b/tests/session/update-session.test.ts @@ -1,6 +1,5 @@ import { NextRequest, NextResponse } from 'next/server'; import { cookies as nextCookies } from 'next/headers'; -import { mocked } from 'ts-jest/utils'; import { CookieJar } from 'tough-cookie'; import { login, setup, teardown } from '../fixtures/setup'; import { withApi, withoutApi } from '../fixtures/default-settings'; @@ -37,7 +36,7 @@ describe('update-user', () => { // Note: An updated session from a React Server Component will not persist // because you can't write to a cookie from a RSC in the current version of Next.js // This test passes because we're mocking the dynamic `cookies` function. - mocked(nextCookies).mockImplementation(() => loginRes.cookies); + jest.mocked(nextCookies).mockImplementation(() => loginRes.cookies); const auth0Instance = initAuth0(withApi); const res = await getResponse({ url: '/api/auth/update', diff --git a/tests/utils/errors.test.ts b/tests/utils/errors.test.ts index da76adbb0..f1a2c9111 100644 --- a/tests/utils/errors.test.ts +++ b/tests/utils/errors.test.ts @@ -54,10 +54,6 @@ describe('AccessTokenError', () => { }); describe('HandlerError', () => { - test('should not be instance of itself', () => { - expect(new HandlerError({ code: '', message: '', name: '', cause: new Error() })).not.toBeInstanceOf(HandlerError); - }); - test('should set all required properties', () => { const code = 'foo'; const message = 'bar'; diff --git a/tsconfig.json b/tsconfig.json index e1c0070bd..7336ba556 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,7 @@ "sourceMap": true, "skipLibCheck": true, "strict": true, - "target": "es5", + "target": "ES2017", "useUnknownInCatchVariables": false, "lib": ["es6", "dom"], "downlevelIteration": true,