diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index 2054d695d8..acccc76c70 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -8,16 +8,17 @@ on: paths: - ".github/workflows/ci-build.yml" - "backend/**" - - "frontend/**" + - "frontend/apps/**" - ".dockerignore" - "docker-init.sh" - "Dockerfile" - "!**.md" + - "!frontend/packages/**" pull_request: paths: - ".github/workflows/ci-build.yml" - "backend/**" - - "frontend/**" + - "frontend/apps/**" - ".dockerignore" - "docker-init.sh" - "Dockerfile" diff --git a/.github/workflows/ci-frontend-api.yml b/.github/workflows/ci-frontend-api.yml new file mode 100644 index 0000000000..9ca0102a14 --- /dev/null +++ b/.github/workflows/ci-frontend-api.yml @@ -0,0 +1,153 @@ +name: "@remark42/api" + +on: + push: + branches: + - master + paths: + - ".github/workflows/ci-frontend-api.yml" + - "frontend/packages/**" + - "!**.md" + pull_request: + paths: + - ".github/workflows/ci-frontend-api.yml" + - "frontend/packages/**" + - "!**.md" + +jobs: + type-check: + name: Type check + runs-on: ubuntu-latest + strategy: + matrix: + node: [16.15.1] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + + - name: Install pnpm + uses: pnpm/action-setup@v2.0.1 + id: pnpm-install + with: + version: 7 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - name: Setup pnpm cache + uses: actions/cache@v3 + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm i + working-directory: ./frontend + + - name: Run type check + run: pnpm type-check:api + working-directory: ./frontend + + lint: + name: Lint + runs-on: ubuntu-latest + strategy: + matrix: + node: [16.15.1] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + + - name: Install pnpm + uses: pnpm/action-setup@v2.0.1 + id: pnpm-install + with: + version: 7 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - name: Setup pnpm cache + uses: actions/cache@v3 + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm i + working-directory: ./frontend + + - name: Run linters + run: pnpm lint:api + working-directory: ./frontend/ + + test: + name: Tests & Coverage + runs-on: ubuntu-latest + strategy: + matrix: + node: [16.15.1] + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + + - name: Install pnpm + uses: pnpm/action-setup@v2.0.1 + id: pnpm-install + with: + version: 7 + run_install: false + + - name: Get pnpm store directory + id: pnpm-cache + run: | + echo "::set-output name=pnpm_cache_dir::$(pnpm store path)" + + - name: Setup pnpm cache + uses: actions/cache@v3 + with: + path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm i + working-directory: ./frontend + + - name: Test & Coverage + run: pnpm coverage:api + working-directory: ./frontend + + - name: Submit coverage + run: ${{ github.workspace }}/frontend/apps/remark42/node_modules/.bin/codecov + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/frontend/package.json b/frontend/package.json index b55fa06188..d8b8f5d072 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -10,10 +10,15 @@ ], "scripts": { "prepare": "if [ -z \"$CI\" ]; then cd .. && husky install frontend/.husky; else echo \"Skip Husky Hooks\"; fi", - "lint-staged": "lint-staged" + "lint-staged": "lint-staged", + "test:api": "turbo run test --filter=@remark42/api", + "coverage:api": "turbo run coverage --filter=@remark42/api", + "type-check:api": "turbo run type-check --filter=@remark42/api", + "lint:api": "turbo run lint --filter=@remark42/api" }, "devDependencies": { "husky": "^8.0.1", - "lint-staged": "^13.0.3" + "lint-staged": "^13.0.3", + "turbo": "^1.4.3" } } diff --git a/frontend/packages/api/.eslintignore b/frontend/packages/api/.eslintignore new file mode 100644 index 0000000000..009af5438f --- /dev/null +++ b/frontend/packages/api/.eslintignore @@ -0,0 +1,2 @@ +dist +coverage diff --git a/frontend/packages/api/.eslintrc.cjs b/frontend/packages/api/.eslintrc.cjs new file mode 100644 index 0000000000..78bb8a1524 --- /dev/null +++ b/frontend/packages/api/.eslintrc.cjs @@ -0,0 +1,22 @@ +module.exports = { + env: { + browser: true, + es2021: true, + node: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:@typescript-eslint/recommended-requiring-type-checking', + 'plugin:@typescript-eslint/strict', + 'plugin:prettier/recommended', + ], + overrides: [], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: './tsconfig.eslint.json', + }, + plugins: ['@typescript-eslint'], +} diff --git a/frontend/packages/api/.gitignore b/frontend/packages/api/.gitignore new file mode 100644 index 0000000000..c189a76ee8 --- /dev/null +++ b/frontend/packages/api/.gitignore @@ -0,0 +1,5 @@ +node_modules +coverage +dist +**/*.js +**/*.d.ts \ No newline at end of file diff --git a/frontend/packages/api/.lintstagedrc.cjs b/frontend/packages/api/.lintstagedrc.cjs new file mode 100644 index 0000000000..ac21e2e6f4 --- /dev/null +++ b/frontend/packages/api/.lintstagedrc.cjs @@ -0,0 +1,3 @@ +module.exports = { + './**/*.ts': ['pnpm lint-staged:lint'], +} diff --git a/frontend/packages/api/.npmignore b/frontend/packages/api/.npmignore new file mode 100644 index 0000000000..a2c6d94722 --- /dev/null +++ b/frontend/packages/api/.npmignore @@ -0,0 +1,17 @@ +coverage/** +dist/** +node_modules/** +src/** +test/** +.editorconfig +.eslintrc.cjs +.prettierrc +files.txt +jest.config.ts +pnpm-lock.yaml +postpublish.sh +prepublish.sh +tsconfig.common.json +tsconfig.dev.json +tsconfig.json + diff --git a/frontend/packages/api/.nvmrc b/frontend/packages/api/.nvmrc new file mode 100644 index 0000000000..975215f459 --- /dev/null +++ b/frontend/packages/api/.nvmrc @@ -0,0 +1 @@ +16.17.0 \ No newline at end of file diff --git a/frontend/packages/api/.prettierrc b/frontend/packages/api/.prettierrc new file mode 100644 index 0000000000..521053ec72 --- /dev/null +++ b/frontend/packages/api/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": false, + "printWidth": 100, + "quoteProps": "consistent", + "singleQuote": true +} diff --git a/frontend/packages/api/README.md b/frontend/packages/api/README.md new file mode 100644 index 0000000000..7d6256f4e9 --- /dev/null +++ b/frontend/packages/api/README.md @@ -0,0 +1,11 @@ +# @remark42/api + +Implementation of API methods for Remark42 + +## Development + +- If you don't have `pnpm` installed run `npm i -g pnpm` +- Install dependencies `pnpm i` +- Run development mode with `pnpm run dev` +- Build lib with `pnpm run build` +- Run tests with `pnpm run test` diff --git a/frontend/packages/api/clients/admin.ts b/frontend/packages/api/clients/admin.ts new file mode 100644 index 0000000000..474ce24f9f --- /dev/null +++ b/frontend/packages/api/clients/admin.ts @@ -0,0 +1,134 @@ +import type { ClientParams, User } from './index' +import { API_BASE } from '../consts' +import { createFetcher } from '../lib/fetcher' + +export type BlockTTL = 'permanently' | '43200m' | '10080m' | '1440m' +export interface BlockUserResponse { + block: boolean + site_id: string + user_id: string +} + +export function createAdminClient({ siteId, baseUrl }: ClientParams) { + const fetcher = createFetcher(siteId, `${baseUrl}${API_BASE}`) + + async function toggleUserVerification(id: string, verified: 0 | 1): Promise { + return fetcher.put(`/verify/${id}`, { verified }) + } + + async function toggleCommentPin(id: string, pinned: 0 | 1): Promise { + return fetcher.put(`/pin/${id}`, { pinned }) + } + + async function toggleCommenting(url: string, ro: 0 | 1): Promise { + return fetcher.put('/readonly', { url, ro }) + } + + async function toggleUserBlock(id: string, ttl?: BlockTTL): Promise { + const params = ttl + ? { + block: 1, + ttl: ttl === 'permanently' ? 0 : ttl, + } + : { block: 0 } + + return fetcher.put(`/user/${id}`, params) + } + + /** + * Request list of blocked users + */ + async function getBlockedUsers(): Promise { + return fetcher.get('/blocked') + } + + /** + * Block user from commenting + * @param id user ID + * @param ttl block duration + */ + async function blockUser(id: string, ttl: BlockTTL): Promise { + return toggleUserBlock(id, ttl) + } + + /** + * Unblock user from commenting + * @param id user ID + */ + async function unblockUser(id: string): Promise { + return toggleUserBlock(id) + } + + /** + * Mark user as verified + * @param id user ID + */ + async function verifyUser(id: string): Promise { + return toggleUserVerification(id, 1) + } + /** + * Mark user as unverified + * @param id user ID + */ + async function unverifyUser(id: string): Promise { + return toggleUserVerification(id, 0) + } + /** + * Approve request to remove user data + * @param token token from email + */ + async function approveRemovingRequest(token: string): Promise { + return fetcher.get('/deleteme', { token }) + } + + /** + * Mark comment as pinned + * @param id comment ID + */ + async function pinComment(id: string): Promise { + return toggleCommentPin(id, 1) + } + /** + * Mark comment as unpinned + * @param id comment ID + */ + async function unpinComment(id: string): Promise { + return toggleCommentPin(id, 0) + } + /** + * Remove comment + * @param url page URL + * @param id comment ID + */ + async function removeComment(url: string, id: string): Promise { + return fetcher.delete(`/comment/${id}`, { url }) + } + /** + * Enable commenting on a page + * @param url page URL + */ + async function enableCommenting(url: string) { + return toggleCommenting(url, 1) + } + /** + * Disable commenting on a page + * @param url page URL + */ + async function disableCommenting(url: string) { + return toggleCommenting(url, 0) + } + + return { + getBlockedUsers, + blockUser, + unblockUser, + verifyUser, + unverifyUser, + approveRemovingRequest, + pinComment, + unpinComment, + removeComment, + enableCommenting, + disableCommenting, + } +} diff --git a/frontend/packages/api/clients/auth.ts b/frontend/packages/api/clients/auth.ts new file mode 100644 index 0000000000..75631328e5 --- /dev/null +++ b/frontend/packages/api/clients/auth.ts @@ -0,0 +1,47 @@ +import type { ClientParams, User } from './index' +import { createFetcher } from '../lib/fetcher' + +export function createAuthClient({ siteId, baseUrl }: ClientParams) { + const fetcher = createFetcher(siteId, `${baseUrl}/auth`) + + async function anonymous(user: string): Promise { + return fetcher.get('/anonymous/login', { user, aud: siteId }) + } + + async function email(email: string, username: string): Promise<(token: string) => Promise> { + const EMAIL_SIGNIN_ENDPOINT = '/email/login' + + await fetcher.get(EMAIL_SIGNIN_ENDPOINT, { address: email, user: username }) + + return function tokenVerification(token: string): Promise { + return fetcher.get(EMAIL_SIGNIN_ENDPOINT, { token }) + } + } + + async function telegram() { + const TELEGRAM_SIGNIN_ENDPOINT = '/telegram/login' + + const { bot, token } = await fetcher.get<{ bot: string; token: string }>( + TELEGRAM_SIGNIN_ENDPOINT + ) + + return { + bot, + token, + verify() { + return fetcher.get(TELEGRAM_SIGNIN_ENDPOINT, { token }) + }, + } + } + + async function logout(): Promise { + return fetcher.get('/logout') + } + + return { + anonymous, + email, + telegram, + logout, + } +} diff --git a/frontend/packages/api/clients/index.ts b/frontend/packages/api/clients/index.ts new file mode 100644 index 0000000000..53647888de --- /dev/null +++ b/frontend/packages/api/clients/index.ts @@ -0,0 +1,55 @@ +import { createAdminClient } from './admin' +import { createAuthClient } from './auth' +import { createPublicClient } from './public' + +export interface User { + id: string + name: string + /** url to avatar */ + picture: string + admin: boolean + block: boolean + verified: boolean + /** subscription to email notification */ + email_subscription?: boolean + /** users with Patreon auth can have paid status */ + paid_sub?: boolean +} + +export type OAuthProvider = + | 'facebook' + | 'twitter' + | 'google' + | 'yandex' + | 'github' + | 'microsoft' + | 'patreon' + | 'telegram' + | 'dev' +export type FormProvider = 'email' | 'anonymous' +export type Provider = OAuthProvider | FormProvider + +export interface ClientParams { + siteId: string + baseUrl: string +} + +export interface Client { + admin: ReturnType + auth: ReturnType + public: ReturnType +} + +let client: Client | undefined + +export function createClient(params: ClientParams): Client { + if (client === undefined) { + client = { + auth: createAuthClient(params), + admin: createAdminClient(params), + public: createPublicClient(params), + } + } + + return client +} diff --git a/frontend/packages/api/clients/public.ts b/frontend/packages/api/clients/public.ts new file mode 100644 index 0000000000..1a8e672eb5 --- /dev/null +++ b/frontend/packages/api/clients/public.ts @@ -0,0 +1,153 @@ +import type { ClientParams, Provider, User } from './index' +import { createFetcher } from '../lib/fetcher' +import { API_BASE } from '../consts' + +export interface Config { + version: string + auth_providers: Provider[] + edit_duration: number + max_comment_size: number + admins: string[] + admin_email: string + low_score: number + critical_score: number + positive_score: boolean + readonly_age: number + max_image_size: number + simple_view: boolean + anon_vote: boolean + email_notifications: boolean + telegram_bot_username: string + emoji_enabled: boolean +} + +export interface Comment { + /** comment id */ + id: string + /** parent id */ + pid: string + /** comment text, after md processing */ + text: string + /** original comment text */ + orig?: string + user: User + locator: { + /** site id */ + site: string + /** page url */ + url: string + } + score: number + voted_ips: { Timestamp: string; Value: boolean }[] + /** + * vote delta, + * if user hasn't voted delta will be 0, + * -1/+1 for downvote/upvote + */ + vote: 0 | 1 | -1 + /** comment controversy */ + controversy?: number + /** pointer to have empty default in json response */ + edit?: { + time: string + summary: string + } + /** timestamp */ + time: string + pin?: boolean + delete?: boolean + /** page title */ + title?: string +} + +export interface CommentsTree { + comment: Comment + replies: Comment[] +} + +export interface CommentPayload { + title?: string + pid?: string + text: string +} + +export type Sort = '-active' | '+active' +export interface GetUserCommentsParams { + url: string + sort?: Sort + limit?: number + skip?: number +} +export type Vote = -1 | 1 + +export function createPublicClient({ siteId: site, baseUrl }: ClientParams) { + const fetcher = createFetcher(site, `${baseUrl}${API_BASE}`) + + /** + * Get server config + */ + async function getConfig(): Promise { + return fetcher.get('/config') + } + + /** + * Get current authorized user + */ + async function getUser(): Promise { + return fetcher.get('/user').catch(() => null) + } + + /** + * Get comments + */ + async function getComments(url: string): Promise + async function getComments(params: GetUserCommentsParams): Promise + async function getComments( + params: string | GetUserCommentsParams + ): Promise { + if (typeof params === 'string') { + return fetcher.get('/comments', { url: params }) + } + + return fetcher.get('/find', { ...params, format: 'tree' }) + } + + /** + * Add new comment + */ + async function addComment(url: string, payload: CommentPayload): Promise { + const locator = { site, url } + return fetcher.post('/comment', {}, { ...payload, locator }) + } + + /** + * Update comment + */ + async function updateComment(url: string, id: string, text: string): Promise { + return fetcher.put(`/comment/${id}`, { url }, { text }) + } + + /** + * Remove comment on a page + */ + async function removeComment(url: string, id: string): Promise { + return fetcher.put(`/comment/${id}`, { url }, { delete: true }) + } + + /** + * Vote for a comment + */ + async function vote(url: string, id: string, vote: Vote): Promise<{ id: string; vote: number }> { + return fetcher.put<{ id: string; vote: number }>(`/vote/${id}`, { url, vote }) + } + + return { + getConfig, + getUser, + getComments, + addComment, + updateComment, + removeComment, + vote, + } +} diff --git a/frontend/packages/api/consts.ts b/frontend/packages/api/consts.ts new file mode 100644 index 0000000000..7ea6b1e577 --- /dev/null +++ b/frontend/packages/api/consts.ts @@ -0,0 +1,11 @@ +/** Base path to API */ +export const API_BASE = '/api/v1' + +/** Header name for JWT token */ +export const JWT_HEADER = 'X-JWT' + +/** Header name for XSRF token */ +export const XSRF_HEADER = 'X-XSRF-TOKEN' + +/** Cookie field with XSRF token */ +export const XSRF_COOKIE = 'XSRF-TOKEN' diff --git a/frontend/packages/api/index.ts b/frontend/packages/api/index.ts new file mode 100644 index 0000000000..fe46378446 --- /dev/null +++ b/frontend/packages/api/index.ts @@ -0,0 +1,4 @@ +export * from './clients' +export * from './clients/admin' +export * from './clients/auth' +export * from './clients/public' diff --git a/frontend/packages/api/lib/cookies.ts b/frontend/packages/api/lib/cookies.ts new file mode 100644 index 0000000000..cf84643148 --- /dev/null +++ b/frontend/packages/api/lib/cookies.ts @@ -0,0 +1,11 @@ +export function getCookie(name: string): string | undefined { + const matches = document.cookie.match( + new RegExp(`(?:^|; )${name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1')}=([^;]*)`) + ) + + if (matches === null) { + return + } + + return decodeURIComponent(matches[1]) +} diff --git a/frontend/packages/api/lib/fetcher.ts b/frontend/packages/api/lib/fetcher.ts new file mode 100644 index 0000000000..bdaf4e77b8 --- /dev/null +++ b/frontend/packages/api/lib/fetcher.ts @@ -0,0 +1,94 @@ +import { JWT_HEADER, XSRF_COOKIE, XSRF_HEADER } from '../consts' +import { getCookie } from '../lib/cookies' + +export type QueryParams = Record +export type Payload = BodyInit | Record | null +export type BodylessMethod = (url: string, query?: QueryParams) => Promise +export type BodyMethod = (url: string, query?: QueryParams, body?: Payload) => Promise +export interface Client { + get: BodylessMethod + put: BodyMethod + post: BodyMethod + delete: BodylessMethod +} + +/** JWT token received from server and will be send by each request, if it present */ +let token: string | undefined + +export const createFetcher = (site: string, baseUrl: string): Client => { + const client = { + get: (uri: string, query?: QueryParams): Promise => request('get', uri, query), + put: (uri: string, query?: QueryParams, body?: Payload): Promise => + request('put', uri, query, body), + post: (uri: string, query?: QueryParams, body?: Payload): Promise => + request('post', uri, query, body), + delete: (uri: string, query?: QueryParams, body?: Payload): Promise => + request('delete', uri, query, body), + } + + /** + * Fetcher is abstraction on top of fetch + * + * @method - a string to set http method + * @uri – uri to API endpoint + * @query - collection of query params. They will be concatenated to URL. `siteId` will be added automatically. + * @body - data for sending to the server. If you pass object it will be stringified. If you pass form data it will be sent as is. Content type headers will be added automatically. + */ + async function request( + method: string, + uri: string, + query: QueryParams = {}, + body?: Payload + ): Promise { + const searchParams = new URLSearchParams({ site, ...query }) + searchParams.sort() + const url = `${baseUrl}${uri}?${searchParams.toString()}` + const headers = new Headers() + const params: RequestInit = { method, headers } + + // Save token in memory and pass it into headers in case if storing cookies is disabled + if (token) { + headers.set(JWT_HEADER, token) + } + + // An HTTP header cannot be empty. + // Although some webservers allow this (nginx, Apache), others answer 400 Bad Request (lighttpd). + const xsrfToken = getCookie(XSRF_COOKIE) + if (typeof xsrfToken === 'string') { + headers.set(XSRF_HEADER, xsrfToken) + } + + if (typeof body === 'object' && body !== null && !(body instanceof FormData)) { + headers.set('Content-Type', 'application/json') + params.body = JSON.stringify(body) + } else { + params.body = body + } + + return fetch(url, params).then((res) => { + if ([401, 403].includes(res.status)) { + token = undefined + + return Promise.reject('Unauthorized') + } + + token = res.headers.get(JWT_HEADER) ?? token + + return res + .text() + .catch(Object) + .then((data: string) => { + if (res.status < 200 || res.status > 299) { + return Promise.reject(data) + } + try { + return JSON.parse(data) as T + } catch (e) { + return data as unknown as T + } + }) + }) + } + + return client +} diff --git a/frontend/packages/api/package.json b/frontend/packages/api/package.json new file mode 100644 index 0000000000..36cd753796 --- /dev/null +++ b/frontend/packages/api/package.json @@ -0,0 +1,57 @@ +{ + "name": "@remark42/api", + "version": "0.6.0-alpha.11", + "description": "Implementation of API methods for Remark42", + "repository": { + "type": "git", + "url": "git+https://github.com/umputun/remark42.git#master" + }, + "bugs": { + "url": "https://github.com/umputun/remark42/issues" + }, + "homepage": "https://github.com/umputun/remark42/tree/master/frontend/packages/api#readme", + "keywords": [ + "remark42", + "comments" + ], + "author": "Paul Mineev", + "license": "MIT", + "scripts": { + "dev": "tsc -w --incremental", + "build:cjs": "tsc --module CommonJS", + "build:esm": "tsc --module ESNext", + "build": "npm-run-all cleanup --parallel build:*", + "postpublish": "pnpm run cleanup", + "cleanup": "rm -rf *.js *.d.ts **/*.js **/*.d.ts *.tsbuildinfo", + "test": "vitest", + "coverage": "vitest run --coverage", + "lint": "eslint --ext .cjs,.mjs,.ts --max-warnings=0", + "type-check": "tsc --noEmit", + "lint-staged:lint": "eslint --fix --ext .cjs,.mjs,.ts" + }, + "devDependencies": { + "@types/node": "^18.0.5", + "@typescript-eslint/eslint-plugin": "^5.33.1", + "@typescript-eslint/parser": "^5.33.1", + "@vitest/coverage-c8": "^0.22.1", + "eslint": "^8.18.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-prettier": "^4.2.1", + "jsdom": "^20.0.0", + "msw": "^0.44.1", + "npm-run-all": "^4.1.5", + "prettier": "^2.7.1", + "ts-node": "^10.9.1", + "tslib": "^2.4.0", + "typescript": "^4.7.4", + "vitest": "^0.22.1", + "whatwg-fetch": "^3.6.2" + }, + "type": "module", + "files": [ + "./*.js", + "./*.d.ts", + "./clients/*.d.ts", + "./lib/*.d.ts" + ] +} diff --git a/frontend/packages/api/tests/clients/admin.test.ts b/frontend/packages/api/tests/clients/admin.test.ts new file mode 100644 index 0000000000..f672597ee7 --- /dev/null +++ b/frontend/packages/api/tests/clients/admin.test.ts @@ -0,0 +1,105 @@ +import { beforeEach, describe, expect } from 'vitest' +import { mockEndpoint } from '../test-utils' +import { BlockTTL, createAdminClient } from '../../clients/admin' + +interface Context { + client: ReturnType +} + +describe('Admin Client', (adminClient) => { + beforeEach((ctx) => { + ctx.client = createAdminClient({ siteId: 'mysite', baseUrl: '/remark42' }) + }) + + adminClient('should return list of blocked users', async ({ client }) => { + const data = [{ id: 1 }, { id: 2 }] + + mockEndpoint('/remark42/api/v1/blocked', { body: data }) + await expect(client.getBlockedUsers()).resolves.toEqual(data) + }) + + const ttlCases: [BlockTTL, string][] = [ + ['permanently', '0'], + ['1440m', '1440m'], + ['43200m', '43200m'], + ] + + ttlCases.forEach(([ttl, expected]) => { + adminClient(`should block user with ttl: ${ttl}`, async ({ client }) => { + const data = { block: true, site_id: 'remark42', user_id: '1' } + const ref = mockEndpoint('/remark42/api/v1/user/1', { method: 'put', body: data }) + + await expect(client.blockUser('1', ttl)).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('ttl')).toBe(expected) + }) + }) + + adminClient('should unblock user', async ({ client }) => { + const data = { block: false, site_id: 'remark42', user_id: '1' } + const ref = mockEndpoint('/remark42/api/v1/user/1', { method: 'put', body: data }) + + await expect(client.unblockUser('1')).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('block')).toBe('0') + }) + + adminClient('should mark user as verified', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/verify/1', { method: 'put' }) + + await client.verifyUser('1') + expect(ref.req.url.searchParams.get('verified')).toBe('1') + }) + + adminClient('should mark user as unverified', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/verify/1', { method: 'put' }) + + await client.unverifyUser('1') + expect(ref.req.url.searchParams.get('verified')).toBe('0') + }) + + adminClient('should approve removing request', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/deleteme') + + await client.approveRemovingRequest('token') + expect(ref.req.url.searchParams.get('token')).toBe('token') + }) + + adminClient('should pin comment', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/pin/1', { method: 'put' }) + + await client.pinComment('1') + expect(ref.req.url.searchParams.get('pinned')).toBe('1') + }) + + adminClient('should unpin comment', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/pin/1', { method: 'put' }) + + await client.unpinComment('1') + expect(ref.req.url.searchParams.get('pinned')).toBe('0') + }) + + adminClient('should remove comment', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/comment/1', { method: 'delete' }) + const url = '/post/1' + + await client.removeComment(url, '1') + expect(ref.req.url.searchParams.get('url')).toBe(url) + }) + + adminClient('should enable commenting on a page', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/readonly', { method: 'put' }) + const url = '/post/1' + + await client.enableCommenting(url) + expect(ref.req.url.searchParams.get('ro')).toBe('1') + expect(ref.req.url.searchParams.get('url')).toBe(url) + }) + + adminClient('should disable commenting on a page', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/readonly', { method: 'put' }) + const url = '/post/1' + + await client.disableCommenting('/post/1') + expect(ref.req.url.searchParams.get('ro')).toBe('0') + expect(ref.req.url.searchParams.get('url')).toBe(url) + }) +}) diff --git a/frontend/packages/api/tests/clients/auth.test.ts b/frontend/packages/api/tests/clients/auth.test.ts new file mode 100644 index 0000000000..de26744690 --- /dev/null +++ b/frontend/packages/api/tests/clients/auth.test.ts @@ -0,0 +1,59 @@ +import { beforeEach, describe, expect } from 'vitest' +import { mockEndpoint } from '../test-utils' +import { createAuthClient } from '../../clients/auth' + +interface Content { + client: ReturnType +} + +describe('Auth Client', (authClient) => { + beforeEach((ctx) => { + ctx.client = createAuthClient({ siteId: 'mysite', baseUrl: '/remark42' }) + }) + + authClient('should authorize as anonymouse', async ({ client }) => { + const data = { id: 1 } + const ref = mockEndpoint('/remark42/auth/anonymous/login', { body: data }) + + await expect(client.anonymous('username')).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('aud')).toBe('mysite') + expect(ref.req.url.searchParams.get('user')).toBe('username') + }) + + authClient('should authorize with email', async ({ client }) => { + const data = { id: 1 } + const ref = mockEndpoint('/remark42/auth/email/login', { body: data }) + const tokenVerification = await client.email('username@example.com', 'username') + + expect(ref.req.url.searchParams.get('address')).toBe('username@example.com') + expect(ref.req.url.searchParams.get('user')).toBe('username') + + await expect(tokenVerification('token')).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('token')).toBe('token') + }) + + authClient('should authorize with telegram', async ({ client }) => { + const data = { + bot: 'remark42bot', + token: 'token', + } + const user = { id: 1 } + + mockEndpoint('/remark42/auth/telegram/login', { body: data }) + + const telegramAuth = await client.telegram() + + expect(telegramAuth.bot).toBe(data.bot) + expect(telegramAuth.token).toBe(data.token) + + const ref = mockEndpoint('/remark42/auth/telegram/login', { body: user }) + + await expect(telegramAuth.verify()).resolves.toEqual(user) + expect(ref.req.url.searchParams.get('token')).toBe('token') + }) + + authClient('should logout', async ({ client }) => { + mockEndpoint('/remark42/auth/logout') + await expect(client.logout()).resolves.toBe('') + }) +}) diff --git a/frontend/packages/api/tests/clients/index.test.ts b/frontend/packages/api/tests/clients/index.test.ts new file mode 100644 index 0000000000..0709d9c947 --- /dev/null +++ b/frontend/packages/api/tests/clients/index.test.ts @@ -0,0 +1,14 @@ +import { describe, expect, it } from 'vitest' +import { createClient } from '../..' + +describe('Client', () => { + it('should create a client', () => { + const params = { siteId: 'mysite', baseUrl: '/remark42' } + const client = createClient(params) + + expect(client).toBeDefined() + expect(client.admin).toBeDefined() + expect(client.auth).toBeDefined() + expect(client.public).toBeDefined() + }) +}) diff --git a/frontend/packages/api/tests/clients/public.test.ts b/frontend/packages/api/tests/clients/public.test.ts new file mode 100644 index 0000000000..70734dab37 --- /dev/null +++ b/frontend/packages/api/tests/clients/public.test.ts @@ -0,0 +1,107 @@ +import { beforeEach, describe, expect } from 'vitest' +import { mockEndpoint } from '../test-utils' +import { createPublicClient, GetUserCommentsParams, Vote } from '../../clients/public' + +interface Context { + client: ReturnType +} + +describe('Public Client', (publicClient) => { + beforeEach((ctx) => { + ctx.client = createPublicClient({ siteId: 'mysite', baseUrl: '/remark42' }) + }) + + publicClient('getConfig: should return config', async ({ client }) => { + const data = { x: 1, y: 2 } + + mockEndpoint('/remark42/api/v1/config', { body: data }) + await expect(client.getConfig()).resolves.toEqual(data) + }) + + publicClient('getComments: should return page comments', async ({ client }) => { + const data = { post: { id: '1' }, node: [{ id: 1 }] } + const ref = mockEndpoint('/remark42/api/v1/comments', { body: data }) + + await expect(client.getComments('/post/1')).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('url')).toBe('/post/1') + }) + + const commentRequestCases: GetUserCommentsParams[] = [ + { url: '' }, + { url: '' }, + { url: '', limit: 10 }, + { url: '', skip: 10 }, + { url: '', skip: 10, limit: 0 }, + ] + + commentRequestCases.forEach((params) => { + publicClient( + `getComments: should return user comments with params: ${JSON.stringify(params)}`, + async ({ client }) => { + const data = [{ id: 1 }, { id: 2 }] + const ref = mockEndpoint('/remark42/api/v1/find', { body: data }) + + await expect(client.getComments(params)).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('limit')).toBe( + params.limit === undefined ? null : `${params.limit}` + ) + expect(ref.req.url.searchParams.get('skip')).toBe( + params.skip === undefined ? null : `${params.skip}` + ) + } + ) + }) + + publicClient('addComment: should add comment', async ({ client }) => { + const data = { id: '1', text: 'test' } + const ref = mockEndpoint('/remark42/api/v1/comment', { method: 'post', body: data }) + + await expect(client.addComment('/post/my-first-post', { text: 'test' })).resolves.toEqual(data) + await expect(ref.req.json()).resolves.toEqual({ + text: data.text, + locator: { + site: 'mysite', + url: '/post/my-first-post', + }, + }) + }) + + publicClient('updateComment: should update comment', async ({ client }) => { + const data = { id: 1, body: 'test' } + const ref = mockEndpoint('/remark42/api/v1/comment/1', { method: 'put', body: data }) + + await expect(client.updateComment('/post/my-first-post', '1', 'test')).resolves.toEqual(data) + await expect(ref.req.json()).resolves.toEqual({ text: 'test' }) + expect(ref.req.url.searchParams.get('url')).toBe('/post/my-first-post') + }) + + publicClient('should remove comment', async ({ client }) => { + const ref = mockEndpoint('/remark42/api/v1/comment/1', { method: 'put' }) + + await expect(client.removeComment('/post/my-first-post', '1')).resolves.toBe('') + expect(ref.req.url.searchParams.get('url')).toBe('/post/my-first-post') + }) + + const voteRequestCases: { vote: Vote; value: string }[] = [ + { vote: 1, value: 'upvote' }, + { vote: -1, value: 'downvote' }, + ] + voteRequestCases.forEach(({ vote, value }) => { + publicClient(`vote: should ${value} for comment`, async ({ client }) => { + const data = { id: 1, vote: 2 } + const ref = mockEndpoint('/remark42/api/v1/vote/1', { method: 'put', body: data }) + + await expect(client.vote('/post/my-first-post', '1', vote)).resolves.toEqual(data) + expect(ref.req.url.searchParams.get('url')).toBe('/post/my-first-post') + expect(ref.req.url.searchParams.get('vote')).toBe(`${vote}`) + }) + }) + + const userCases = [null, { id: '1', username: 'user' }] + userCases.forEach((user) => { + publicClient('should return user', async ({ client }) => { + mockEndpoint('/remark42/api/v1/user', { body: user }) + await expect(client.getUser()).resolves.toEqual(user) + }) + }) +}) diff --git a/frontend/packages/api/tests/index.test.ts b/frontend/packages/api/tests/index.test.ts new file mode 100644 index 0000000000..449b8eeefa --- /dev/null +++ b/frontend/packages/api/tests/index.test.ts @@ -0,0 +1,6 @@ +import { test, expect } from 'vitest' +import { createClient } from '..' + +test('create client', () => { + expect(() => createClient({ siteId: 'site', baseUrl: '' })).not.toThrow() +}) diff --git a/frontend/packages/api/tests/lib/fetcher.test.ts b/frontend/packages/api/tests/lib/fetcher.test.ts new file mode 100644 index 0000000000..8aecb14e30 --- /dev/null +++ b/frontend/packages/api/tests/lib/fetcher.test.ts @@ -0,0 +1,117 @@ +import { beforeEach, describe, expect } from 'vitest' +import { mockEndpoint } from '../test-utils' +import { JWT_HEADER, XSRF_COOKIE, XSRF_HEADER } from '../../consts' +import { Client, createFetcher } from '../../lib/fetcher' + +interface Context { + client: Client +} + +describe('Fetcher', (fetcher) => { + beforeEach((ctx) => { + ctx.client = createFetcher('remark42', '') + }) + + fetcher('get', async ({ client }) => { + const ref = mockEndpoint('/test') + + await client.get('/test') + expect(ref.req.method).toBe('GET') + }) + + fetcher('post', async ({ client }) => { + const ref = mockEndpoint('/test', { method: 'post' }) + + await client.post('/test') + expect(ref.req.method).toBe('POST') + }) + + fetcher('put', async ({ client }) => { + const ref = mockEndpoint('/test', { method: 'put' }) + + await client.put('/test') + expect(ref.req.method).toBe('PUT') + }) + + fetcher('delete', async ({ client }) => { + const ref = mockEndpoint('/test', { method: 'delete' }) + + await client.delete('/test') + expect(ref.req.method).toBe('DELETE') + }) + fetcher('should send json', async ({ client }) => { + const data = { name: 'test' } + const ref = mockEndpoint('/test', { method: 'post', body: data }) + + await expect(client.post('/test', {}, data)).resolves.toStrictEqual(data) + await expect(ref.req.json()).resolves.toStrictEqual(data) + expect(ref.req.headers.get('Content-Type')).toBe('application/json') + }) + + fetcher('should send text', async ({ client }) => { + const data = 'text' + const ref = mockEndpoint('/test', { method: 'post', body: data }) + + await expect(client.post('/test', {}, data)).resolves.toBe(data) + await expect(ref.req.text()).resolves.toBe(data) + expect(ref.req.headers.get('Content-Type')).toMatch('text/plain') + }) + + fetcher('should send query', async ({ client }) => { + const ref = mockEndpoint('/test') + + await expect(client.get('/test', { x: 1, p: 2 })).resolves.toBe('') + expect(ref.req.url.searchParams.get('x')).toBe('1') + expect(ref.req.url.searchParams.get('p')).toBe('2') + }) + + fetcher('should sort query params', async ({ client }) => { + const ref = mockEndpoint('/test') + + await expect(client.get('/test', { x: 1, p: 2 })).resolves.toBe('') + expect(ref.req.url.search).toBe('?p=2&site=remark42&x=1') + }) + + fetcher( + 'should set active token and then clean it on unauthorized response', + async ({ client }) => { + let ref = mockEndpoint('/user', { headers: { [JWT_HEADER]: 'token' } }) + + // token should be saved + await client.get('/user') + // the first call should be without token + expect(ref.req.headers.get(JWT_HEADER)).toBe(null) + // the second call should be with token + await client.get('/user') + // check if the second call was with token + expect(ref.req.headers.get(JWT_HEADER)).toBe('token') + + // unauthorized response should clean token + ref = mockEndpoint('/user', { status: 401 }) + // the third call should be with token but token should be cleaned after it + await expect(client.get('/user')).rejects.toBe('Unauthorized') + // the fourth call should be without token + await expect(client.get('/user')).rejects.toBe('Unauthorized') + // check if the fourth call was with token + expect(ref.req.headers.get(JWT_HEADER)).toBe(null) + } + ) + + fetcher('should add XSRF header if we have it in cookies', async ({ client }) => { + const ref = mockEndpoint('/user') + + Object.defineProperty(document, 'cookie', { + writable: true, + value: `${XSRF_COOKIE}=token`, + }) + + await client.get('/user') + expect(ref.req.headers.get(XSRF_HEADER)).toBe('token') + }) + + fetcher('should throw error on api response with status code 400', async ({ client }) => { + mockEndpoint('/user', { status: 400 }) + + await expect(client.get('/user')).rejects.toBe('') + }) +}) diff --git a/frontend/packages/api/tests/setup.ts b/frontend/packages/api/tests/setup.ts new file mode 100644 index 0000000000..9398bfdf2c --- /dev/null +++ b/frontend/packages/api/tests/setup.ts @@ -0,0 +1,15 @@ +import 'whatwg-fetch' +import { afterAll, afterEach, beforeAll } from 'vitest' +import { server } from './test-utils' + +beforeAll(() => { + server.listen({ onUnhandledRequest: 'error' }) +}) + +afterEach(() => { + server.resetHandlers() +}) + +afterAll(() => { + server.close() +}) diff --git a/frontend/packages/api/tests/test-utils.ts b/frontend/packages/api/tests/test-utils.ts new file mode 100644 index 0000000000..742a792148 --- /dev/null +++ b/frontend/packages/api/tests/test-utils.ts @@ -0,0 +1,36 @@ +import { rest, RestRequest } from 'msw' +import { setupServer } from 'msw/node' + +export const server = setupServer() + +interface RequestRef { + req: RestRequest +} + +export function mockEndpoint( + url: string, + params: { + method?: 'get' | 'put' | 'post' | 'delete' + body?: number | string | null | Record | unknown[] + status?: number + headers?: Record + } = {} +): RequestRef { + const { body, method = 'get', status = 200, headers } = params + const result = { req: {} } as RequestRef + + server.use( + rest[method](url, (req, res, ctx) => { + const transformers = [ctx.status(status), ctx.json(body)] + + if (headers) { + transformers.push(ctx.set(headers)) + } + + result.req = req + return res(...transformers) + }) + ) + + return result +} diff --git a/frontend/packages/api/tsconfig.eslint.json b/frontend/packages/api/tsconfig.eslint.json new file mode 100644 index 0000000000..842b527e87 --- /dev/null +++ b/frontend/packages/api/tsconfig.eslint.json @@ -0,0 +1,5 @@ +{ + "extends": "./tsconfig.json", + "include": ["**/*.ts"], + "exclude": [".turbo", "node_modules"] +} diff --git a/frontend/packages/api/tsconfig.json b/frontend/packages/api/tsconfig.json new file mode 100644 index 0000000000..e0ad37c0df --- /dev/null +++ b/frontend/packages/api/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2016", + "lib": ["DOM"], + "moduleResolution": "node", + "baseUrl": "./", + "declaration": true, + "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "strict": true + }, + "include": ["index.ts", "clients", "lib"], + "exclude": ["tests", "coverage"] +} diff --git a/frontend/packages/api/vitest.config.mjs b/frontend/packages/api/vitest.config.mjs new file mode 100644 index 0000000000..6462fcde76 --- /dev/null +++ b/frontend/packages/api/vitest.config.mjs @@ -0,0 +1,9 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + environment: 'jsdom', + setupFiles: ['./tests/setup.ts'], + include: ['tests/**/*.test.ts'], + }, +}) diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index af68d67711..a5bf91b79e 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -6,9 +6,11 @@ importers: specifiers: husky: ^8.0.1 lint-staged: ^13.0.3 + turbo: ^1.4.3 devDependencies: husky: 8.0.1 lint-staged: 13.0.3 + turbo: 1.4.3 apps/remark42: specifiers: @@ -209,6 +211,42 @@ importers: webpack-cli: 4.10.0_orc2ewcajya4tocnqelr4vzh7u webpack-dev-server: 4.9.3_77l47gmqkrqiei5z7sbwz5iaj4 + packages/api: + specifiers: + '@types/node': ^18.0.5 + '@typescript-eslint/eslint-plugin': ^5.33.1 + '@typescript-eslint/parser': ^5.33.1 + '@vitest/coverage-c8': ^0.22.1 + eslint: ^8.18.0 + eslint-config-prettier: ^8.5.0 + eslint-plugin-prettier: ^4.2.1 + jsdom: ^20.0.0 + msw: ^0.44.1 + npm-run-all: ^4.1.5 + prettier: ^2.7.1 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^4.7.4 + vitest: ^0.22.1 + whatwg-fetch: ^3.6.2 + devDependencies: + '@types/node': 18.0.6 + '@typescript-eslint/eslint-plugin': 5.33.1_xvmm3ouh3ttkwfukqn4o7asoxy + '@typescript-eslint/parser': 5.33.1_4x5o4skxv6sl53vpwefgt23khm + '@vitest/coverage-c8': 0.22.1_jsdom@20.0.0 + eslint: 8.19.0 + eslint-config-prettier: 8.5.0_eslint@8.19.0 + eslint-plugin-prettier: 4.2.1_7uxdfn2xinezdgvmbammh6ev5i + jsdom: 20.0.0 + msw: 0.44.2_typescript@4.7.4 + npm-run-all: 4.1.5 + prettier: 2.7.1 + ts-node: 10.9.1_tdn3ypgnfy6bmey2q4hu5jonwi + tslib: 2.4.0 + typescript: 4.7.4 + vitest: 0.22.1_jsdom@20.0.0 + whatwg-fetch: 3.6.2 + packages: /@ampproject/remapping/2.2.0: @@ -1716,6 +1754,15 @@ packages: engines: {node: '>=10.0.0'} dev: true + /@esbuild/linux-loong64/0.14.54: + resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + /@eslint/eslintrc/1.3.0: resolution: {integrity: sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1869,6 +1916,18 @@ packages: slash: 3.0.0 dev: true + /@jest/console/28.1.3: + resolution: {integrity: sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/types': 28.1.3 + '@types/node': 18.0.6 + chalk: 4.1.2 + jest-message-util: 28.1.3 + jest-util: 28.1.3 + slash: 3.0.0 + dev: true + /@jest/core/28.1.2_ts-node@10.8.2: resolution: {integrity: sha512-Xo4E+Sb/nZODMGOPt2G3cMmCBqL4/W2Ijwr7/mrXlq4jdJwcFQ/9KrrJZT2adQRk2otVBXXOz1GRQ4Z5iOgvRQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -1894,16 +1953,16 @@ packages: jest-haste-map: 28.1.1 jest-message-util: 28.1.1 jest-regex-util: 28.0.2 - jest-resolve: 28.1.1 - jest-resolve-dependencies: 28.1.2 - jest-runner: 28.1.2 - jest-runtime: 28.1.2 - jest-snapshot: 28.1.2 - jest-util: 28.1.1 - jest-validate: 28.1.1 - jest-watcher: 28.1.1 + jest-resolve: 28.1.3 + jest-resolve-dependencies: 28.1.3 + jest-runner: 28.1.3 + jest-runtime: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 + jest-watcher: 28.1.3 micromatch: 4.0.5 - pretty-format: 28.1.1 + pretty-format: 28.1.3 rimraf: 3.0.2 slash: 3.0.0 strip-ansi: 6.0.1 @@ -1929,19 +1988,29 @@ packages: jest-mock: 28.1.1 dev: true - /@jest/expect-utils/28.1.1: - resolution: {integrity: sha512-n/ghlvdhCdMI/hTcnn4qV57kQuV9OTsZzH1TTCVARANKhl6hXJqLKUkwX69ftMGpsbpt96SsDD8n8LD2d9+FRw==} + /@jest/environment/28.1.3: + resolution: {integrity: sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/fake-timers': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 18.0.6 + jest-mock: 28.1.3 + dev: true + + /@jest/expect-utils/28.1.3: + resolution: {integrity: sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: jest-get-type: 28.0.2 dev: true - /@jest/expect/28.1.2: - resolution: {integrity: sha512-HBzyZBeFBiOelNbBKN0pilWbbrGvwDUwAqMC46NVJmWm8AVkuE58NbG1s7DR4cxFt4U5cVLxofAoHxgvC5MyOw==} + /@jest/expect/28.1.3: + resolution: {integrity: sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - expect: 28.1.1 - jest-snapshot: 28.1.2 + expect: 28.1.3 + jest-snapshot: 28.1.3 transitivePeerDependencies: - supports-color dev: true @@ -1958,13 +2027,25 @@ packages: jest-util: 28.1.1 dev: true - /@jest/globals/28.1.2: - resolution: {integrity: sha512-cz0lkJVDOtDaYhvT3Fv2U1B6FtBnV+OpEyJCzTHM1fdoTsU4QNLAt/H4RkiwEUU+dL4g/MFsoTuHeT2pvbo4Hg==} + /@jest/fake-timers/28.1.3: + resolution: {integrity: sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/environment': 28.1.2 - '@jest/expect': 28.1.2 - '@jest/types': 28.1.1 + '@jest/types': 28.1.3 + '@sinonjs/fake-timers': 9.1.2 + '@types/node': 18.0.6 + jest-message-util: 28.1.3 + jest-mock: 28.1.3 + jest-util: 28.1.3 + dev: true + + /@jest/globals/28.1.3: + resolution: {integrity: sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/environment': 28.1.3 + '@jest/expect': 28.1.3 + '@jest/types': 28.1.3 transitivePeerDependencies: - supports-color dev: true @@ -2014,6 +2095,13 @@ packages: '@sinclair/typebox': 0.23.5 dev: true + /@jest/schemas/28.1.3: + resolution: {integrity: sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@sinclair/typebox': 0.24.20 + dev: true + /@jest/source-map/28.1.2: resolution: {integrity: sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -2033,6 +2121,16 @@ packages: collect-v8-coverage: 1.0.1 dev: true + /@jest/test-result/28.1.3: + resolution: {integrity: sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/console': 28.1.3 + '@jest/types': 28.1.3 + '@types/istanbul-lib-coverage': 2.0.4 + collect-v8-coverage: 1.0.1 + dev: true + /@jest/test-sequencer/28.1.1: resolution: {integrity: sha512-nuL+dNSVMcWB7OOtgb0EGH5AjO4UBCt68SLP08rwmC+iRhyuJWS9MtZ/MpipxFwKAlHFftbMsydXqWre8B0+XA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -2066,6 +2164,29 @@ packages: - supports-color dev: true + /@jest/transform/28.1.3: + resolution: {integrity: sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@babel/core': 7.18.6 + '@jest/types': 28.1.3 + '@jridgewell/trace-mapping': 0.3.14 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 1.8.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.10 + jest-haste-map: 28.1.3 + jest-regex-util: 28.0.2 + jest-util: 28.1.3 + micromatch: 4.0.5 + pirates: 4.0.5 + slash: 3.0.0 + write-file-atomic: 4.0.1 + transitivePeerDependencies: + - supports-color + dev: true + /@jest/types/27.5.1: resolution: {integrity: sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -2089,6 +2210,18 @@ packages: chalk: 4.1.2 dev: true + /@jest/types/28.1.3: + resolution: {integrity: sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/schemas': 28.1.3 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/istanbul-reports': 3.0.1 + '@types/node': 18.0.6 + '@types/yargs': 17.0.10 + chalk: 4.1.2 + dev: true + /@jridgewell/gen-mapping/0.1.1: resolution: {integrity: sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==} engines: {node: '>=6.0.0'} @@ -2162,6 +2295,30 @@ packages: resolution: {integrity: sha512-EWUguj2kd7ldmrF9F+vI5hUOralPd+sdsUnYbRy33vZTuZkduC1shE9TtEMEjAQwyfyMb4ole5KtjF8MsnQOlA==} dev: true + /@mswjs/cookies/0.2.2: + resolution: {integrity: sha512-mlN83YSrcFgk7Dm1Mys40DLssI1KdJji2CMKN8eOlBqsTADYzj2+jWzsANsUTFbxDMWPD5e9bfA1RGqBpS3O1g==} + engines: {node: '>=14'} + dependencies: + '@types/set-cookie-parser': 2.4.2 + set-cookie-parser: 2.5.1 + dev: true + + /@mswjs/interceptors/0.17.3: + resolution: {integrity: sha512-jBRFPeHBPqKv3od8KPjmrvt4b/+e1DorizFDYJ8NQCrjFT9YGnxA8ojGi0MIo64x/JgdjYkhP8bG9EY4BGPoqg==} + engines: {node: '>=14'} + dependencies: + '@open-draft/until': 1.0.3 + '@types/debug': 4.1.7 + '@xmldom/xmldom': 0.7.5 + debug: 4.3.4 + headers-polyfill: 3.0.10 + outvariant: 1.3.0 + strict-event-emitter: 0.2.4 + web-encoding: 1.1.5 + transitivePeerDependencies: + - supports-color + dev: true + /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2183,6 +2340,10 @@ packages: fastq: 1.13.0 dev: true + /@open-draft/until/1.0.3: + resolution: {integrity: sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==} + dev: true + /@polka/url/1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: true @@ -2233,6 +2394,10 @@ packages: resolution: {integrity: sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==} dev: true + /@sinclair/typebox/0.24.20: + resolution: {integrity: sha512-kVaO5aEFZb33nPMTZBxiPEkY+slxiPtqC7QX8f9B3eGOMBvEfuMfxp9DSTTCsRJPumPKjrge4yagyssO4q6qzQ==} + dev: true + /@sinonjs/commons/1.8.3: resolution: {integrity: sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==} dependencies: @@ -2518,6 +2683,16 @@ packages: '@types/node': 18.0.3 dev: true + /@types/chai-subset/1.3.3: + resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + dependencies: + '@types/chai': 4.3.3 + dev: true + + /@types/chai/4.3.3: + resolution: {integrity: sha512-hC7OMnszpxhZPduX+m+nrx+uFoLkWOMiR4oa/AZF3MuSETYTZmFfJAHqZEM8MVlvfG7BEUcgvtwoCTxBp6hm3g==} + dev: true + /@types/cheerio/0.22.31: resolution: {integrity: sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==} dependencies: @@ -2534,7 +2709,17 @@ packages: /@types/connect/3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 18.0.3 + '@types/node': 18.0.6 + dev: true + + /@types/cookie/0.4.1: + resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} + dev: true + + /@types/debug/4.1.7: + resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} + dependencies: + '@types/ms': 0.7.31 dev: true /@types/enzyme/3.10.12: @@ -2593,7 +2778,7 @@ packages: /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 18.0.3 + '@types/node': 18.0.6 dev: true /@types/hoist-non-react-statics/3.3.1: @@ -2635,6 +2820,10 @@ packages: pretty-format: 28.1.1 dev: true + /@types/js-levenshtein/1.1.1: + resolution: {integrity: sha512-qC4bCqYGy1y/NP7dDVr7KJarn+PbX1nSpwA7JXdu0HxT3QYjO8MJ+cntENtHFVy2dRAyBV23OZ6MxsW1AM1L8g==} + dev: true + /@types/jsdom/16.2.14: resolution: {integrity: sha512-6BAy1xXEmMuHeAJ4Fv4yXKwBDTGTOseExKE3OaHiNycdHdZw59KfYzrt0DkDluvwmik1HRt6QS7bImxUmpSy+w==} dependencies: @@ -2673,6 +2862,10 @@ packages: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} dev: true + /@types/ms/0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: true + /@types/node-emoji/1.8.1: resolution: {integrity: sha512-0fRfA90FWm6KJfw6P9QGyo0HDTCmthZ7cWaBQndITlaWLTZ6njRyKwrwpzpg+n6kBXBIGKeUHEQuBx7bphGJkA==} dev: true @@ -2681,6 +2874,10 @@ packages: resolution: {integrity: sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==} dev: true + /@types/node/18.0.6: + resolution: {integrity: sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==} + dev: true + /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} dev: true @@ -2750,6 +2947,12 @@ packages: '@types/node': 18.0.3 dev: true + /@types/set-cookie-parser/2.4.2: + resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} + dependencies: + '@types/node': 18.0.6 + dev: true + /@types/sockjs/0.3.33: resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} dependencies: @@ -2827,6 +3030,33 @@ packages: - supports-color dev: true + /@typescript-eslint/eslint-plugin/5.33.1_xvmm3ouh3ttkwfukqn4o7asoxy: + resolution: {integrity: sha512-S1iZIxrTvKkU3+m63YUOxYPKaP+yWDQrdhxTglVDVEVBf+aCSw85+BmJnyUaQQsk5TXFG/LpBu9fa+LrAQ91fQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/parser': 5.33.1_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/scope-manager': 5.33.1 + '@typescript-eslint/type-utils': 5.33.1_4x5o4skxv6sl53vpwefgt23khm + '@typescript-eslint/utils': 5.33.1_4x5o4skxv6sl53vpwefgt23khm + debug: 4.3.4 + eslint: 8.19.0 + functional-red-black-tree: 1.0.1 + ignore: 5.2.0 + regexpp: 3.2.0 + semver: 7.3.7 + tsutils: 3.21.0_typescript@4.7.4 + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/experimental-utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm: resolution: {integrity: sha512-bqvT+0L8IjtW7MCrMgm9oVNxs4g7mESro1mm5c1/SNfTnHuFTf9OUX1WzVkTz75M9cp//UrTrSmGvK48NEKshQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2860,6 +3090,26 @@ packages: - supports-color dev: true + /@typescript-eslint/parser/5.33.1_4x5o4skxv6sl53vpwefgt23khm: + resolution: {integrity: sha512-IgLLtW7FOzoDlmaMoXdxG8HOCByTBXrB1V2ZQYSEV1ggMmJfAkMWTwUjjzagS6OkfpySyhKFkBw7A9jYmcHpZA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 5.33.1 + '@typescript-eslint/types': 5.33.1 + '@typescript-eslint/typescript-estree': 5.33.1_typescript@4.7.4 + debug: 4.3.4 + eslint: 8.19.0 + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/scope-manager/5.30.6: resolution: {integrity: sha512-Hkq5PhLgtVoW1obkqYH0i4iELctEKixkhWLPTYs55doGUKCASvkjOXOd/pisVeLdO24ZX9D6yymJ/twqpJiG3g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2868,6 +3118,14 @@ packages: '@typescript-eslint/visitor-keys': 5.30.6 dev: true + /@typescript-eslint/scope-manager/5.33.1: + resolution: {integrity: sha512-8ibcZSqy4c5m69QpzJn8XQq9NnqAToC8OdH/W6IXPXv83vRyEDPYLdjAlUx8h/rbusq6MkW4YdQzURGOqsn3CA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.33.1 + '@typescript-eslint/visitor-keys': 5.33.1 + dev: true + /@typescript-eslint/type-utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm: resolution: {integrity: sha512-GFVVzs2j0QPpM+NTDMXtNmJKlF842lkZKDSanIxf+ArJsGeZUIaeT4jGg+gAgHt7AcQSFwW7htzF/rbAh2jaVA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2887,11 +3145,35 @@ packages: - supports-color dev: true + /@typescript-eslint/type-utils/5.33.1_4x5o4skxv6sl53vpwefgt23khm: + resolution: {integrity: sha512-X3pGsJsD8OiqhNa5fim41YtlnyiWMF/eKsEZGsHID2HcDqeSC5yr/uLOeph8rNF2/utwuI0IQoAK3fpoxcLl2g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/utils': 5.33.1_4x5o4skxv6sl53vpwefgt23khm + debug: 4.3.4 + eslint: 8.19.0 + tsutils: 3.21.0_typescript@4.7.4 + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/types/5.30.6: resolution: {integrity: sha512-HdnP8HioL1F7CwVmT4RaaMX57RrfqsOMclZc08wGMiDYJBsLGBM7JwXM4cZJmbWLzIR/pXg1kkrBBVpxTOwfUg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@typescript-eslint/types/5.33.1: + resolution: {integrity: sha512-7K6MoQPQh6WVEkMrMW5QOA5FO+BOwzHSNd0j3+BlBwd6vtzfZceJ8xJ7Um2XDi/O3umS8/qDX6jdy2i7CijkwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@typescript-eslint/typescript-estree/5.30.6_typescript@4.7.4: resolution: {integrity: sha512-Z7TgPoeYUm06smfEfYF0RBkpF8csMyVnqQbLYiGgmUSTaSXTP57bt8f0UFXstbGxKIreTwQCujtaH0LY9w9B+A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2913,6 +3195,27 @@ packages: - supports-color dev: true + /@typescript-eslint/typescript-estree/5.33.1_typescript@4.7.4: + resolution: {integrity: sha512-JOAzJ4pJ+tHzA2pgsWQi4804XisPHOtbvwUyqsuuq8+y5B5GMZs7lI1xDWs6V2d7gE/Ez5bTGojSK12+IIPtXA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.33.1 + '@typescript-eslint/visitor-keys': 5.33.1 + debug: 4.3.4 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.7 + tsutils: 3.21.0_typescript@4.7.4 + typescript: 4.7.4 + transitivePeerDependencies: + - supports-color + dev: true + /@typescript-eslint/utils/5.30.6_4x5o4skxv6sl53vpwefgt23khm: resolution: {integrity: sha512-xFBLc/esUbLOJLk9jKv0E9gD/OH966M40aY9jJ8GiqpSkP2xOV908cokJqqhVd85WoIvHVHYXxSFE4cCSDzVvA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2931,6 +3234,24 @@ packages: - typescript dev: true + /@typescript-eslint/utils/5.33.1_4x5o4skxv6sl53vpwefgt23khm: + resolution: {integrity: sha512-uphZjkMaZ4fE8CR4dU7BquOV6u0doeQAr8n6cQenl/poMaIyJtBu8eys5uk6u5HiDH01Mj5lzbJ5SfeDz7oqMQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + '@types/json-schema': 7.0.11 + '@typescript-eslint/scope-manager': 5.33.1 + '@typescript-eslint/types': 5.33.1 + '@typescript-eslint/typescript-estree': 5.33.1_typescript@4.7.4 + eslint: 8.19.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.19.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + /@typescript-eslint/visitor-keys/5.30.6: resolution: {integrity: sha512-41OiCjdL2mCaSDi2SvYbzFLlqqlm5v1ZW9Ym55wXKL/Rx6OOB1IbuFGo71Fj6Xy90gJDFTlgOS+vbmtGHPTQQA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2939,10 +3260,36 @@ packages: eslint-visitor-keys: 3.3.0 dev: true + /@typescript-eslint/visitor-keys/5.33.1: + resolution: {integrity: sha512-nwIxOK8Z2MPWltLKMLOEZwmfBZReqUdbEoHQXeCpa+sRVARe5twpJGHCB4dk9903Yaf0nMAlGbQfaAH92F60eg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.33.1 + eslint-visitor-keys: 3.3.0 + dev: true + /@ungap/custom-elements/1.1.0: resolution: {integrity: sha512-jPOtG6F8Wfmu3C+SF6lAglg/GsMGeiQCelikCrARXodcCVbH51GjG1Ga2GfM+WsxmRfnenLaUBLrkdxduHSGOA==} dev: false + /@vitest/coverage-c8/0.22.1_jsdom@20.0.0: + resolution: {integrity: sha512-KOOYpO7EGpaF+nD8GD+Y05D0JtZp12NUu6DdLXvBPqSOPo2HkZ7KNBtfR0rb6gOy3NLtGiWTYTzCwhajgb2HlA==} + dependencies: + c8: 7.12.0 + vitest: 0.22.1_jsdom@20.0.0 + transitivePeerDependencies: + - '@edge-runtime/vm' + - '@vitest/browser' + - '@vitest/ui' + - happy-dom + - jsdom + - less + - sass + - stylus + - supports-color + - terser + dev: true + /@webassemblyjs/ast/1.11.1: resolution: {integrity: sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==} dependencies: @@ -3081,6 +3428,11 @@ packages: webpack-dev-server: 4.9.3_77l47gmqkrqiei5z7sbwz5iaj4 dev: true + /@xmldom/xmldom/0.7.5: + resolution: {integrity: sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A==} + engines: {node: '>=10.0.0'} + dev: true + /@xtuc/ieee754/1.2.0: resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} dev: true @@ -3089,6 +3441,12 @@ packages: resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} dev: true + /@zxing/text-encoding/0.9.0: + resolution: {integrity: sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==} + requiresBuild: true + dev: true + optional: true + /abab/2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: true @@ -3376,6 +3734,10 @@ packages: engines: {node: '>=0.10.0'} dev: true + /assertion-error/1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /ast-metadata-inferer/0.7.0: resolution: {integrity: sha512-OkMLzd8xelb3gmnp6ToFvvsHLtS6CbagTkFQvQ+ZYFe3/AIl9iKikNR9G7pY3GfOR/2Xc222hwBjzI7HLkE76Q==} dependencies: @@ -3417,6 +3779,11 @@ packages: postcss-value-parser: 4.2.0 dev: true + /available-typed-arrays/1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + dev: true + /axe-core/4.4.2: resolution: {integrity: sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA==} engines: {node: '>=12'} @@ -3608,6 +3975,10 @@ packages: resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} dev: true + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + /batch/0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} dev: true @@ -3625,6 +3996,14 @@ packages: engines: {node: '>=8'} dev: true + /bl/4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: true + /body-parser/1.20.0: resolution: {integrity: sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -3697,6 +4076,13 @@ packages: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /buffer/5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + /bytes-iec/3.1.1: resolution: {integrity: sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA==} engines: {node: '>= 0.8'} @@ -3712,6 +4098,25 @@ packages: engines: {node: '>= 0.8'} dev: true + /c8/7.12.0: + resolution: {integrity: sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A==} + engines: {node: '>=10.12.0'} + hasBin: true + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@istanbuljs/schema': 0.1.3 + find-up: 5.0.0 + foreground-child: 2.0.0 + istanbul-lib-coverage: 3.2.0 + istanbul-lib-report: 3.0.0 + istanbul-reports: 3.1.5 + rimraf: 3.0.2 + test-exclude: 6.0.0 + v8-to-istanbul: 9.0.1 + yargs: 16.2.0 + yargs-parser: 20.2.9 + dev: true + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -3763,6 +4168,19 @@ packages: resolution: {integrity: sha512-VDQZ8OtpuIPMBA4YYvZXECtXbddMCUFJk1qu8Mqxfm/SZJNSr1cy4IuLCOL7RJ/YASrvJcYg1Zh+UEUQ5m6z8Q==} dev: true + /chai/4.3.6: + resolution: {integrity: sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 3.0.1 + get-func-name: 2.0.0 + loupe: 2.3.4 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + /chalk/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3780,8 +4198,16 @@ packages: supports-color: 7.2.0 dev: true - /chalk/4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + /chalk/4.1.1: + resolution: {integrity: sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk/4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} dependencies: ansi-styles: 4.3.0 @@ -3793,6 +4219,14 @@ packages: engines: {node: '>=10'} dev: true + /chardet/0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: true + + /check-error/1.0.2: + resolution: {integrity: sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==} + dev: true + /cheerio-select/2.1.0: resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} dependencies: @@ -3878,6 +4312,11 @@ packages: restore-cursor: 3.1.0 dev: true + /cli-spinners/2.7.0: + resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} + engines: {node: '>=6'} + dev: true + /cli-truncate/2.1.0: resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} engines: {node: '>=8'} @@ -3894,6 +4333,11 @@ packages: string-width: 5.1.2 dev: true + /cli-width/3.0.0: + resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} + engines: {node: '>= 10'} + dev: true + /cliui/7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -3918,6 +4362,11 @@ packages: is-regexp: 2.1.0 dev: true + /clone/1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: true + /clsx/1.2.1: resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} engines: {node: '>=6'} @@ -4064,6 +4513,11 @@ packages: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} dev: true + /cookie/0.4.2: + resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} + engines: {node: '>= 0.6'} + dev: true + /cookie/0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} @@ -4451,6 +4905,13 @@ packages: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} dev: true + /deep-eql/3.0.1: + resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==} + engines: {node: '>=0.12'} + dependencies: + type-detect: 4.0.8 + dev: true + /deep-is/0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -4467,6 +4928,12 @@ packages: execa: 5.1.1 dev: true + /defaults/1.0.3: + resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} + dependencies: + clone: 1.0.4 + dev: true + /define-lazy-prop/2.0.0: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} @@ -4811,6 +5278,215 @@ packages: is-symbol: 1.0.4 dev: true + /esbuild-android-64/0.14.54: + resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-android-arm64/0.14.54: + resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-64/0.14.54: + resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-darwin-arm64/0.14.54: + resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-64/0.14.54: + resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-freebsd-arm64/0.14.54: + resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-32/0.14.54: + resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-64/0.14.54: + resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm/0.14.54: + resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-arm64/0.14.54: + resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-mips64le/0.14.54: + resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-ppc64le/0.14.54: + resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-riscv64/0.14.54: + resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-s390x/0.14.54: + resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-netbsd-64/0.14.54: + resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-openbsd-64/0.14.54: + resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /esbuild-sunos-64/0.14.54: + resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-32/0.14.54: + resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-64/0.14.54: + resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild-windows-arm64/0.14.54: + resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /esbuild/0.14.54: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/linux-loong64': 0.14.54 + esbuild-android-64: 0.14.54 + esbuild-android-arm64: 0.14.54 + esbuild-darwin-64: 0.14.54 + esbuild-darwin-arm64: 0.14.54 + esbuild-freebsd-64: 0.14.54 + esbuild-freebsd-arm64: 0.14.54 + esbuild-linux-32: 0.14.54 + esbuild-linux-64: 0.14.54 + esbuild-linux-arm: 0.14.54 + esbuild-linux-arm64: 0.14.54 + esbuild-linux-mips64le: 0.14.54 + esbuild-linux-ppc64le: 0.14.54 + esbuild-linux-riscv64: 0.14.54 + esbuild-linux-s390x: 0.14.54 + esbuild-netbsd-64: 0.14.54 + esbuild-openbsd-64: 0.14.54 + esbuild-sunos-64: 0.14.54 + esbuild-windows-32: 0.14.54 + esbuild-windows-64: 0.14.54 + esbuild-windows-arm64: 0.14.54 + dev: true + /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} @@ -5298,15 +5974,15 @@ packages: engines: {node: '>= 0.8.0'} dev: true - /expect/28.1.1: - resolution: {integrity: sha512-/AANEwGL0tWBwzLNOvO0yUdy2D52jVdNXppOqswC49sxMN2cPWsGCQdzuIf9tj6hHoBQzNvx75JUYuQAckPo3w==} + /expect/28.1.3: + resolution: {integrity: sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/expect-utils': 28.1.1 + '@jest/expect-utils': 28.1.3 jest-get-type: 28.0.2 - jest-matcher-utils: 28.1.1 - jest-message-util: 28.1.1 - jest-util: 28.1.1 + jest-matcher-utils: 28.1.3 + jest-message-util: 28.1.3 + jest-util: 28.1.3 dev: true /express/4.18.1: @@ -5348,6 +6024,15 @@ packages: - supports-color dev: true + /external-editor/3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + dev: true + /fast-async/6.3.8: resolution: {integrity: sha512-TjlooyqrYm/gOXjD2UHNwfrWkvTbzU105Nk4bvcRTeRoL+wIeK6rqbqDg3CN9z5p37cE2iXhP6SxQFz8OVIaUg==} dependencies: @@ -5411,6 +6096,13 @@ packages: bser: 2.1.1 dev: true + /figures/3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + /file-entry-cache/6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -5505,6 +6197,20 @@ packages: optional: true dev: true + /for-each/0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.4 + dev: true + + /foreground-child/2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 3.0.7 + dev: true + /fork-ts-checker-webpack-plugin/7.2.12_3o2jfq6vfqxns3sz6wn2nnc3ei: resolution: {integrity: sha512-SCjmmjPXPgp5XRQ49hXd2Eqth8rz4+ggtOHygTzyaOn32oIIOd8Kw+xKcgXNkFGlZy5l03bHRYTkbQs+TWhaNA==} engines: {node: '>=12.13.0', yarn: '>=1.0.0'} @@ -5611,6 +6317,10 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-func-name/2.0.0: + resolution: {integrity: sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==} + dev: true + /get-intrinsic/1.1.2: resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==} dependencies: @@ -5730,6 +6440,11 @@ packages: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: true + /graphql/16.6.0: + resolution: {integrity: sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + dev: true + /gzip-size/6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -5794,6 +6509,10 @@ packages: hasBin: true dev: true + /headers-polyfill/3.0.10: + resolution: {integrity: sha512-lOhQU7iG3AMcjmb8NIWCa+KwfJw5bY44BoWPtrj5A4iDbSD3ylGf5QcYr0ZyQnhkKQ2GgWNLdF2rfrXtXlF3nQ==} + dev: true + /hoist-non-react-statics/3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} dependencies: @@ -6029,6 +6748,10 @@ packages: harmony-reflect: 1.6.2 dev: true + /ieee754/1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + /ignore-walk/3.0.4: resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==} dependencies: @@ -6095,6 +6818,27 @@ packages: resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} dev: true + /inquirer/8.2.4: + resolution: {integrity: sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==} + engines: {node: '>=12.0.0'} + dependencies: + ansi-escapes: 4.3.2 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-width: 3.0.0 + external-editor: 3.1.0 + figures: 3.2.0 + lodash: 4.17.21 + mute-stream: 0.0.8 + ora: 5.4.1 + run-async: 2.4.1 + rxjs: 7.5.6 + string-width: 4.2.3 + strip-ansi: 6.0.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + dev: true + /internal-slot/1.0.3: resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} engines: {node: '>= 0.4'} @@ -6132,6 +6876,14 @@ packages: engines: {node: '>= 10'} dev: true + /is-arguments/1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.2 + has-tostringtag: 1.0.0 + dev: true + /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -6201,6 +6953,13 @@ packages: engines: {node: '>=6'} dev: true + /is-generator-function/1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-glob/4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -6208,11 +6967,20 @@ packages: is-extglob: 2.1.1 dev: true + /is-interactive/1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: true + /is-negative-zero/2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} dev: true + /is-node-process/1.0.1: + resolution: {integrity: sha512-5IcdXuf++TTNt3oGl9EBdkvndXA8gmc4bz/Y+mdEpWh3Mcn/+kOw6hI7LD5CocqJWMzeb0I0ClndRVNdEPuJXQ==} + dev: true + /is-number-object/1.0.7: resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} engines: {node: '>= 0.4'} @@ -6317,6 +7085,22 @@ packages: has-symbols: 1.0.3 dev: true + /is-typed-array/1.1.9: + resolution: {integrity: sha512-kfrlnTTn8pZkfpJMUgYD7YZ3qzeJgWUn8XfVYBARc4wnmNOmLbmuuaAs3q5fvB0UJOn6yHAKaGTPM7d6ezoD/A==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-abstract: 1.20.1 + for-each: 0.3.3 + has-tostringtag: 1.0.0 + dev: true + + /is-unicode-supported/0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + /is-weakref/1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: @@ -6389,6 +7173,14 @@ packages: istanbul-lib-report: 3.0.0 dev: true + /istanbul-reports/3.1.5: + resolution: {integrity: sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==} + engines: {node: '>=8'} + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.0 + dev: true + /jest-changed-files/28.0.2: resolution: {integrity: sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6397,26 +7189,27 @@ packages: throat: 6.0.1 dev: true - /jest-circus/28.1.2: - resolution: {integrity: sha512-E2vdPIJG5/69EMpslFhaA46WkcrN74LI5V/cSJ59L7uS8UNoXbzTxmwhpi9XrIL3zqvMt5T0pl5k2l2u2GwBNQ==} + /jest-circus/28.1.3: + resolution: {integrity: sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/environment': 28.1.2 - '@jest/expect': 28.1.2 - '@jest/test-result': 28.1.1 - '@jest/types': 28.1.1 - '@types/node': 18.0.3 + '@jest/environment': 28.1.3 + '@jest/expect': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 18.0.6 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 is-generator-fn: 2.1.0 - jest-each: 28.1.1 - jest-matcher-utils: 28.1.1 - jest-message-util: 28.1.1 - jest-runtime: 28.1.2 - jest-snapshot: 28.1.2 - jest-util: 28.1.1 - pretty-format: 28.1.1 + jest-each: 28.1.3 + jest-matcher-utils: 28.1.3 + jest-message-util: 28.1.3 + jest-runtime: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 + p-limit: 3.1.0 + pretty-format: 28.1.3 slash: 3.0.0 stack-utils: 2.0.5 throat: 6.0.1 @@ -6472,19 +7265,20 @@ packages: chalk: 4.1.2 ci-info: 3.3.2 deepmerge: 4.2.2 + diff-sequences: 28.1.1 glob: 7.2.3 graceful-fs: 4.2.10 - jest-circus: 28.1.2 - jest-environment-node: 28.1.2 + jest-circus: 28.1.3 + jest-environment-node: 28.1.3 jest-get-type: 28.0.2 jest-regex-util: 28.0.2 - jest-resolve: 28.1.1 - jest-runner: 28.1.2 - jest-util: 28.1.1 - jest-validate: 28.1.1 + jest-resolve: 28.1.3 + jest-runner: 28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 micromatch: 4.0.5 parse-json: 5.2.0 - pretty-format: 28.1.1 + pretty-format: 28.1.3 slash: 3.0.0 strip-json-comments: 3.1.1 ts-node: 10.8.2_oob3snywllkr2hdymfpal4vwlq @@ -6502,6 +7296,16 @@ packages: pretty-format: 28.1.1 dev: true + /jest-diff/28.1.3: + resolution: {integrity: sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + chalk: 4.1.2 + diff-sequences: 28.1.1 + jest-get-type: 28.0.2 + pretty-format: 28.1.3 + dev: true + /jest-docblock/28.1.1: resolution: {integrity: sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6509,15 +7313,15 @@ packages: detect-newline: 3.1.0 dev: true - /jest-each/28.1.1: - resolution: {integrity: sha512-A042rqh17ZvEhRceDMi784ppoXR7MWGDEKTXEZXb4svt0eShMZvijGxzKsx+yIjeE8QYmHPrnHiTSQVhN4nqaw==} + /jest-each/28.1.3: + resolution: {integrity: sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/types': 28.1.1 + '@jest/types': 28.1.3 chalk: 4.1.2 jest-get-type: 28.0.2 - jest-util: 28.1.1 - pretty-format: 28.1.1 + jest-util: 28.1.3 + pretty-format: 28.1.3 dev: true /jest-environment-jsdom/28.1.2: @@ -6539,16 +7343,16 @@ packages: - utf-8-validate dev: true - /jest-environment-node/28.1.2: - resolution: {integrity: sha512-oYsZz9Qw27XKmOgTtnl0jW7VplJkN2oeof+SwAwKFQacq3CLlG9u4kTGuuLWfvu3J7bVutWlrbEQMOCL/jughw==} + /jest-environment-node/28.1.3: + resolution: {integrity: sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/environment': 28.1.2 - '@jest/fake-timers': 28.1.2 - '@jest/types': 28.1.1 - '@types/node': 18.0.3 - jest-mock: 28.1.1 - jest-util: 28.1.1 + '@jest/environment': 28.1.3 + '@jest/fake-timers': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 18.0.6 + jest-mock: 28.1.3 + jest-util: 28.1.3 dev: true /jest-fetch-mock/3.0.3: @@ -6571,7 +7375,7 @@ packages: dependencies: '@jest/types': 28.1.1 '@types/graceful-fs': 4.1.5 - '@types/node': 18.0.3 + '@types/node': 18.0.6 anymatch: 3.1.2 fb-watchman: 2.0.1 graceful-fs: 4.2.10 @@ -6584,12 +7388,31 @@ packages: fsevents: 2.3.2 dev: true - /jest-leak-detector/28.1.1: - resolution: {integrity: sha512-4jvs8V8kLbAaotE+wFR7vfUGf603cwYtFf1/PYEsyX2BAjSzj8hQSVTP6OWzseTl0xL6dyHuKs2JAks7Pfubmw==} + /jest-haste-map/28.1.3: + resolution: {integrity: sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/types': 28.1.3 + '@types/graceful-fs': 4.1.5 + '@types/node': 18.0.6 + anymatch: 3.1.2 + fb-watchman: 2.0.1 + graceful-fs: 4.2.10 + jest-regex-util: 28.0.2 + jest-util: 28.1.3 + jest-worker: 28.1.3 + micromatch: 4.0.5 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /jest-leak-detector/28.1.3: + resolution: {integrity: sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: jest-get-type: 28.0.2 - pretty-format: 28.1.1 + pretty-format: 28.1.3 dev: true /jest-localstorage-mock/2.4.21: @@ -6607,6 +7430,16 @@ packages: pretty-format: 28.1.1 dev: true + /jest-matcher-utils/28.1.3: + resolution: {integrity: sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + chalk: 4.1.2 + jest-diff: 28.1.3 + jest-get-type: 28.0.2 + pretty-format: 28.1.3 + dev: true + /jest-message-util/28.1.1: resolution: {integrity: sha512-xoDOOT66fLfmTRiqkoLIU7v42mal/SqwDKvfmfiWAdJMSJiU+ozgluO7KbvoAgiwIrrGZsV7viETjc8GNrA/IQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6622,6 +7455,21 @@ packages: stack-utils: 2.0.5 dev: true + /jest-message-util/28.1.3: + resolution: {integrity: sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@babel/code-frame': 7.18.6 + '@jest/types': 28.1.3 + '@types/stack-utils': 2.0.1 + chalk: 4.1.2 + graceful-fs: 4.2.10 + micromatch: 4.0.5 + pretty-format: 28.1.3 + slash: 3.0.0 + stack-utils: 2.0.5 + dev: true + /jest-mock/28.1.1: resolution: {integrity: sha512-bDCb0FjfsmKweAvE09dZT59IMkzgN0fYBH6t5S45NoJfd2DHkS3ySG2K+hucortryhO3fVuXdlxWcbtIuV/Skw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6630,7 +7478,15 @@ packages: '@types/node': 18.0.3 dev: true - /jest-pnp-resolver/1.2.2_jest-resolve@28.1.1: + /jest-mock/28.1.3: + resolution: {integrity: sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/types': 28.1.3 + '@types/node': 18.0.6 + dev: true + + /jest-pnp-resolver/1.2.2_jest-resolve@28.1.3: resolution: {integrity: sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==} engines: {node: '>=6'} peerDependencies: @@ -6639,7 +7495,7 @@ packages: jest-resolve: optional: true dependencies: - jest-resolve: 28.1.1 + jest-resolve: 28.1.3 dev: true /jest-regex-util/28.0.2: @@ -6647,92 +7503,92 @@ packages: engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dev: true - /jest-resolve-dependencies/28.1.2: - resolution: {integrity: sha512-OXw4vbOZuyRTBi3tapWBqdyodU+T33ww5cPZORuTWkg+Y8lmsxQlVu3MWtJh6NMlKRTHQetF96yGPv01Ye7Mbg==} + /jest-resolve-dependencies/28.1.3: + resolution: {integrity: sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: jest-regex-util: 28.0.2 - jest-snapshot: 28.1.2 + jest-snapshot: 28.1.3 transitivePeerDependencies: - supports-color dev: true - /jest-resolve/28.1.1: - resolution: {integrity: sha512-/d1UbyUkf9nvsgdBildLe6LAD4DalgkgZcKd0nZ8XUGPyA/7fsnaQIlKVnDiuUXv/IeZhPEDrRJubVSulxrShA==} + /jest-resolve/28.1.3: + resolution: {integrity: sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: chalk: 4.1.2 graceful-fs: 4.2.10 - jest-haste-map: 28.1.1 - jest-pnp-resolver: 1.2.2_jest-resolve@28.1.1 - jest-util: 28.1.1 - jest-validate: 28.1.1 + jest-haste-map: 28.1.3 + jest-pnp-resolver: 1.2.2_jest-resolve@28.1.3 + jest-util: 28.1.3 + jest-validate: 28.1.3 resolve: 1.22.1 resolve.exports: 1.1.0 slash: 3.0.0 dev: true - /jest-runner/28.1.2: - resolution: {integrity: sha512-6/k3DlAsAEr5VcptCMdhtRhOoYClZQmxnVMZvZ/quvPGRpN7OBQYPIC32tWSgOnbgqLXNs5RAniC+nkdFZpD4A==} + /jest-runner/28.1.3: + resolution: {integrity: sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/console': 28.1.1 - '@jest/environment': 28.1.2 - '@jest/test-result': 28.1.1 - '@jest/transform': 28.1.2 - '@jest/types': 28.1.1 - '@types/node': 18.0.3 + '@jest/console': 28.1.3 + '@jest/environment': 28.1.3 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 18.0.6 chalk: 4.1.2 emittery: 0.10.2 graceful-fs: 4.2.10 jest-docblock: 28.1.1 - jest-environment-node: 28.1.2 - jest-haste-map: 28.1.1 - jest-leak-detector: 28.1.1 - jest-message-util: 28.1.1 - jest-resolve: 28.1.1 - jest-runtime: 28.1.2 - jest-util: 28.1.1 - jest-watcher: 28.1.1 - jest-worker: 28.1.1 + jest-environment-node: 28.1.3 + jest-haste-map: 28.1.3 + jest-leak-detector: 28.1.3 + jest-message-util: 28.1.3 + jest-resolve: 28.1.3 + jest-runtime: 28.1.3 + jest-util: 28.1.3 + jest-watcher: 28.1.3 + jest-worker: 28.1.3 + p-limit: 3.1.0 source-map-support: 0.5.13 - throat: 6.0.1 transitivePeerDependencies: - supports-color dev: true - /jest-runtime/28.1.2: - resolution: {integrity: sha512-i4w93OsWzLOeMXSi9epmakb2+3z0AchZtUQVF1hesBmcQQy4vtaql5YdVe9KexdJaVRyPDw8DoBR0j3lYsZVYw==} + /jest-runtime/28.1.3: + resolution: {integrity: sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/environment': 28.1.2 - '@jest/fake-timers': 28.1.2 - '@jest/globals': 28.1.2 + '@jest/environment': 28.1.3 + '@jest/fake-timers': 28.1.3 + '@jest/globals': 28.1.3 '@jest/source-map': 28.1.2 - '@jest/test-result': 28.1.1 - '@jest/transform': 28.1.2 - '@jest/types': 28.1.1 + '@jest/test-result': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 execa: 5.1.1 glob: 7.2.3 graceful-fs: 4.2.10 - jest-haste-map: 28.1.1 - jest-message-util: 28.1.1 - jest-mock: 28.1.1 + jest-haste-map: 28.1.3 + jest-message-util: 28.1.3 + jest-mock: 28.1.3 jest-regex-util: 28.0.2 - jest-resolve: 28.1.1 - jest-snapshot: 28.1.2 - jest-util: 28.1.1 + jest-resolve: 28.1.3 + jest-snapshot: 28.1.3 + jest-util: 28.1.3 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color dev: true - /jest-snapshot/28.1.2: - resolution: {integrity: sha512-wzrieFttZYfLvrCVRJxX+jwML2YTArOUqFpCoSVy1QUapx+LlV9uLbV/mMEhYj4t7aMeE9aSQFHSvV/oNoDAMA==} + /jest-snapshot/28.1.3: + resolution: {integrity: sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: '@babel/core': 7.18.6 @@ -6740,23 +7596,23 @@ packages: '@babel/plugin-syntax-typescript': 7.18.6_@babel+core@7.18.6 '@babel/traverse': 7.18.8 '@babel/types': 7.18.8 - '@jest/expect-utils': 28.1.1 - '@jest/transform': 28.1.2 - '@jest/types': 28.1.1 + '@jest/expect-utils': 28.1.3 + '@jest/transform': 28.1.3 + '@jest/types': 28.1.3 '@types/babel__traverse': 7.17.1 '@types/prettier': 2.6.3 babel-preset-current-node-syntax: 1.0.1_@babel+core@7.18.6 chalk: 4.1.2 - expect: 28.1.1 + expect: 28.1.3 graceful-fs: 4.2.10 - jest-diff: 28.1.1 + jest-diff: 28.1.3 jest-get-type: 28.0.2 - jest-haste-map: 28.1.1 - jest-matcher-utils: 28.1.1 - jest-message-util: 28.1.1 - jest-util: 28.1.1 + jest-haste-map: 28.1.3 + jest-matcher-utils: 28.1.3 + jest-message-util: 28.1.3 + jest-util: 28.1.3 natural-compare: 1.4.0 - pretty-format: 28.1.1 + pretty-format: 28.1.3 semver: 7.3.7 transitivePeerDependencies: - supports-color @@ -6774,6 +7630,18 @@ packages: picomatch: 2.3.1 dev: true + /jest-util/28.1.3: + resolution: {integrity: sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/types': 28.1.3 + '@types/node': 18.0.6 + chalk: 4.1.2 + ci-info: 3.3.2 + graceful-fs: 4.2.10 + picomatch: 2.3.1 + dev: true + /jest-validate/28.1.1: resolution: {integrity: sha512-Kpf6gcClqFCIZ4ti5++XemYJWUPCFUW+N2gknn+KgnDf549iLul3cBuKVe1YcWRlaF8tZV8eJCap0eECOEE3Ug==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6786,17 +7654,29 @@ packages: pretty-format: 28.1.1 dev: true - /jest-watcher/28.1.1: - resolution: {integrity: sha512-RQIpeZ8EIJMxbQrXpJQYIIlubBnB9imEHsxxE41f54ZwcqWLysL/A0ZcdMirf+XsMn3xfphVQVV4EW0/p7i7Ug==} + /jest-validate/28.1.3: + resolution: {integrity: sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} dependencies: - '@jest/test-result': 28.1.1 - '@jest/types': 28.1.1 - '@types/node': 18.0.3 + '@jest/types': 28.1.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 28.0.2 + leven: 3.1.0 + pretty-format: 28.1.3 + dev: true + + /jest-watcher/28.1.3: + resolution: {integrity: sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/test-result': 28.1.3 + '@jest/types': 28.1.3 + '@types/node': 18.0.6 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.10.2 - jest-util: 28.1.1 + jest-util: 28.1.3 string-length: 4.0.2 dev: true @@ -6818,6 +7698,15 @@ packages: supports-color: 8.1.1 dev: true + /jest-worker/28.1.3: + resolution: {integrity: sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@types/node': 18.0.6 + merge-stream: 2.0.0 + supports-color: 8.1.1 + dev: true + /jest/28.1.2_eudefza5kbv4z3gj6nnnsfn4wu: resolution: {integrity: sha512-Tuf05DwLeCh2cfWCQbcz9UxldoDyiR1E9Igaei5khjonKncYdc6LDfynKCEWozK0oLE3GD+xKAo2u8x/0s6GOg==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -6838,6 +7727,11 @@ packages: - ts-node dev: true + /js-levenshtein/1.1.6: + resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} + engines: {node: '>=0.10.0'} + dev: true + /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} dev: true @@ -6903,6 +7797,48 @@ packages: - utf-8-validate dev: true + /jsdom/20.0.0: + resolution: {integrity: sha512-x4a6CKCgx00uCmP+QakBDFXwjAJ69IkkIWHmtmjd3wvXPcdOS44hfX2vqkOQrVrq8l9DhNNADZRXaCEWvgXtVA==} + engines: {node: '>=14'} + peerDependencies: + canvas: ^2.5.0 + peerDependenciesMeta: + canvas: + optional: true + dependencies: + abab: 2.0.6 + acorn: 8.7.1 + acorn-globals: 6.0.0 + cssom: 0.5.0 + cssstyle: 2.3.0 + data-urls: 3.0.2 + decimal.js: 10.3.1 + 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.1 + parse5: 7.0.0 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 4.0.0 + w3c-hr-time: 1.0.2 + w3c-xmlserializer: 3.0.0 + webidl-conversions: 7.0.0 + whatwg-encoding: 2.0.0 + whatwg-mimetype: 3.0.0 + whatwg-url: 11.0.0 + ws: 8.8.0 + xml-name-validator: 4.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + /jsesc/0.5.0: resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} hasBin: true @@ -7088,6 +8024,11 @@ packages: json5: 2.2.1 dev: true + /local-pkg/0.4.2: + resolution: {integrity: sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==} + engines: {node: '>=14'} + dev: true + /locate-path/2.0.0: resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} engines: {node: '>=4'} @@ -7153,6 +8094,14 @@ packages: /lodash/4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + /log-symbols/4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + /log-update/4.0.0: resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} engines: {node: '>=10'} @@ -7170,6 +8119,12 @@ packages: js-tokens: 4.0.0 dev: true + /loupe/2.3.4: + resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} + dependencies: + get-func-name: 2.0.0 + dev: true + /lower-case/2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: @@ -7381,6 +8336,43 @@ packages: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true + /msw/0.44.2_typescript@4.7.4: + resolution: {integrity: sha512-u8wjzzcMWouoZtuIShCwx4M3wFF5sBAV1f8K4a0WX8kiihFjzl89IKE1VYmTclLyMIwpOq8qQ1HTpuh2BFX/3A==} + engines: {node: '>=14'} + hasBin: true + requiresBuild: true + peerDependencies: + typescript: '>= 4.2.x <= 4.7.x' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@mswjs/cookies': 0.2.2 + '@mswjs/interceptors': 0.17.3 + '@open-draft/until': 1.0.3 + '@types/cookie': 0.4.1 + '@types/js-levenshtein': 1.1.1 + chalk: 4.1.1 + chokidar: 3.5.3 + cookie: 0.4.2 + graphql: 16.6.0 + headers-polyfill: 3.0.10 + inquirer: 8.2.4 + is-node-process: 1.0.1 + js-levenshtein: 1.1.6 + node-fetch: 2.6.7 + outvariant: 1.3.0 + path-to-regexp: 6.2.1 + statuses: 2.0.1 + strict-event-emitter: 0.2.4 + type-fest: 1.4.0 + typescript: 4.7.4 + yargs: 17.5.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + /multicast-dns/7.2.5: resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} hasBin: true @@ -7389,6 +8381,10 @@ packages: thunky: 1.1.0 dev: true + /mute-stream/0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + dev: true + /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -7699,6 +8695,30 @@ packages: word-wrap: 1.2.3 dev: true + /ora/5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.7.0 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: true + + /os-tmpdir/1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + dev: true + + /outvariant/1.3.0: + resolution: {integrity: sha512-yeWM9k6UPfG/nzxdaPlJkB2p08hCg4xP6Lx99F+vP8YF7xyZVfTmJjrrNalkmzudD4WFvNLVudQikqUmF8zhVQ==} + dev: true + /p-limit/1.3.0: resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} engines: {node: '>=4'} @@ -7874,6 +8894,10 @@ packages: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} dev: true + /path-to-regexp/6.2.1: + resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} + dev: true + /path-type/3.0.0: resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} engines: {node: '>=4'} @@ -7886,6 +8910,10 @@ packages: engines: {node: '>=8'} dev: true + /pathval/1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + /performance-now/2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: true @@ -8658,6 +9686,15 @@ packages: source-map-js: 1.0.2 dev: true + /postcss/8.4.16: + resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /preact/10.6.2: resolution: {integrity: sha512-ppDjurt75nSxyikpyali+uKwRl8CK9N6ntOPovGIEGQagjMLVzEgVqFEsUUyUrqyE9Ch90KE0jmFc9q2QcPLBA==} @@ -8710,6 +9747,16 @@ packages: react-is: 18.2.0 dev: true + /pretty-format/28.1.3: + resolution: {integrity: sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==} + engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} + dependencies: + '@jest/schemas': 28.1.3 + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 18.2.0 + dev: true + /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true @@ -9132,6 +10179,14 @@ packages: glob: 7.2.3 dev: true + /rollup/2.77.3: + resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} + engines: {node: '>=10.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.2 + dev: true + /rst-selector-parser/2.2.3: resolution: {integrity: sha512-nDG1rZeP6oFTLN6yNDV/uiAvs1+FS/KlrEwh7+y7dpuApDBy6bI2HTBcc0/V8lv9OTqfyD34eF7au2pm8aBbhA==} dependencies: @@ -9139,6 +10194,11 @@ packages: nearley: 2.20.1 dev: true + /run-async/2.4.1: + resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} + engines: {node: '>=0.12.0'} + dev: true + /run-parallel/1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: @@ -9170,6 +10230,13 @@ packages: xmlchars: 2.2.0 dev: true + /saxes/6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + dependencies: + xmlchars: 2.2.0 + dev: true + /schema-utils/2.7.1: resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} engines: {node: '>= 8.9.0'} @@ -9294,6 +10361,10 @@ packages: - supports-color dev: true + /set-cookie-parser/2.5.1: + resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==} + dev: true + /setprototypeof/1.1.0: resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} dev: true @@ -9451,6 +10522,7 @@ packages: /source-map/0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} + requiresBuild: true dev: true /spdx-correct/3.1.1: @@ -9533,6 +10605,12 @@ packages: stubs: 3.0.0 dev: true + /strict-event-emitter/0.2.4: + resolution: {integrity: sha512-xIqTLS5azUH1djSUsLH9DbP6UnM/nI18vu8d43JigCQEoVsnY+mrlE+qv6kYqs6/1OkMnMIiL6ffedQSZStuoQ==} + dependencies: + events: 3.3.0 + dev: true + /string-argv/0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} engines: {node: '>=0.6.19'} @@ -9943,6 +11021,23 @@ packages: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} dev: true + /tinypool/0.2.4: + resolution: {integrity: sha512-Vs3rhkUH6Qq1t5bqtb816oT+HeJTXfwt2cbPH17sWHIYKTotQIFPk3tf2fgqRrVyMDVOc1EnPgzIxfIulXVzwQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy/1.0.2: + resolution: {integrity: sha512-bSGlgwLBYf7PnUsQ6WOc6SJ3pGOcd+d8AA6EUnLDDM0kWEstC1JIlSZA3UNliDXhd9ABoS7hiRBDCu+XP/sf1Q==} + engines: {node: '>=14.0.0'} + dev: true + + /tmp/0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + dependencies: + os-tmpdir: 1.0.2 + dev: true + /tmpl/1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} dev: true @@ -10041,6 +11136,37 @@ packages: yn: 3.1.1 dev: true + /ts-node/10.9.1_tdn3ypgnfy6bmey2q4hu5jonwi: + resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.9 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.3 + '@types/node': 18.0.6 + acorn: 8.7.1 + acorn-walk: 8.2.0 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 4.7.4 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + dev: true + /tsconfig-paths-webpack-plugin/3.5.2: resolution: {integrity: sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw==} dependencies: @@ -10075,6 +11201,139 @@ packages: typescript: 4.7.4 dev: true + /turbo-android-arm64/1.4.3: + resolution: {integrity: sha512-ZUvdoEHJkTkOFOO9PKWYrdONDBVqkNsvwEMufTVf07RXgqmbXDPkznzT4hcQm6xXyqWqJdjgSAMdlm+2nNE1Og==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /turbo-darwin-64/1.4.3: + resolution: {integrity: sha512-gapoVm5qbu2TJS4lJ6fM3o2eAkLyXSxHihw/4NRAYmwHCH3at1/cIAnRcctB/HLL3ZaB/p3HKb8mnI7k6xNHOw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /turbo-darwin-arm64/1.4.3: + resolution: {integrity: sha512-XUe6FTsHamEH7FfNslYYO04yecAaguhZuwW4kE9B/BAP8MUYsmVqONauLPyE/YqM6pf2K0xwVe+RlEGf53CWbg==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /turbo-freebsd-64/1.4.3: + resolution: {integrity: sha512-1CAjXmDClgMXdWZXreUfAbGBB2WB9TZHfJIdsgnDqt4fIcFGChknzYqc+Fj3tGHAczMpinGjBbWIzFuxOq/ofQ==} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /turbo-freebsd-arm64/1.4.3: + resolution: {integrity: sha512-j5C7j/vwabPKpr5d6YlLgHGHBZCOcXj3HdkBshDHTQ0wghH0NuCUUaesYxI3wva/4/Ec0dhIrb20Laa/HMxXLA==} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-32/1.4.3: + resolution: {integrity: sha512-vnc+StXIoQEnxIU43j7rEz/J+v+RV4dbUdUolBq0k9gkUV8KMCcqPkIa753K47E2KLNGKXMaYDI6AHQX1GAQZg==} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-64/1.4.3: + resolution: {integrity: sha512-KAUeIa8Ejt6BLrBGbVurlrjDxqh62tu75D4cqKqKfzWspcbEtmdqlV6qthXfm8SlzGSNuQXX0+qXEWds2FIZXg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-arm/1.4.3: + resolution: {integrity: sha512-zZNoHUK5ioFyxAngh8tHe763Dzb22ne3LJkaZn0ExkFHJtWClWv536lPcDuQPpIH9W9iz5OwPKtN32DNpNwk8A==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-arm64/1.4.3: + resolution: {integrity: sha512-rzB7w+RHCQkKr8aDxxozv/IzdN976CYyBiRocSf9QGU73uyAg8pCo3i0MiENSRjDC+tUbdbu2lEUwGXf9ziB9Q==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-mips64le/1.4.3: + resolution: {integrity: sha512-Ztr1BM5NiUsHWjB7zpkP2RpRDA/fjbLaCbkyfyGlLmVkrSkh05NFBD03IWs2LSLy/wb6vRpL3MQ4FKcb97Tn8w==} + cpu: [mipsel] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-linux-ppc64le/1.4.3: + resolution: {integrity: sha512-tJaFJWxwfy/iLd69VHZj6JcXy9hO8LQ+ZUOna/p/wiy5WrFVgEYlD+4gfECfRZ+52EIelMgXl97vACaN1WMhLw==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-32/1.4.3: + resolution: {integrity: sha512-w9LyYd+DW3PYFXu9vQiie5lfdqmVIKLV0h181C49hempkIXfgQAosXfaugYWDwBc0GEBoBIQB0vGQKE7gt5nzA==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-64/1.4.3: + resolution: {integrity: sha512-qPCqemxxOrXyqqig3fVQozRkOwo5oJSsQ3FTZE5YlNu2NwwWvY1mC0X4WTZIDsbj4oHqr0riqC7RGKbjQm1IIQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo-windows-arm64/1.4.3: + resolution: {integrity: sha512-djnOOBjw33AnUx2SR6TMOpDr3nKLnVD+HcZvnQz70HyE331AKWjBoEE4rtUOteLAfViWAp3afbiljFSOnbU00Q==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /turbo/1.4.3: + resolution: {integrity: sha512-g08eD2HdO/XW5xGHnXr0cXGiWnrgFBI6pN/3u0EOTeerKAsWIZU0ZrpSnl3whRtImeBB/gQu7Eu1waM2VOxzgw==} + hasBin: true + requiresBuild: true + optionalDependencies: + turbo-android-arm64: 1.4.3 + turbo-darwin-64: 1.4.3 + turbo-darwin-arm64: 1.4.3 + turbo-freebsd-64: 1.4.3 + turbo-freebsd-arm64: 1.4.3 + turbo-linux-32: 1.4.3 + turbo-linux-64: 1.4.3 + turbo-linux-arm: 1.4.3 + turbo-linux-arm64: 1.4.3 + turbo-linux-mips64le: 1.4.3 + turbo-linux-ppc64le: 1.4.3 + turbo-windows-32: 1.4.3 + turbo-windows-64: 1.4.3 + turbo-windows-arm64: 1.4.3 + dev: true + /type-check/0.3.2: resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==} engines: {node: '>= 0.8.0'} @@ -10119,6 +11378,11 @@ packages: engines: {node: '>=8'} dev: true + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + /type-is/1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -10231,6 +11495,17 @@ packages: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} dev: true + /util/0.12.4: + resolution: {integrity: sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw==} + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.9 + safe-buffer: 5.2.1 + which-typed-array: 1.1.8 + dev: true + /utila/0.4.0: resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} dev: true @@ -10274,6 +11549,73 @@ packages: engines: {node: '>= 0.8'} dev: true + /vite/3.0.9: + resolution: {integrity: sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + less: '*' + sass: '*' + stylus: '*' + terser: ^5.4.0 + peerDependenciesMeta: + less: + optional: true + sass: + optional: true + stylus: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.14.54 + postcss: 8.4.16 + resolve: 1.22.1 + rollup: 2.77.3 + optionalDependencies: + fsevents: 2.3.2 + dev: true + + /vitest/0.22.1_jsdom@20.0.0: + resolution: {integrity: sha512-+x28YTnSLth4KbXg7MCzoDAzPJlJex7YgiZbUh6YLp0/4PqVZ7q7/zyfdL0OaPtKTpNiQFPpMC8Y2MSzk8F7dw==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@vitest/browser': '*' + '@vitest/ui': '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.3 + '@types/chai-subset': 1.3.3 + '@types/node': 18.0.6 + chai: 4.3.6 + debug: 4.3.4 + jsdom: 20.0.0 + local-pkg: 0.4.2 + tinypool: 0.2.4 + tinyspy: 1.0.2 + vite: 3.0.9 + transitivePeerDependencies: + - less + - sass + - stylus + - supports-color + - terser + dev: true + /w3c-hr-time/1.0.2: resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==} dependencies: @@ -10307,6 +11649,20 @@ packages: minimalistic-assert: 1.0.1 dev: true + /wcwidth/1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.3 + dev: true + + /web-encoding/1.1.5: + resolution: {integrity: sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==} + dependencies: + util: 0.12.4 + optionalDependencies: + '@zxing/text-encoding': 0.9.0 + dev: true + /webidl-conversions/3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} dev: true @@ -10510,6 +11866,10 @@ packages: iconv-lite: 0.6.3 dev: true + /whatwg-fetch/3.6.2: + resolution: {integrity: sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==} + dev: true + /whatwg-mimetype/3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} @@ -10548,6 +11908,18 @@ packages: is-symbol: 1.0.4 dev: true + /which-typed-array/1.1.8: + resolution: {integrity: sha512-Jn4e5PItbcAHyLoRDwvPj1ypu27DJbtdYXUa5zsinrUx77Uvfb0cXwwnGMTn7cjUfhhqgVQnVJCwF+7cgU7tpw==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.2 + es-abstract: 1.20.1 + for-each: 0.3.3 + has-tostringtag: 1.0.0 + is-typed-array: 1.1.9 + dev: true + /which/1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -10666,6 +12038,19 @@ packages: engines: {node: '>=12'} dev: true + /yargs/16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + dependencies: + cliui: 7.0.4 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + dev: true + /yargs/17.5.1: resolution: {integrity: sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==} engines: {node: '>=12'} diff --git a/frontend/pnpm-workspace.yaml b/frontend/pnpm-workspace.yaml index 06b6051910..3ff5faaaf5 100644 --- a/frontend/pnpm-workspace.yaml +++ b/frontend/pnpm-workspace.yaml @@ -1,2 +1,3 @@ packages: - "apps/*" + - "packages/*"