diff --git a/.babelrc b/.babelrc deleted file mode 100644 index d8738ccfe..000000000 --- a/.babelrc +++ /dev/null @@ -1,21 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "browsers": ["last 2 versions", "ie >= 10"] - } - } - ], - "@babel/preset-typescript" - ], - "sourceType": "unambiguous", - "plugins": [ - "@babel/plugin-transform-object-assign", - "@babel/plugin-transform-runtime", - "@babel/proposal-object-rest-spread", - "@babel/plugin-proposal-class-properties" - ], - "ignore": ["node_modules", "dist"] -} diff --git a/.commitlintrc.js b/.commitlintrc.js deleted file mode 100644 index 4c73b71e6..000000000 --- a/.commitlintrc.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['@commitlint/config-conventional'], -}; diff --git a/.commitlintrc.json b/.commitlintrc.json new file mode 100644 index 000000000..b4eb7e992 --- /dev/null +++ b/.commitlintrc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://json.schemastore.org/commitlintrc.json", + "extends": ["@commitlint/config-conventional"] +} diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 6c4492f2a..000000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -/dist -/node_modules -/test -scripts/get_changelog_diff.js -*.md diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 775cd5349..000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "plugins": ["markdown", "sonarjs", "prettier", "@typescript-eslint", "typescript-sort-keys"], - "extends": ["eslint:recommended", "plugin:sonarjs/recommended", "plugin:@typescript-eslint/recommended", "prettier"], - "rules": { - "@typescript-eslint/ban-ts-comment": 0, - "@typescript-eslint/explicit-module-boundary-types": 0, - "@typescript-eslint/ban-types": 0, - "@typescript-eslint/no-this-alias": 0, - "@typescript-eslint/triple-slash-reference": 0, - "no-console": 0, - "no-class-assign": 0, - "no-mixed-spaces-and-tabs": 0, - "comma-dangle": 0, - "no-unused-vars": 0, - "@typescript-eslint/no-unused-vars": 1, - "eqeqeq": [2, "smart"], - "no-useless-concat": 2, - "default-case": 2, - "no-self-compare": 2, - "prefer-const": 2, - "object-shorthand": 1, - "array-callback-return": 2, - "valid-typeof": 2, - "react/prop-types": 0, - "no-var": 2, - "linebreak-style": [2, "unix"], - "semi": [1, "always"], - "no-buffer-constructor": "error", - "sonarjs/cognitive-complexity": ["error", 30], - "sonarjs/no-duplicate-string": 0, - "typescript-sort-keys/interface": [ - "error", - "asc", - { - "caseSensitive": false, - "natural": true, - "requiredFirst": true - } - ], - "typescript-sort-keys/string-enum": [ - "error", - "asc", - { - "caseSensitive": false, - "natural": true - } - ] - }, - "env": { - "es6": true, - "node": true, - "browser": true - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "sourceType": "module", - "ecmaVersion": 2018, - "ecmaFeatures": { - "modules": true - } - }, - "overrides": [ - { - "files": ["*.md"], - "rules": { - "react/jsx-no-undef": 0, - "react/react-in-jsx-scope": 0, - "no-unused-vars": 0, - "semi": 0, - "no-undef": 0 - } - } - ] -} diff --git a/.github/actions/setup-node/action.yml b/.github/actions/setup-node/action.yml index f437c730d..052feeac9 100644 --- a/.github/actions/setup-node/action.yml +++ b/.github/actions/setup-node/action.yml @@ -3,12 +3,12 @@ description: Sets up Node and Build SDK inputs: node-version: - description: "Specify Node version" + description: 'Specify Node version' required: false - default: "22" + default: '22' runs: - using: "composite" + using: 'composite' steps: - name: Setup Node uses: actions/setup-node@v3 @@ -20,13 +20,12 @@ runs: shell: bash run: echo "NODE_VERSION=$(node --version)" >> $GITHUB_ENV - - name: Cache Dependencies + - name: Cache dependencies uses: actions/cache@v3 with: path: ./node_modules - key: ${{ runner.os }}-${{ inputs.node-version }}-modules-${{ hashFiles('**/yarn.lock') }} - restore-keys: ${{ runner.os }}-${{ inputs.node-version }}-modules- + key: ${{ runner.os }}-${{ env.NODE_VERSION }}-modules-${{ hashFiles('./yarn.lock') }} - - name: Install Dependencies & Build - run: yarn install --frozen-lockfile --ignore-engines + - name: Install dependencies + run: yarn install --frozen-lockfile shell: bash diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7099251a0..e7d26b547 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -3,7 +3,7 @@ on: pull_request: types: [opened, synchronize, reopened, edited] -concurrency: +concurrency: group: ${{ github.workflow }}-${{ github.head_ref }} cancel-in-progress: true @@ -11,12 +11,9 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/setup-node - - name: Commit message lint - run: echo "${{ github.event.pull_request.title }}" | yarn commitlinter - - name: Lint run: yarn lint diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml new file mode 100644 index 000000000..b1918d269 --- /dev/null +++ b/.github/workflows/pr-check.yml @@ -0,0 +1,16 @@ +name: Check PR title + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +jobs: + pr-title: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - uses: ./.github/actions/setup-node + + - name: commitlint + run: echo "${{ github.event.pull_request.title }}" | npx commitlint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 57be904d6..9b732f196 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,6 +29,7 @@ jobs: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} # https://github.com/stream-ci-bot GH_TOKEN: ${{ secrets.DOCUSAURUS_GH_TOKEN }} + GITHUB_TOKEN: ${{ secrets.DOCUSAURUS_GH_TOKEN }} HUSKY: 0 run: > yarn semantic-release diff --git a/.github/workflows/scheduled_test.yml b/.github/workflows/scheduled_test.yml index 40304cf06..5d2884604 100644 --- a/.github/workflows/scheduled_test.yml +++ b/.github/workflows/scheduled_test.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: schedule: # Monday at 9:00 UTC - - cron: "0 9 * * 1" + - cron: '0 9 * * 1' jobs: test: diff --git a/.github/workflows/size.yml b/.github/workflows/size.yml index a022ad3e4..c67f11ab3 100644 --- a/.github/workflows/size.yml +++ b/.github/workflows/size.yml @@ -6,7 +6,7 @@ on: - 'test/**' - '**.md' -concurrency: +concurrency: group: ${{ github.workflow }}-${{ github.head_ref }} cancel-in-progress: true diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 000000000..57fafac34 --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,3 @@ +#!/usr/bin/env sh + +npx commitlint --edit $1 diff --git a/.husky/pre-commit b/.husky/pre-commit index afd56763a..5a6501e5a 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,5 @@ +#!/usr/bin/env sh + if ! yarn run lint-staged; then echo echo "Some files were not formatted correctly (see output above), commit aborted!" diff --git a/.lintstagedrc.fix.json b/.lintstagedrc.fix.json index 8c7234801..d1bfd3b96 100644 --- a/.lintstagedrc.fix.json +++ b/.lintstagedrc.fix.json @@ -1,4 +1,4 @@ { - "{**/*.{js,ts,md,css,scss,json}, .eslintrc.json, .prettierrc, .babelrc}": "prettier --write", - "**/*.{js,md,ts}": "eslint --fix" + "**/*.{json,js,mjs,ts,yml,md}": "prettier --write", + "**/*.{js,mjs,ts}": "eslint --fix" } diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 8bdbf1e89..92e367ee6 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,4 +1,4 @@ { - "{**/*.{js,ts,md,css,scss,json}, .eslintrc.json, .prettierrc, .babelrc}": "prettier --list-different", - "**/*.{js,md,ts}, !test": "eslint --max-warnings 0" + "**/*.{json,js,mjs,ts,yml,md}": "prettier --list-different", + "**/*.{js,mjs,ts}, !test": "eslint --max-warnings 0" } diff --git a/.mocharc.json b/.mocharc.json deleted file mode 100644 index 4b1283fce..000000000 --- a/.mocharc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "https://json.schemastore.org/mocharc", - "bail": true, - "exit": true, - "timeout": 20000, - "require": ["ts-node/register"] -} diff --git a/.prettierignore b/.prettierignore index 9a6d504a1..bdcfb56e3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,5 @@ /dist /node_modules /.vscode -/types CHANGELOG.md test/typescript/data.ts \ No newline at end of file diff --git a/.prettierrc b/.prettierrc index e92009c67..48f0a723d 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,17 +1,17 @@ { - "useTabs": false, - "printWidth": 120, - "tabWidth": 2, + "arrowParens": "always", + "jsxSingleQuote": true, + "printWidth": 90, "singleQuote": true, + "tabWidth": 2, "trailingComma": "all", - "jsxBracketSameLine": false, + "useTabs": false, "semi": true, "overrides": [ { "files": "*.js", "options": { - "useTabs": true, - "tabWidth": 4 + "useTabs": true } } ] diff --git a/README.md b/README.md index de40b906d..2f891b767 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,9 @@ await client.upsertUser({ }); // create a channel -const channel = client.channel('messaging', 'test-channel', { created_by_id: 'vishal-1' }); +const channel = client.channel('messaging', 'test-channel', { + created_by_id: 'vishal-1', +}); await channel.create(); // send message @@ -84,10 +86,16 @@ declare module 'stream-chat' { // index.ts // property `profile_picture` is code-completed and expects type `string | undefined` -await client.partialUpdateUser({ id: 'vishal-1', set: { profile_picture: 'https://random.picture/1.jpg' } }); +await client.partialUpdateUser({ + id: 'vishal-1', + set: { profile_picture: 'https://random.picture/1.jpg' }, +}); // property `custom_property` is code-completed and expects type `number | undefined` -const { message } = await channel.sendMessage({ text: 'This is another test message', custom_property: 255 }); +const { message } = await channel.sendMessage({ + text: 'This is another test message', + custom_property: 255, +}); message.custom_property; // in the response object as well ``` diff --git a/babel-register.js b/babel-register.js deleted file mode 100644 index 0e4c87206..000000000 --- a/babel-register.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -require('@babel/register')({ extensions: ['.js', '.ts'] }); diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..426b580b1 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,88 @@ +import js from '@eslint/js'; +import globals from 'globals'; +import tseslint from 'typescript-eslint'; + +import importPlugin from 'eslint-plugin-import'; + +export default tseslint.config( + { + ignores: ['dist', 'src/@types', '*.{js,ts}'], + }, + { + name: 'default', + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['src/**/*.{js,ts}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + import: importPlugin, + }, + settings: { + react: { + version: 'detect', + }, + }, + rules: { + camelcase: 'off', + semi: ['warn', 'always'], + eqeqeq: ['error', 'smart'], + 'array-callback-return': 'error', + 'arrow-body-style': 'error', + 'comma-dangle': 'off', + 'default-case': 'error', + 'jsx-quotes': ['error', 'prefer-single'], + 'linebreak-style': ['error', 'unix'], + 'no-console': 'off', + 'no-mixed-spaces-and-tabs': 'warn', + 'no-self-compare': 'error', + 'no-underscore-dangle': 'off', + 'no-use-before-define': 'off', + 'no-useless-concat': 'error', + 'no-var': 'error', + 'no-script-url': 'error', + 'no-continue': 'off', + 'object-shorthand': 'warn', + 'prefer-const': 'warn', + 'require-await': 'error', + 'sort-imports': [ + 'error', + { + allowSeparatedGroups: true, + ignoreCase: true, + ignoreDeclarationSort: true, + ignoreMemberSort: false, + memberSyntaxSortOrder: ['none', 'all', 'multiple', 'single'], + }, + ], + 'sort-keys': 'off', + 'valid-typeof': 'error', + 'max-classes-per-file': 'off', + 'no-unused-expressions': 'off', + 'import/prefer-default-export': 'off', + 'import/extensions': 'off', + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: true, // TODO: set to false once React is in the dependencies (not devDependencies) + optionalDependencies: false, + peerDependencies: false, + }, + ], + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { ignoreRestSiblings: false, caughtErrors: 'none' }, + ], + '@typescript-eslint/no-unsafe-function-type': 'error', + '@typescript-eslint/no-wrapper-object-types': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + 'no-empty-function': 'off', + '@typescript-eslint/no-empty-function': 'warn', + '@typescript-eslint/no-require-imports': 'off', // TODO: remove this rule once all files are .mjs (and require is not used) + '@typescript-eslint/consistent-type-imports': 'error', + '@typescript-eslint/no-empty-object-type': 'off', + }, + }, +); diff --git a/package.json b/package.json index 56011c291..00321498b 100644 --- a/package.json +++ b/package.json @@ -59,71 +59,53 @@ "ws": "^8.18.1" }, "devDependencies": { - "@commitlint/cli": "^16.0.2", - "@commitlint/config-conventional": "^16.0.0", + "@commitlint/cli": "^19.7.1", + "@commitlint/config-conventional": "^19.7.1", + "@eslint/js": "^9.21.0", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "@types/base64-js": "^1.3.0", - "@types/chai": "^4.2.15", - "@types/chai-arrays": "^2.0.0", - "@types/chai-as-promised": "^7.1.4", - "@types/chai-like": "^1.1.1", - "@types/eslint": "7.2.7", - "@types/mocha": "^9.0.0", - "@types/node": "^16.11.11", - "@types/prettier": "^2.2.2", "@types/sinon": "^10.0.6", "@types/uuid": "^10.0.0", - "@typescript-eslint/eslint-plugin": "^4.17.0", - "@typescript-eslint/parser": "^4.17.0", - "chai": "^4.3.4", - "chai-arrays": "^2.2.0", - "chai-as-promised": "^7.1.1", - "chai-like": "^1.1.1", - "chai-sorted": "^0.2.0", "concurrently": "^9.1.2", "conventional-changelog-conventionalcommits": "^8.0.0", "dotenv": "^8.2.0", "esbuild": "^0.25.0", - "eslint": "7.21.0", - "eslint-config-prettier": "^8.1.0", - "eslint-plugin-markdown": "^2.0.0", - "eslint-plugin-prettier": "^3.3.1", - "eslint-plugin-sonarjs": "^0.6.0", - "eslint-plugin-typescript-sort-keys": "1.5.0", - "husky": "^4.3.8", + "eslint": "^9.21.0", + "eslint-plugin-import": "^2.31.0", + "globals": "^16.0.0", + "husky": "^9.1.7", "lint-staged": "^15.2.2", - "mocha": "^11.1.0", "nyc": "^15.1.0", - "prettier": "^2.2.1", + "prettier": "^3.5.2", "semantic-release": "^24.2.3", "sinon": "^12.0.1", - "standard-version": "^9.3.2", - "ts-node": "^10.9.2", "tslib": "^2.8.1", "typescript": "^5.7.3", - "uuid": "^8.3.2" + "typescript-eslint": "^8.25.0", + "uuid": "^11.1.0", + "vitest": "^3.0.7" }, "scripts": { - "start": "tsc --watch", - "commitlinter": "commitlint", "build": "rm -rf dist && yarn bundle", "bundle": "concurrently 'tsc --declaration --emitDeclarationOnly --outDir ./dist/types' ./scripts/bundle.mjs", + "start": "tsc --watch", "types": "tsc --noEmit", - "prettier": "prettier --check '**/*.{js,ts,md,css,scss,json}' .eslintrc.json .prettierrc .babelrc", - "prettier-fix": "npx prettier --write '**/*.{js,ts,md,css,scss,json}' .eslintrc.json .prettierrc .babelrc", - "test-types": "node test/typescript/index.js && tsc --esModuleInterop true --noEmit true --strictNullChecks true --noImplicitAny true --strict true test/typescript/*.ts", - "eslint": "eslint '**/*.{js,md,ts}' --max-warnings 0 --ignore-path ./.eslintignore", - "eslint-fix": "npx eslint --fix '**/*.{js,md,ts}' --max-warnings 0 --ignore-path ./.eslintignore", - "test-unit": "NODE_ENV=test TS_NODE_PROJECT=tsconfig.test.json mocha test/unit/*.{js,test.ts}", - "test-coverage": "nyc yarn test-unit", - "test": "yarn test-unit", - "testwatch": "NODE_ENV=test nodemon ./node_modules/.bin/mocha --timeout 20000 --require test-entry.js test/test.js", "lint": "yarn run prettier && yarn run eslint", "lint-fix": "yarn run prettier-fix && yarn run eslint-fix", + "prettier": "prettier '**/*.{json,js,mjs,ts,yml,md}' --check", + "prettier-fix": "yarn run prettier --write", + "eslint": "eslint --max-warnings 0", + "eslint-fix": "yarn run eslint --fix", + "test": "yarn test-unit", + "testwatch": "NODE_ENV=test nodemon ./node_modules/.bin/mocha --timeout 20000 --require test-entry.js test/test.js", + "test-types": "node test/typescript/index.js && tsc --esModuleInterop true --noEmit true --strictNullChecks true --noImplicitAny true --strict true test/typescript/*.ts", + "test-unit": "vitest test/unit/* --run", + "test-coverage": "nyc yarn test-unit", "fix-staged": "lint-staged --config .lintstagedrc.fix.json --concurrent 1", "semantic-release": "semantic-release", - "prepack": "yarn run build" + "prepack": "yarn run build", + "prepare": "husky" }, "engines": { "node": ">=18" diff --git a/scripts/bundle.mjs b/scripts/bundle.mjs index f421f3fe1..6bb37fac0 100755 --- a/scripts/bundle.mjs +++ b/scripts/bundle.mjs @@ -2,7 +2,7 @@ import { resolve } from 'node:path'; import * as esbuild from 'esbuild'; -import packageJson from '../package.json' with {'type': 'json'}; +import packageJson from '../package.json' with { type: 'json' }; import getPackageVersion from './get-package-version.mjs'; // import.meta.dirname is not available before Node 20 diff --git a/scripts/get-package-version.mjs b/scripts/get-package-version.mjs index 8dc8e437e..339058fa0 100644 --- a/scripts/get-package-version.mjs +++ b/scripts/get-package-version.mjs @@ -12,7 +12,9 @@ export default function getPackageVersion() { version = execSync('git describe --tags --abbrev=0').toString().trim(); } catch (error) { console.error(error); - console.warn('Could not get latest version from git tags, falling back to package.json'); + console.warn( + 'Could not get latest version from git tags, falling back to package.json', + ); version = packageJson.version; } } diff --git a/src/base64.ts b/src/base64.ts index 040eb552d..472ba73ae 100644 --- a/src/base64.ts +++ b/src/base64.ts @@ -17,7 +17,10 @@ function isMapStringCallback( // source - https://github.com/beatgammit/base64-js/blob/master/test/convert.js#L72 function map(array: T[], callback: MapGenericCallback): U[]; function map(string: string, callback: MapStringCallback): U[]; -function map(arrayOrString: string | T[], callback: MapGenericCallback | MapStringCallback): U[] { +function map( + arrayOrString: string | T[], + callback: MapGenericCallback | MapStringCallback, +): U[] { const res = []; if (isString(arrayOrString) && isMapStringCallback(arrayOrString, callback)) { @@ -67,6 +70,7 @@ export const decodeBase64 = (s: string): string => { b = (b << 6) + c; l += 6; while (l >= 8) { + // eslint-disable-next-line @typescript-eslint/no-unused-expressions ((a = (b >>> (l -= 8)) & 0xff) || x < L - 2) && (r += w(a)); } } diff --git a/src/campaign.ts b/src/campaign.ts index 217bfb200..b9634c854 100644 --- a/src/campaign.ts +++ b/src/campaign.ts @@ -1,5 +1,5 @@ -import { StreamChat } from './client'; -import { CampaignData, GetCampaignOptions } from './types'; +import type { StreamChat } from './client'; +import type { CampaignData, GetCampaignOptions } from './types'; export class Campaign { id: string | null; @@ -47,7 +47,7 @@ export class Campaign { return await this.client.startCampaign(this.id as string, options); } - async update(data: Partial) { + update(data: Partial) { this.verifyCampaignId(); return this.client.updateCampaign(this.id as string, data); @@ -59,13 +59,13 @@ export class Campaign { return await this.client.deleteCampaign(this.id as string); } - async stop() { + stop() { this.verifyCampaignId(); return this.client.stopCampaign(this.id as string); } - async get(options?: GetCampaignOptions) { + get(options?: GetCampaignOptions) { this.verifyCampaignId(); return this.client.getCampaign(this.id as string, options); diff --git a/src/channel.ts b/src/channel.ts index d22d2b03e..c59e18bdc 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -1,9 +1,16 @@ import { ChannelState } from './channel_state'; -import { generateChannelTempCid, logChatPromiseExecution, messageSetPagination, normalizeQuerySort } from './utils'; -import { StreamChat } from './client'; +import { + generateChannelTempCid, + logChatPromiseExecution, + messageSetPagination, + normalizeQuerySort, +} from './utils'; +import type { StreamChat } from './client'; import { DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE } from './constants'; import type { + AIState, APIResponse, + AscDesc, BanUserOptions, ChannelAPIResponse, ChannelData, @@ -30,6 +37,7 @@ import type { MemberSort, Message, MessageFilters, + MessageOptions, MessagePaginationOptions, MessageResponse, MessageSetType, @@ -38,8 +46,12 @@ import type { PartialUpdateChannel, PartialUpdateChannelAPIResponse, PartialUpdateMember, + PartialUpdateMemberAPIResponse, PinnedMessagePaginationOptions, PinnedMessagesSort, + PollVoteData, + PushPreference, + QueryChannelAPIResponse, QueryMembersOptions, Reaction, ReactionAPIResponse, @@ -48,19 +60,12 @@ import type { SearchOptions, SearchPayload, SendMessageAPIResponse, + SendMessageOptions, TruncateChannelAPIResponse, TruncateOptions, UpdateChannelAPIResponse, - UserResponse, - QueryChannelAPIResponse, - PollVoteData, - SendMessageOptions, - AscDesc, - PartialUpdateMemberAPIResponse, - AIState, - MessageOptions, - PushPreference, UpdateChannelOptions, + UserResponse, } from './types'; import type { Role } from './permissions'; import type { CustomChannelData } from './custom_types'; @@ -109,7 +114,12 @@ export class Channel { * * @return {Channel} Returns a new uninitialized channel */ - constructor(client: StreamChat, type: string, id: string | undefined, data: ChannelData) { + constructor( + client: StreamChat, + type: string, + id: string | undefined, + data: ChannelData, + ) { const validTypeRe = /^[\w_-]+$/; const validIDRe = /^[\w!_-]+$/; @@ -174,10 +184,13 @@ export class Channel { * @return {Promise} The Server Response */ async sendMessage(message: Message, options?: SendMessageOptions) { - return await this.getClient().post(this._channelURL() + '/message', { - message, - ...options, - }); + return await this.getClient().post( + this._channelURL() + '/message', + { + message, + ...options, + }, + ); } sendFile( @@ -186,11 +199,28 @@ export class Channel { contentType?: string, user?: UserResponse, ) { - return this.getClient().sendFile(`${this._channelURL()}/file`, uri, name, contentType, user); + return this.getClient().sendFile( + `${this._channelURL()}/file`, + uri, + name, + contentType, + user, + ); } - sendImage(uri: string | NodeJS.ReadableStream | File, name?: string, contentType?: string, user?: UserResponse) { - return this.getClient().sendFile(`${this._channelURL()}/image`, uri, name, contentType, user); + sendImage( + uri: string | NodeJS.ReadableStream | File, + name?: string, + contentType?: string, + user?: UserResponse, + ) { + return this.getClient().sendFile( + `${this._channelURL()}/image`, + uri, + name, + contentType, + user, + ); } deleteFile(url: string) { @@ -240,7 +270,9 @@ export class Channel { const payload: SearchPayload = { filter_conditions: { cid: this.cid } as ChannelFilters, ...options, - sort: options.sort ? normalizeQuerySort(options.sort) : undefined, + sort: options.sort + ? normalizeQuerySort(options.sort) + : undefined, }; if (typeof query === 'string') { payload.query = query; @@ -252,9 +284,12 @@ export class Channel { // Make sure we wait for the connect promise if there is a pending one await this.getClient().wsPromise; - return await this.getClient().get(this.getClient().baseURL + '/search', { - payload, - }); + return await this.getClient().get( + this.getClient().baseURL + '/search', + { + payload, + }, + ); } /** @@ -267,7 +302,11 @@ export class Channel { * * @return {Promise} Query Members response */ - async queryMembers(filterConditions: MemberFilters, sort: MemberSort = [], options: QueryMembersOptions = {}) { + async queryMembers( + filterConditions: MemberFilters, + sort: MemberSort = [], + options: QueryMembersOptions = {}, + ) { let id: string | undefined; const type = this.type; let members: string[] | ChannelMemberResponse[] | undefined; @@ -277,16 +316,19 @@ export class Channel { members = this.data.members; } // Return a list of members - return await this.getClient().get(this.getClient().baseURL + '/members', { - payload: { - type, - id, - members, - sort: normalizeQuerySort(sort), - filter_conditions: filterConditions, - ...options, + return await this.getClient().get( + this.getClient().baseURL + '/members', + { + payload: { + type, + id, + members, + sort: normalizeQuerySort(sort), + filter_conditions: filterConditions, + ...options, + }, }, - }); + ); } /** @@ -349,7 +391,9 @@ export class Channel { deleteReaction(messageID: string, reactionType: string, user_id?: string) { this._checkInitialized(); if (!reactionType || !messageID) { - throw Error('Deleting a reaction requires specifying both the message and reaction type'); + throw Error( + 'Deleting a reaction requires specifying both the message and reaction type', + ); } const url = @@ -378,7 +422,10 @@ export class Channel { ) { // Strip out reserved names that will result in API errors. // TODO: this needs to be typed better - const reserved: Exclude[] = [ + const reserved: Exclude< + keyof (ChannelResponse & ChannelData), + keyof CustomChannelData + >[] = [ 'config', 'cid', 'created_by', @@ -410,11 +457,20 @@ export class Channel { * @return {Promise} */ async updatePartial(update: PartialUpdateChannel) { - const data = await this.getClient().patch(this._channelURL(), update); + const data = await this.getClient().patch( + this._channelURL(), + update, + ); const areCapabilitiesChanged = [...(data.channel.own_capabilities || [])].sort().join() !== - [...(Array.isArray(this.data?.own_capabilities) ? (this.data?.own_capabilities as string[]) : [])].sort().join(); + [ + ...(Array.isArray(this.data?.own_capabilities) + ? (this.data?.own_capabilities as string[]) + : []), + ] + .sort() + .join(); this.data = data.channel; // If the capabiltities are changed, we trigger the `capabilities.changed` event. if (areCapabilitiesChanged) { @@ -434,9 +490,12 @@ export class Channel { * @return {Promise} The server response */ async enableSlowMode(coolDownInterval: number) { - const data = await this.getClient().post(this._channelURL(), { - cooldown: coolDownInterval, - }); + const data = await this.getClient().post( + this._channelURL(), + { + cooldown: coolDownInterval, + }, + ); this.data = data.channel; return data; } @@ -447,9 +506,12 @@ export class Channel { * @return {Promise} The server response */ async disableSlowMode() { - const data = await this.getClient().post(this._channelURL(), { - cooldown: 0, - }); + const data = await this.getClient().post( + this._channelURL(), + { + cooldown: 0, + }, + ); this.data = data.channel; return data; } @@ -473,7 +535,10 @@ export class Channel { * @return {Promise} The server response */ async truncate(options: TruncateOptions = {}) { - return await this.getClient().post(this._channelURL() + '/truncate', options); + return await this.getClient().post( + this._channelURL() + '/truncate', + options, + ); } /** @@ -506,7 +571,11 @@ export class Channel { * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating * @return {Promise} The server response */ - async addMembers(members: string[] | Array, message?: Message, options: ChannelUpdateOptions = {}) { + async addMembers( + members: string[] | Array, + message?: Message, + options: ChannelUpdateOptions = {}, + ) { return await this._update({ add_members: members, message, ...options }); } @@ -518,7 +587,11 @@ export class Channel { * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating * @return {Promise} The server response */ - async addModerators(members: string[], message?: Message, options: ChannelUpdateOptions = {}) { + async addModerators( + members: string[], + message?: Message, + options: ChannelUpdateOptions = {}, + ) { return await this._update({ add_moderators: members, message, ...options }); } @@ -562,7 +635,11 @@ export class Channel { * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating * @return {Promise} The server response */ - async removeMembers(members: string[], message?: Message, options: ChannelUpdateOptions = {}) { + async removeMembers( + members: string[], + message?: Message, + options: ChannelUpdateOptions = {}, + ) { return await this._update({ remove_members: members, message, ...options }); } @@ -574,7 +651,11 @@ export class Channel { * @param {ChannelUpdateOptions} [options] Option object, configuration to control the behavior while updating * @return {Promise} The server response */ - async demoteModerators(members: string[], message?: Message, options: ChannelUpdateOptions = {}) { + async demoteModerators( + members: string[], + message?: Message, + options: ChannelUpdateOptions = {}, + ) { return await this._update({ demote_moderators: members, message, ...options }); } @@ -584,8 +665,11 @@ export class Channel { * @return {Promise} The server response * TODO: introduce new type instead of Object in the next major update */ - async _update(payload: Object) { - const data = await this.getClient().post(this._channelURL(), payload); + async _update(payload: object) { + const data = await this.getClient().post( + this._channelURL(), + payload, + ); this.data = data.channel; return data; } @@ -603,10 +687,13 @@ export class Channel { * */ async mute(opts: { expiration?: number; user_id?: string } = {}) { - return await this.getClient().post(this.getClient().baseURL + '/moderation/mute/channel', { - channel_cid: this.cid, - ...opts, - }); + return await this.getClient().post( + this.getClient().baseURL + '/moderation/mute/channel', + { + channel_cid: this.cid, + ...opts, + }, + ); } /** @@ -618,10 +705,13 @@ export class Channel { * await channel.unmute({user_id: userId}); */ async unmute(opts: { user_id?: string } = {}) { - return await this.getClient().post(this.getClient().baseURL + '/moderation/unmute/channel', { - channel_cid: this.cid, - ...opts, - }); + return await this.getClient().post( + this.getClient().baseURL + '/moderation/unmute/channel', + { + channel_cid: this.cid, + ...opts, + }, + ); } /** @@ -774,7 +864,11 @@ export class Channel { * @param state - The new state of the AI process (e.g., thinking, generating). * @param options - Optional parameters, such as `ai_message`, to include additional details in the event. */ - async updateAIState(messageId: string, state: AIState, options: { ai_message?: string } = {}) { + async updateAIState( + messageId: string, + state: AIState, + options: { ai_message?: string } = {}, + ) { await this.sendEvent({ ...options, type: 'ai_indicator.update', @@ -926,10 +1020,14 @@ export class Channel { this.initialized = true; this.data = state.channel; - this._client.logger('info', `channel:watch() - started watching channel ${this.cid}`, { - tags: ['channel'], - channel: this, - }); + this._client.logger( + 'info', + `channel:watch() - started watching channel ${this.cid}`, + { + tags: ['channel'], + channel: this, + }, + ); return state; } @@ -939,12 +1037,19 @@ export class Channel { * @return {Promise} The server response */ async stopWatching() { - const response = await this.getClient().post(this._channelURL() + '/stop-watching', {}); + const response = await this.getClient().post( + this._channelURL() + '/stop-watching', + {}, + ); - this._client.logger('info', `channel:watch() - stopped watching channel ${this.cid}`, { - tags: ['channel'], - channel: this, - }); + this._client.logger( + 'info', + `channel:watch() - stopped watching channel ${this.cid}`, + { + tags: ['channel'], + channel: this, + }, + ); return response; } @@ -993,12 +1098,15 @@ export class Channel { options: PinnedMessagePaginationOptions & { user?: UserResponse; user_id?: string }, sort: PinnedMessagesSort = [], ) { - return await this.getClient().get(this._channelURL() + '/pinned_messages', { - payload: { - ...options, - sort: normalizeQuerySort(sort), + return await this.getClient().get( + this._channelURL() + '/pinned_messages', + { + payload: { + ...options, + sort: normalizeQuerySort(sort), + }, }, - }); + ); } /** @@ -1026,9 +1134,12 @@ export class Channel { * @return {Promise} Server response */ getMessagesById(messageIds: string[]) { - return this.getClient().get(this._channelURL() + '/messages', { - ids: messageIds.join(','), - }); + return this.getClient().get( + this._channelURL() + '/messages', + { + ids: messageIds.join(','), + }, + ); } /** @@ -1047,10 +1158,14 @@ export class Channel { if (message.silent) return false; if (message.parent_id && !message.show_in_channel) return false; if (message.user?.id === this.getClient().userID) return false; - if (message.user?.id && this.getClient().userMuteStatus(message.user.id)) return false; + if (message.user?.id && this.getClient().userMuteStatus(message.user.id)) + return false; // Return false if channel doesn't allow read events. - if (Array.isArray(this.data?.own_capabilities) && !this.data?.own_capabilities.includes('read-events')) { + if ( + Array.isArray(this.data?.own_capabilities) && + !this.data?.own_capabilities.includes('read-events') + ) { return false; } @@ -1127,12 +1242,18 @@ export class Channel { * * @return {Promise} Returns a query response */ - async query(options: ChannelQueryOptions = {}, messageSetToAddToIfDoesNotExist: MessageSetType = 'current') { + async query( + options: ChannelQueryOptions = {}, + messageSetToAddToIfDoesNotExist: MessageSetType = 'current', + ) { // Make sure we wait for the connect promise if there is a pending one await this.getClient().wsPromise; const createdById = - options.created_by?.id ?? options.created_by_id ?? this._data?.created_by?.id ?? this._data?.created_by_id; + options.created_by?.id ?? + options.created_by_id ?? + this._data?.created_by?.id ?? + this._data?.created_by_id; if (this.getClient()._isUsingServerAuth() && typeof createdById !== 'string') { this.getClient().logger( @@ -1146,11 +1267,14 @@ export class Channel { queryURL += `/${encodeURIComponent(this.id)}`; } - const state = await this.getClient().post(queryURL + '/query', { - data: this._data, - state: true, - ...options, - }); + const state = await this.getClient().post( + queryURL + '/query', + { + data: this._data, + state: true, + ...options, + }, + ); // update the channel id if it was missing if (!this.id) { @@ -1169,7 +1293,10 @@ export class Channel { delete this.getClient().activeChannels[tempChannelCid]; } - if (!(this.cid in this.getClient().activeChannels) && this.getClient()._cacheEnabled()) { + if ( + !(this.cid in this.getClient().activeChannels) && + this.getClient()._cacheEnabled() + ) { this.getClient().activeChannels[this.cid] = this; } } @@ -1183,7 +1310,8 @@ export class Channel { ...messageSetPagination({ parentSet: messageSet, messagePaginationOptions: options?.messages, - requestedPageSize: options?.messages?.limit ?? DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE, + requestedPageSize: + options?.messages?.limit ?? DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE, returnedPage: state.messages, logger: this.getClient().logger, }), @@ -1193,7 +1321,13 @@ export class Channel { const areCapabilitiesChanged = [...(state.channel.own_capabilities || [])].sort().join() !== - [...(this.data && Array.isArray(this.data?.own_capabilities) ? this.data.own_capabilities : [])].sort().join(); + [ + ...(this.data && Array.isArray(this.data?.own_capabilities) + ? this.data.own_capabilities + : []), + ] + .sort() + .join(); this.data = state.channel; this.offlineMode = false; @@ -1313,7 +1447,10 @@ export class Channel { * @returns {Promise} */ async createCall(options: CreateCallOptions) { - return await this.getClient().post(this._channelURL() + '/call', options); + return await this.getClient().post( + this._channelURL() + '/call', + options, + ); } /** @@ -1342,25 +1479,36 @@ export class Channel { */ on(eventType: EventTypes, callback: EventHandler): { unsubscribe: () => void }; on(callback: EventHandler): { unsubscribe: () => void }; - on(callbackOrString: EventHandler | EventTypes, callbackOrNothing?: EventHandler): { unsubscribe: () => void } { + on( + callbackOrString: EventHandler | EventTypes, + callbackOrNothing?: EventHandler, + ): { unsubscribe: () => void } { const key = callbackOrNothing ? (callbackOrString as string) : 'all'; const callback = callbackOrNothing ? callbackOrNothing : callbackOrString; if (!(key in this.listeners)) { this.listeners[key] = []; } - this._client.logger('info', `Attaching listener for ${key} event on channel ${this.cid}`, { - tags: ['event', 'channel'], - channel: this, - }); + this._client.logger( + 'info', + `Attaching listener for ${key} event on channel ${this.cid}`, + { + tags: ['event', 'channel'], + channel: this, + }, + ); this.listeners[key].push(callback); return { unsubscribe: () => { - this._client.logger('info', `Removing listener for ${key} event from channel ${this.cid}`, { - tags: ['event', 'channel'], - channel: this, - }); + this._client.logger( + 'info', + `Removing listener for ${key} event from channel ${this.cid}`, + { + tags: ['event', 'channel'], + channel: this, + }, + ); this.listeners[key] = this.listeners[key].filter((el) => el !== callback); }, @@ -1373,22 +1521,29 @@ export class Channel { */ off(eventType: EventTypes, callback: EventHandler): void; off(callback: EventHandler): void; - off(callbackOrString: EventHandler | EventTypes, callbackOrNothing?: EventHandler): void { + off( + callbackOrString: EventHandler | EventTypes, + callbackOrNothing?: EventHandler, + ): void { const key = callbackOrNothing ? (callbackOrString as string) : 'all'; const callback = callbackOrNothing ? callbackOrNothing : callbackOrString; if (!(key in this.listeners)) { this.listeners[key] = []; } - this._client.logger('info', `Removing listener for ${key} event from channel ${this.cid}`, { - tags: ['event', 'channel'], - channel: this, - }); + this._client.logger( + 'info', + `Removing listener for ${key} event from channel ${this.cid}`, + { + tags: ['event', 'channel'], + channel: this, + }, + ); this.listeners[key] = this.listeners[key].filter((value) => value !== callback); } - // eslint-disable-next-line sonarjs/cognitive-complexity _handleChannelEvent(event: Event) { + // eslint-disable-next-line @typescript-eslint/no-this-alias const channel = this; this._client.logger( 'info', @@ -1453,7 +1608,8 @@ export class Channel { if (event.message) { /* if message belongs to current user, always assume timestamp is changed to filter it out and add again to avoid duplication */ const ownMessage = event.user?.id === this.getClient().user?.id; - const isThreadMessage = event.message.parent_id && !event.message.show_in_channel; + const isThreadMessage = + event.message.parent_id && !event.message.show_in_channel; if (this.state.isUpToDate || isThreadMessage) { channelState.addMessageSorted(event.message, ownMessage); @@ -1506,12 +1662,14 @@ export class Channel { channelState.messageSets.forEach((messageSet, messageSetIndex) => { messageSet.messages.forEach(({ created_at: createdAt, id }) => { - if (truncatedAt > +createdAt) channelState.removeMessage({ id, messageSetIndex }); + if (truncatedAt > +createdAt) + channelState.removeMessage({ id, messageSetIndex }); }); }); channelState.pinnedMessages.forEach(({ id, created_at: createdAt }) => { - if (truncatedAt > +createdAt) channelState.removePinnedMessage({ id } as MessageResponse); + if (truncatedAt > +createdAt) + channelState.removePinnedMessage({ id } as MessageResponse); }); } else { channelState.clearMessages(); @@ -1575,14 +1733,17 @@ export class Channel { } case 'channel.updated': if (event.channel) { - const isFrozenChanged = event.channel?.frozen !== undefined && event.channel.frozen !== channel.data?.frozen; + const isFrozenChanged = + event.channel?.frozen !== undefined && + event.channel.frozen !== channel.data?.frozen; if (isFrozenChanged) { this.query({ state: false, messages: { limit: 0 }, watchers: { limit: 0 } }); } channel.data = { ...event.channel, hidden: event.channel?.hidden ?? channel.data?.hidden, - own_capabilities: event.channel?.own_capabilities ?? channel.data?.own_capabilities, + own_capabilities: + event.channel?.own_capabilities ?? channel.data?.own_capabilities, }; } break; @@ -1639,6 +1800,7 @@ export class Channel { } _callChannelListeners = (event: Event) => { + // eslint-disable-next-line @typescript-eslint/no-this-alias const channel = this; // gather and call the listeners const listeners = []; @@ -1670,15 +1832,21 @@ export class Channel { }; _checkInitialized() { - if (!this.initialized && !this.offlineMode && !this.getClient()._isUsingServerAuth()) { + if ( + !this.initialized && + !this.offlineMode && + !this.getClient()._isUsingServerAuth() + ) { throw Error( `Channel ${this.cid} hasn't been initialized yet. Make sure to call .watch() and wait for it to resolve`, ); } } - // eslint-disable-next-line sonarjs/cognitive-complexity - _initializeState(state: ChannelAPIResponse, messageSetToAddToIfDoesNotExist: MessageSetType = 'latest') { + _initializeState( + state: ChannelAPIResponse, + messageSetToAddToIfDoesNotExist: MessageSetType = 'latest', + ) { const { state: clientState, user, userID } = this.getClient(); // add the members and users @@ -1698,7 +1866,13 @@ export class Channel { if (!this.state.messages) { this.state.initMessages(); } - const { messageSet } = this.state.addMessagesSorted(messages, false, true, true, messageSetToAddToIfDoesNotExist); + const { messageSet } = this.state.addMessagesSorted( + messages, + false, + true, + true, + messageSetToAddToIfDoesNotExist, + ); if (!this.state.pinnedMessages) { this.state.pinnedMessages = []; @@ -1778,12 +1952,15 @@ export class Channel { */ overrideCurrentState?: boolean; }) { - const newMembersById = members.reduce((membersById, member) => { - if (member.user) { - membersById[member.user.id] = member; - } - return membersById; - }, {}); + const newMembersById = members.reduce( + (membersById, member) => { + if (member.user) { + membersById[member.user.id] = member; + } + return membersById; + }, + {}, + ); if (overrideCurrentState) { this.state.members = newMembersById; @@ -1796,10 +1973,14 @@ export class Channel { } _disconnect() { - this._client.logger('info', `channel:disconnect() - Disconnecting the channel ${this.cid}`, { - tags: ['connection', 'channel'], - channel: this, - }); + this._client.logger( + 'info', + `channel:disconnect() - Disconnecting the channel ${this.cid}`, + { + tags: ['connection', 'channel'], + channel: this, + }, + ); this.disconnected = true; this.state.setIsUpToDate(false); diff --git a/src/channel_manager.ts b/src/channel_manager.ts index b02c801e9..0d5f0bcaf 100644 --- a/src/channel_manager.ts +++ b/src/channel_manager.ts @@ -1,7 +1,14 @@ import type { StreamChat } from './client'; -import type { Event, ChannelOptions, ChannelStateOptions, ChannelFilters, ChannelSort } from './types'; -import { StateStore, ValueOrPatch, isPatch } from './store'; -import { Channel } from './channel'; +import type { + ChannelFilters, + ChannelOptions, + ChannelSort, + ChannelStateOptions, + Event, +} from './types'; +import type { ValueOrPatch } from './store'; +import { isPatch, StateStore } from './store'; +import type { Channel } from './channel'; import { extractSortValue, findLastPinnedChannelIndex, @@ -42,7 +49,9 @@ export type GenericEventHandlerType = ( ...args: T ) => void | (() => void) | ((...args: T) => Promise) | Promise; export type EventHandlerType = GenericEventHandlerType<[Event]>; -export type EventHandlerOverrideType = GenericEventHandlerType<[ChannelSetterType, Event]>; +export type EventHandlerOverrideType = GenericEventHandlerType< + [ChannelSetterType, Event] +>; export type ChannelManagerEventTypes = | 'notification.added_to_channel' @@ -183,7 +192,9 @@ export class ChannelManager { public setChannels = (valueOrFactory: ChannelSetterParameterType) => { this.state.next((current) => { const { channels: currentChannels } = current; - const newChannels = isPatch(valueOrFactory) ? valueOrFactory(currentChannels) : valueOrFactory; + const newChannels = isPatch(valueOrFactory) + ? valueOrFactory(currentChannels) + : valueOrFactory; // If the references between the two values are the same, just return the // current state; otherwise trigger a state change. @@ -194,7 +205,9 @@ export class ChannelManager { }); }; - public setEventHandlerOverrides = (eventHandlerOverrides: ChannelManagerEventHandlerOverrides = {}) => { + public setEventHandlerOverrides = ( + eventHandlerOverrides: ChannelManagerEventHandlerOverrides = {}, + ) => { const truthyEventHandlerOverrides = Object.entries(eventHandlerOverrides).reduce< Partial >((acc, [key, value]) => { @@ -203,7 +216,9 @@ export class ChannelManager { } return acc; }, {}); - this.eventHandlerOverrides = new Map(Object.entries(truthyEventHandlerOverrides)); + this.eventHandlerOverrides = new Map( + Object.entries(truthyEventHandlerOverrides), + ); }; public setOptions = (options: ChannelManagerOptions = {}) => { @@ -216,7 +231,10 @@ export class ChannelManager { options: ChannelOptions = {}, stateOptions: ChannelStateOptions = {}, ) => { - const { offset, limit } = { ...DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS, ...options }; + const { offset, limit } = { + ...DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS, + ...options, + }; const { pagination: { isLoading }, } = this.state.getLatestValue(); @@ -239,7 +257,12 @@ export class ChannelManager { }, })); - const channels = await this.client.queryChannels(filters, sort, options, stateOptions); + const channels = await this.client.queryChannels( + filters, + sort, + options, + stateOptions, + ); const newOffset = offset + (channels?.length ?? 0); const newOptions = { ...options, offset: newOffset }; const { pagination } = this.state.getLatestValue(); @@ -273,11 +296,19 @@ export class ChannelManager { } try { - const { offset, limit } = { ...DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS, ...options }; + const { offset, limit } = { + ...DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS, + ...options, + }; this.state.partialNext({ pagination: { ...pagination, isLoading: false, isLoadingNext: true }, }); - const nextChannels = await this.client.queryChannels(filters, sort, options, this.stateOptions); + const nextChannels = await this.client.queryChannels( + filters, + sort, + options, + this.stateOptions, + ); const { channels } = this.state.getLatestValue(); const newOffset = offset + (nextChannels?.length ?? 0); const newOptions = { ...options, offset: newOffset }; @@ -305,7 +336,12 @@ export class ChannelManager { private notificationAddedToChannelHandler = async (event: Event) => { const { id, type, members } = event?.channel ?? {}; - if (!type || !this.options.allowNotLoadedChannelPromotionForEvent?.['notification.added_to_channel']) { + if ( + !type || + !this.options.allowNotLoadedChannelPromotionForEvent?.[ + 'notification.added_to_channel' + ] + ) { return; } @@ -345,7 +381,9 @@ export class ChannelManager { } const newChannels = [...channels]; - const channelIndex = newChannels.findIndex((channel) => channel.cid === (event.cid || event.channel?.cid)); + const channelIndex = newChannels.findIndex( + (channel) => channel.cid === (event.cid || event.channel?.cid), + ); if (channelIndex < 0) { return; @@ -391,7 +429,8 @@ export class ChannelManager { // list order is locked this.options.lockChannelOrder || // target channel is not within the loaded list and loading from cache is disallowed - (!targetChannelExistsWithinList && !this.options.allowNotLoadedChannelPromotionForEvent?.['message.new']) + (!targetChannelExistsWithinList && + !this.options.allowNotLoadedChannelPromotionForEvent?.['message.new']) ) { return; } @@ -500,7 +539,11 @@ export class ChannelManager { const considerArchivedChannels = shouldConsiderArchivedChannels(filters); const pinnedAtSort = extractSortValue({ atIndex: 0, sort, targetKey: 'pinned_at' }); - if (!channels || (!considerPinnedChannels && !considerArchivedChannels) || this.options.lockChannelOrder) { + if ( + !channels || + (!considerPinnedChannels && !considerArchivedChannels) || + this.options.lockChannelOrder + ) { return; } @@ -535,7 +578,8 @@ export class ChannelManager { if (pinnedAtSort === 1 || (pinnedAtSort === -1 && !isTargetChannelPinned)) { lastPinnedChannelIndex = findLastPinnedChannelIndex({ channels: newChannels }); } - const newTargetChannelIndex = typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0; + const newTargetChannelIndex = + typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0; // skip state update if the position of the channel does not change if (channels[newTargetChannelIndex] === targetChannel) { @@ -547,7 +591,8 @@ export class ChannelManager { }; private subscriptionOrOverride = (event: Event) => { - const handlerName = channelManagerEventToHandlerMapping[event.type as ChannelManagerEventTypes]; + const handlerName = + channelManagerEventToHandlerMapping[event.type as ChannelManagerEventTypes]; const defaultEventHandler = this.eventHandlers.get(handlerName); const eventHandlerOverride = this.eventHandlerOverrides.get(handlerName); if (eventHandlerOverride && typeof eventHandlerOverride === 'function') { @@ -567,7 +612,9 @@ export class ChannelManager { } for (const eventType of Object.keys(channelManagerEventToHandlerMapping)) { - this.unsubscribeFunctions.add(this.client.on(eventType, this.subscriptionOrOverride).unsubscribe); + this.unsubscribeFunctions.add( + this.client.on(eventType, this.subscriptionOrOverride).unsubscribe, + ); } }; diff --git a/src/channel_state.ts b/src/channel_state.ts index 938254a5b..06c102739 100644 --- a/src/channel_state.ts +++ b/src/channel_state.ts @@ -1,5 +1,5 @@ -import { Channel } from './channel'; -import { +import type { Channel } from './channel'; +import type { ChannelMemberResponse, Event, FormatMessageResponse, @@ -78,7 +78,10 @@ export class ChannelState { * be pushed on to message list. */ this.isUpToDate = true; - this.last_message_at = channel?.state?.last_message_at != null ? new Date(channel.state.last_message_at) : null; + this.last_message_at = + channel?.state?.last_message_at != null + ? new Date(channel.state.last_message_at) + : null; } get messages() { @@ -104,7 +107,10 @@ export class ChannelState { } get messagePagination() { - return this.messageSets.find((s) => s.isCurrent)?.pagination || DEFAULT_MESSAGE_SET_PAGINATION; + return ( + this.messageSets.find((s) => s.isCurrent)?.pagination || + DEFAULT_MESSAGE_SET_PAGINATION + ); } /** @@ -182,7 +188,9 @@ export class ChannelState { * handle updates to user, we can use the reference map, to determine which * channels need to be updated with updated user object. */ - this._channel.getClient().state.updateUserReference(message.user, this._channel.cid); + this._channel + .getClient() + .state.updateUserReference(message.user, this._channel.cid); } if (initializing && message.id && this.threads[message.id]) { @@ -280,11 +288,19 @@ export class ChannelState { this.pinnedMessages = result; } - addReaction(reaction: ReactionResponse, message?: MessageResponse, enforce_unique?: boolean) { + addReaction( + reaction: ReactionResponse, + message?: MessageResponse, + enforce_unique?: boolean, + ) { if (!message) return; const messageWithReaction = message; this._updateMessage(message, (msg) => { - messageWithReaction.own_reactions = this._addOwnReactionToMessage(msg.own_reactions, reaction, enforce_unique); + messageWithReaction.own_reactions = this._addOwnReactionToMessage( + msg.own_reactions, + reaction, + enforce_unique, + ); return this.formatMessage(messageWithReaction); }); return messageWithReaction; @@ -309,9 +325,14 @@ export class ChannelState { return ownReactions; } - _removeOwnReactionFromMessage(ownReactions: ReactionResponse[] | null | undefined, reaction: ReactionResponse) { + _removeOwnReactionFromMessage( + ownReactions: ReactionResponse[] | null | undefined, + reaction: ReactionResponse, + ) { if (ownReactions) { - return ownReactions.filter((item) => item.user_id !== reaction.user_id || item.type !== reaction.type); + return ownReactions.filter( + (item) => item.user_id !== reaction.user_id || item.type !== reaction.type, + ); } return ownReactions; } @@ -320,25 +341,37 @@ export class ChannelState { if (!message) return; const messageWithReaction = message; this._updateMessage(message, (msg) => { - messageWithReaction.own_reactions = this._removeOwnReactionFromMessage(msg.own_reactions, reaction); + messageWithReaction.own_reactions = this._removeOwnReactionFromMessage( + msg.own_reactions, + reaction, + ); return this.formatMessage(messageWithReaction); }); return messageWithReaction; } - _updateQuotedMessageReferences({ message, remove }: { message: MessageResponse; remove?: boolean }) { + _updateQuotedMessageReferences({ + message, + remove, + }: { + message: MessageResponse; + remove?: boolean; + }) { const parseMessage = (m: ReturnType) => - (({ + ({ ...m, created_at: m.created_at.toISOString(), pinned_at: m.pinned_at?.toISOString(), updated_at: m.updated_at?.toISOString(), - } as unknown) as MessageResponse); + }) as unknown as MessageResponse; const update = (messages: FormatMessageResponse[]) => { const updatedMessages = messages.reduce((acc, msg) => { if (msg.quoted_message_id === message.id) { - acc.push({ ...parseMessage(msg), quoted_message: remove ? { ...message, attachments: [] } : message }); + acc.push({ + ...parseMessage(msg), + quoted_message: remove ? { ...message, attachments: [] } : message, + }); } return acc; }, []); @@ -369,7 +402,9 @@ export class ChannelState { pinned?: boolean; show_in_channel?: boolean; }, - updateFunc: (msg: ReturnType) => ReturnType, + updateFunc: ( + msg: ReturnType, + ) => ReturnType, ) { const { parent_id, show_in_channel, pinned } = message; @@ -385,7 +420,9 @@ export class ChannelState { if ((!show_in_channel && !parent_id) || show_in_channel) { const messageSetIndex = this.findMessageSetIndex(message); if (messageSetIndex !== -1) { - const msgIndex = this.messageSets[messageSetIndex].messages.findIndex((msg) => msg.id === message.id); + const msgIndex = this.messageSets[messageSetIndex].messages.findIndex( + (msg) => msg.id === message.id, + ); if (msgIndex !== -1) { this.messageSets[messageSetIndex].messages[msgIndex] = updateFunc( this.messageSets[messageSetIndex].messages[msgIndex], @@ -430,7 +467,13 @@ export class ChannelState { sortBy: 'pinned_at' | 'created_at' = 'created_at', addIfDoesNotExist = true, ) { - return addToMessageList(messages, message, timestampChanged, sortBy, addIfDoesNotExist); + return addToMessageList( + messages, + message, + timestampChanged, + sortBy, + addIfDoesNotExist, + ); } /** @@ -440,7 +483,11 @@ export class ChannelState { * * @return {boolean} Returns if the message was removed */ - removeMessage(messageToRemove: { id: string; messageSetIndex?: number; parent_id?: string }) { + removeMessage(messageToRemove: { + id: string; + messageSetIndex?: number; + parent_id?: string; + }) { let isRemoved = false; if (messageToRemove.parent_id && this.threads[messageToRemove.parent_id]) { const { removed, result: threadMessages } = this.removeMessageFromArray( @@ -451,7 +498,8 @@ export class ChannelState { this.threads[messageToRemove.parent_id] = threadMessages; isRemoved = removed; } else { - const messageSetIndex = messageToRemove.messageSetIndex ?? this.findMessageSetIndex(messageToRemove); + const messageSetIndex = + messageToRemove.messageSetIndex ?? this.findMessageSetIndex(messageToRemove); if (messageSetIndex !== -1) { const { removed, result: messages } = this.removeMessageFromArray( this.messageSets[messageSetIndex].messages, @@ -469,7 +517,9 @@ export class ChannelState { msgArray: Array>, msg: { id: string; parent_id?: string }, ) => { - const result = msgArray.filter((message) => !(!!message.id && !!msg.id && message.id === msg.id)); + const result = msgArray.filter( + (message) => !(!!message.id && !!msg.id && message.id === msg.id), + ); return { removed: result.length < msgArray.length, result }; }; @@ -480,7 +530,10 @@ export class ChannelState { * @param {UserResponse} user */ updateUserMessages = (user: UserResponse) => { - const _updateUserMessages = (messages: Array>, user: UserResponse) => { + const _updateUserMessages = ( + messages: Array>, + user: UserResponse, + ) => { for (let i = 0; i < messages.length; i++) { const m = messages[i]; if (m.user?.id === user.id) { @@ -521,7 +574,7 @@ export class ChannelState { * In case of hard delete, we need to strip down all text, html, * attachments and all the custom properties on message */ - messages[i] = ({ + messages[i] = { cid: m.cid, created_at: m.created_at, deleted_at: user.deleted_at, @@ -536,7 +589,7 @@ export class ChannelState { type: 'deleted', updated_at: m.updated_at, user: m.user, - } as unknown) as ReturnType; + } as unknown as ReturnType; } else { messages[i] = { ...m, @@ -547,7 +600,9 @@ export class ChannelState { } }; - this.messageSets.forEach((set) => _deleteUserMessages(set.messages, user, hardDelete)); + this.messageSets.forEach((set) => + _deleteUserMessages(set.messages, user, hardDelete), + ); for (const parentId in this.threads) { _deleteUserMessages(this.threads[parentId], user, hardDelete); @@ -561,7 +616,9 @@ export class ChannelState { * */ filterErrorMessages() { - const filteredMessages = this.latestMessages.filter((message) => message.type !== 'error'); + const filteredMessages = this.latestMessages.filter( + (message) => message.type !== 'error', + ); this.latestMessages = filteredMessages; } @@ -594,7 +651,14 @@ export class ChannelState { } initMessages() { - this.messageSets = [{ messages: [], isLatest: true, isCurrent: true, pagination: DEFAULT_MESSAGE_SET_PAGINATION }]; + this.messageSets = [ + { + messages: [], + isLatest: true, + isCurrent: true, + pagination: DEFAULT_MESSAGE_SET_PAGINATION, + }, + ]; } /** @@ -604,7 +668,11 @@ export class ChannelState { * @param {string} parentMessageId The id of the parent message, if we want load a thread reply * @param {number} limit The page size if the message has to be queried from the server */ - async loadMessageIntoState(messageId: string | 'latest', parentMessageId?: string, limit = 25) { + async loadMessageIntoState( + messageId: string | 'latest', + parentMessageId?: string, + limit = 25, + ) { let messageSetIndex: number; let switchedToMessageSet = false; let loadedMessageThread = false; @@ -621,12 +689,17 @@ export class ChannelState { this.switchToMessageSet(messageSetIndex); switchedToMessageSet = true; } - loadedMessageThread = !parentMessageId || !!this.threads[parentMessageId]?.find((m) => m.id === messageId); + loadedMessageThread = + !parentMessageId || + !!this.threads[parentMessageId]?.find((m) => m.id === messageId); if (switchedToMessageSet && loadedMessageThread) { return; } if (!switchedToMessageSet) { - await this._channel.query({ messages: { id_around: messageIdToFind, limit } }, 'new'); + await this._channel.query( + { messages: { id_around: messageIdToFind, limit } }, + 'new', + ); } if (!loadedMessageThread && parentMessageId) { await this._channel.getReplies(parentMessageId, { id_around: messageId, limit }); @@ -670,12 +743,17 @@ export class ChannelState { this.messageSets[index].isCurrent = true; } - private areMessageSetsOverlap(messages1: Array<{ id: string }>, messages2: Array<{ id: string }>) { + private areMessageSetsOverlap( + messages1: Array<{ id: string }>, + messages2: Array<{ id: string }>, + ) { return messages1.some((m1) => messages2.find((m2) => m1.id === m2.id)); } private findMessageSetIndex(message: { id?: string }) { - return this.messageSets.findIndex((set) => !!set.messages.find((m) => m.id === message.id)); + return this.messageSets.findIndex( + (set) => !!set.messages.find((m) => m.id === message.id), + ); } private findTargetMessageSet( @@ -683,12 +761,15 @@ export class ChannelState { addIfDoesNotExist = true, messageSetToAddToIfDoesNotExist: MessageSetType = 'current', ) { - let messagesToAdd: (MessageResponse | ReturnType)[] = newMessages; + let messagesToAdd: (MessageResponse | ReturnType)[] = + newMessages; let targetMessageSetIndex!: number; if (addIfDoesNotExist) { const overlappingMessageSetIndices = this.messageSets .map((_, i) => i) - .filter((i) => this.areMessageSetsOverlap(this.messageSets[i].messages, newMessages)); + .filter((i) => + this.areMessageSetsOverlap(this.messageSets[i].messages, newMessages), + ); switch (messageSetToAddToIfDoesNotExist) { case 'new': if (overlappingMessageSetIndices.length > 0) { @@ -716,13 +797,18 @@ export class ChannelState { // when merging the target set will be the first one from the overlapping message sets const mergeTargetMessageSetIndex = overlappingMessageSetIndices.splice(0, 1)[0]; const mergeSourceMessageSetIndices = [...overlappingMessageSetIndices]; - if (mergeTargetMessageSetIndex !== undefined && mergeTargetMessageSetIndex !== targetMessageSetIndex) { + if ( + mergeTargetMessageSetIndex !== undefined && + mergeTargetMessageSetIndex !== targetMessageSetIndex + ) { mergeSourceMessageSetIndices.push(targetMessageSetIndex); } // merge message sets if (mergeSourceMessageSetIndices.length > 0) { const target = this.messageSets[mergeTargetMessageSetIndex]; - const sources = this.messageSets.filter((_, i) => mergeSourceMessageSetIndices.indexOf(i) !== -1); + const sources = this.messageSets.filter( + (_, i) => mergeSourceMessageSetIndices.indexOf(i) !== -1, + ); sources.forEach((messageSet) => { target.isLatest = target.isLatest || messageSet.isLatest; target.isCurrent = target.isCurrent || messageSet.isCurrent; @@ -731,7 +817,8 @@ export class ChannelState { ? messageSet.pagination.hasPrev : target.pagination.hasPrev; target.pagination.hasNext = - target.messages.slice(-1)[0].created_at < messageSet.messages.slice(-1)[0].created_at + target.messages.slice(-1)[0].created_at < + messageSet.messages.slice(-1)[0].created_at ? messageSet.pagination.hasNext : target.pagination.hasNext; messagesToAdd = [...messagesToAdd, ...messageSet.messages]; diff --git a/src/client.ts b/src/client.ts index 29baea3ac..5b0785aa2 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,7 +1,8 @@ /* eslint no-unused-vars: "off" */ /* global process */ -import axios, { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; +import type { AxiosError, AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; +import axios from 'axios'; import https from 'https'; import type WebSocket from 'isomorphic-ws'; @@ -29,7 +30,7 @@ import { sleep, } from './utils'; -import { +import type { APIErrorResponse, APIResponse, AppSettings, @@ -80,7 +81,6 @@ import { Device, DeviceIdentifier, EndpointName, - ErrorFromResponse, Event, EventHandler, ExportChannelOptions, @@ -212,13 +212,18 @@ import { UserSort, VoteSort, } from './types'; +import { ErrorFromResponse } from './types'; import { InsightMetrics, postInsights } from './insights'; import { Thread } from './thread'; import { Moderation } from './moderation'; import { ThreadManager } from './thread_manager'; import { DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE } from './constants'; import { PollManager } from './poll_manager'; -import { ChannelManager, ChannelManagerEventHandlerOverrides, ChannelManagerOptions } from './channel_manager'; +import type { + ChannelManagerEventHandlerOverrides, + ChannelManagerOptions, +} from './channel_manager'; +import { ChannelManager } from './channel_manager'; function isString(x: unknown): x is string { return typeof x === 'string' || x instanceof String; @@ -299,7 +304,11 @@ export class StreamChat { */ constructor(key: string, options?: StreamChatOptions); constructor(key: string, secret?: string, options?: StreamChatOptions); - constructor(key: string, secretOrOptions?: StreamChatOptions | string, options?: StreamChatOptions) { + constructor( + key: string, + secretOrOptions?: StreamChatOptions | string, + options?: StreamChatOptions, + ) { // set the key this.key = key; this.listeners = {}; @@ -316,9 +325,16 @@ export class StreamChat { } // set the options... and figure out defaults... - const inputOptions = options ? options : secretOrOptions && !isString(secretOrOptions) ? secretOrOptions : {}; - - this.browser = typeof inputOptions.browser !== 'undefined' ? inputOptions.browser : typeof window !== 'undefined'; + const inputOptions = options + ? options + : secretOrOptions && !isString(secretOrOptions) + ? secretOrOptions + : {}; + + this.browser = + typeof inputOptions.browser !== 'undefined' + ? inputOptions.browser + : typeof window !== 'undefined'; this.node = !this.browser; this.options = { @@ -341,11 +357,19 @@ export class StreamChat { this.setBaseURL(this.options.baseURL || 'https://chat.stream-io-api.com'); - if (typeof process !== 'undefined' && 'env' in process && process.env.STREAM_LOCAL_TEST_RUN) { + if ( + typeof process !== 'undefined' && + 'env' in process && + process.env.STREAM_LOCAL_TEST_RUN + ) { this.setBaseURL('http://localhost:3030'); } - if (typeof process !== 'undefined' && 'env' in process && process.env.STREAM_LOCAL_TEST_HOST) { + if ( + typeof process !== 'undefined' && + 'env' in process && + process.env.STREAM_LOCAL_TEST_HOST + ) { this.setBaseURL('http://' + process.env.STREAM_LOCAL_TEST_HOST); } @@ -449,7 +473,11 @@ export class StreamChat { * StreamChat.getInstance('api_key', "secret", { httpsAgent: customAgent }) */ public static getInstance(key: string, options?: StreamChatOptions): StreamChat; - public static getInstance(key: string, secret?: string, options?: StreamChatOptions): StreamChat; + public static getInstance( + key: string, + secret?: string, + options?: StreamChatOptions, + ): StreamChat; public static getInstance( key: string, secretOrOptions?: StreamChatOptions | string, @@ -479,7 +507,8 @@ export class StreamChat { this.wsBaseURL = this.baseURL.replace('http', 'ws').replace(':3030', ':8800'); } - _getConnectionID = () => this.wsConnection?.connectionID || this.wsFallback?.connectionID; + _getConnectionID = () => + this.wsConnection?.connectionID || this.wsFallback?.connectionID; _hasConnectionID = () => Boolean(this._getConnectionID()); @@ -491,7 +520,10 @@ export class StreamChat { * * @return {ConnectAPIResponse} Returns a promise that resolves when the connection is setup */ - connectUser = async (user: OwnUserResponse | UserResponse, userTokenOrProvider: TokenOrProvider) => { + connectUser = async ( + user: OwnUserResponse | UserResponse, + userTokenOrProvider: TokenOrProvider, + ) => { if (!user.id) { throw new Error('The "id" field on the user is missing'); } @@ -513,7 +545,10 @@ export class StreamChat { ); } - if ((this._isUsingServerAuth() || this.node) && !this.options.allowServerSideConnect) { + if ( + (this._isUsingServerAuth() || this.node) && + !this.options.allowServerSideConnect + ) { console.warn( 'Please do not use connectUser server side. connectUser impacts MAU and concurrent connection usage and thus your bill. If you have a valid use-case, add "allowServerSideConnect: true" to the client options to disable this warning.', ); @@ -590,7 +625,10 @@ export class StreamChat { this.cleaningIntervalRef = undefined; } - await Promise.all([this.wsConnection?.disconnect(timeout), this.wsFallback?.disconnect(timeout)]); + await Promise.all([ + this.wsConnection?.disconnect(timeout), + this.wsFallback?.disconnect(timeout), + ]); return Promise.resolve(); }; @@ -608,16 +646,16 @@ export class StreamChat { }: { eventHandlerOverrides?: ChannelManagerEventHandlerOverrides; options?: ChannelManagerOptions; - }) => { - return new ChannelManager({ client: this, eventHandlerOverrides, options }); - }; + }) => new ChannelManager({ client: this, eventHandlerOverrides, options }); /** * Creates a new WebSocket connection with the current user. Returns empty promise, if there is an active connection */ - openConnection = async () => { + openConnection = () => { if (!this.userID) { - throw Error('User is not set on client, use client.connectUser or client.connectAnonymousUser instead'); + throw Error( + 'User is not set on client, use client.connectUser or client.connectAnonymousUser instead', + ); } if (this.wsConnection?.isConnecting && this.wsPromise) { @@ -627,10 +665,17 @@ export class StreamChat { return this.wsPromise; } - if ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) && this._hasConnectionID()) { - this.logger('info', 'client:openConnection() - openConnection called twice, healthy connection already exists', { - tags: ['connection', 'client'], - }); + if ( + (this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) && + this._hasConnectionID() + ) { + this.logger( + 'info', + 'client:openConnection() - openConnection called twice, healthy connection already exists', + { + tags: ['connection', 'client'], + }, + ); return; } @@ -695,7 +740,9 @@ export class StreamChat { } if (before === '') { - throw new Error("Don't pass blank string for since, use null instead if resetting the token revoke"); + throw new Error( + "Don't pass blank string for since, use null instead if resetting the token revoke", + ); } return before; @@ -768,7 +815,9 @@ export class StreamChat { ...(data.messageID ? { message_id: data.messageID } : {}), ...(data.apnTemplate ? { apn_template: data.apnTemplate } : {}), ...(data.firebaseTemplate ? { firebase_template: data.firebaseTemplate } : {}), - ...(data.firebaseDataTemplate ? { firebase_data_template: data.firebaseDataTemplate } : {}), + ...(data.firebaseDataTemplate + ? { firebase_data_template: data.firebaseDataTemplate } + : {}), ...(data.skipDevices ? { skip_devices: true } : {}), ...(data.pushProviderName ? { push_provider_name: data.pushProviderName } : {}), ...(data.pushProviderType ? { push_provider_type: data.pushProviderType } : {}), @@ -809,7 +858,7 @@ export class StreamChat { * @param timeout Max number of ms, to wait for close event of websocket, before forcefully assuming successful disconnection. * https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent */ - disconnectUser = async (timeout?: number) => { + disconnectUser = (timeout?: number) => { this.logger('info', 'client:disconnect() - Disconnecting the client', { tags: ['connection', 'client'], }); @@ -851,7 +900,10 @@ export class StreamChat { * connectAnonymousUser - Set an anonymous user and open a WebSocket connection */ connectAnonymousUser = () => { - if ((this._isUsingServerAuth() || this.node) && !this.options.allowServerSideConnect) { + if ( + (this._isUsingServerAuth() || this.node) && + !this.options.allowServerSideConnect + ) { console.warn( 'Please do not use connectUser server side. connectUser impacts MAU and concurrent connection usage and thus your bill. If you have a valid use-case, add "allowServerSideConnect: true" to the client options to disable this warning.', ); @@ -942,9 +994,14 @@ export class StreamChat { */ on(callback: EventHandler): { unsubscribe: () => void }; on(eventType: string, callback: EventHandler): { unsubscribe: () => void }; - on(callbackOrString: EventHandler | string, callbackOrNothing?: EventHandler): { unsubscribe: () => void } { + on( + callbackOrString: EventHandler | string, + callbackOrNothing?: EventHandler, + ): { unsubscribe: () => void } { const key = callbackOrNothing ? (callbackOrString as string) : 'all'; - const callback = callbackOrNothing ? callbackOrNothing : (callbackOrString as EventHandler); + const callback = callbackOrNothing + ? callbackOrNothing + : (callbackOrString as EventHandler); if (!(key in this.listeners)) { this.listeners[key] = []; } @@ -970,7 +1027,9 @@ export class StreamChat { off(eventType: string, callback: EventHandler): void; off(callbackOrString: EventHandler | string, callbackOrNothing?: EventHandler) { const key = callbackOrNothing ? (callbackOrString as string) : 'all'; - const callback = callbackOrNothing ? callbackOrNothing : (callbackOrString as EventHandler); + const callback = callbackOrNothing + ? callbackOrNothing + : (callbackOrString as EventHandler); if (!(key in this.listeners)) { this.listeners[key] = []; } @@ -998,11 +1057,15 @@ export class StreamChat { } _logApiResponse(type: string, url: string, response: AxiosResponse) { - this.logger('info', `client:${type} - Response - url: ${url} > status ${response.status}`, { - tags: ['api', 'api_response', 'client'], - url, - response, - }); + this.logger( + 'info', + `client:${type} - Response - url: ${url} > status ${response.status}`, + { + tags: ['api', 'api_response', 'client'], + url, + response, + }, + ); } _logApiError(type: string, url: string, error: unknown) { @@ -1061,7 +1124,10 @@ export class StreamChat { this.consecutiveFailures += 1; if (e.response) { /** connection_fallback depends on this token expiration logic */ - if (e.response.data.code === chatCodes.TOKEN_EXPIRED && !this.tokenManager.isStatic()) { + if ( + e.response.data.code === chatCodes.TOKEN_EXPIRED && + !this.tokenManager.isStatic() + ) { if (this.consecutiveFailures > 1) { await sleep(retryInterval(this.consecutiveFailures)); } @@ -1115,11 +1181,15 @@ export class StreamChat { }); } - errorFromResponse(response: AxiosResponse): ErrorFromResponse { + errorFromResponse( + response: AxiosResponse, + ): ErrorFromResponse { let err: ErrorFromResponse; err = new ErrorFromResponse(`StreamChat error HTTP code: ${response.status}`); if (response.data && response.data.code) { - err = new Error(`StreamChat error code ${response.data.code}: ${response.data.message}`); + err = new Error( + `StreamChat error code ${response.data.code}: ${response.data.message}`, + ); err.code = response.data.code; } err.response = response; @@ -1296,20 +1366,33 @@ export class StreamChat { this._updateUserMessageReferences(event.user); } - if (event.type === 'user.deleted' && event.user.deleted_at && (event.mark_messages_deleted || event.hard_delete)) { + if ( + event.type === 'user.deleted' && + event.user.deleted_at && + (event.mark_messages_deleted || event.hard_delete) + ) { this._deleteUserMessageReference(event.user, event.hard_delete); } }; _handleClientEvent(event: Event) { + // eslint-disable-next-line @typescript-eslint/no-this-alias const client = this; const postListenerCallbacks = []; - this.logger('info', `client:_handleClientEvent - Received event of type { ${event.type} }`, { - tags: ['event', 'client'], - event, - }); + this.logger( + 'info', + `client:_handleClientEvent - Received event of type { ${event.type} }`, + { + tags: ['event', 'client'], + event, + }, + ); - if (event.type === 'user.presence.changed' || event.type === 'user.updated' || event.type === 'user.deleted') { + if ( + event.type === 'user.presence.changed' || + event.type === 'user.updated' || + event.type === 'user.deleted' + ) { this._handleUserEvent(event); } @@ -1334,10 +1417,17 @@ export class StreamChat { if (event.type === 'notification.mark_read' && event.unread_channels === 0) { const activeChannelKeys = Object.keys(this.activeChannels); - activeChannelKeys.forEach((activeChannelKey) => (this.activeChannels[activeChannelKey].state.unreadCount = 0)); + activeChannelKeys.forEach( + (activeChannelKey) => + (this.activeChannels[activeChannelKey].state.unreadCount = 0), + ); } - if ((event.type === 'channel.deleted' || event.type === 'notification.channel_deleted') && event.cid) { + if ( + (event.type === 'channel.deleted' || + event.type === 'notification.channel_deleted') && + event.cid + ) { client.state.deleteAllChannelReference(event.cid); this.activeChannels[event.cid]?._disconnect(); @@ -1357,7 +1447,9 @@ export class StreamChat { const mute = this.mutedChannels[i]; if (mute.channel?.cid === cid) { muteStatus = { - muted: mute.expires ? new Date(mute.expires).getTime() > new Date().getTime() : true, + muted: mute.expires + ? new Date(mute.expires).getTime() > new Date().getTime() + : true, createdAt: mute.created_at ? new Date(mute.created_at) : new Date(), expiresAt: mute.expires ? new Date(mute.expires) : null, }; @@ -1377,6 +1469,7 @@ export class StreamChat { } _callClientListeners = (event: Event) => { + // eslint-disable-next-line @typescript-eslint/no-this-alias const client = this; // gather and call the listeners const listeners: Array<(event: Event) => void> = []; @@ -1394,19 +1487,33 @@ export class StreamChat { }; recoverState = async () => { - this.logger('info', `client:recoverState() - Start of recoverState with connectionID ${this._getConnectionID()}`, { - tags: ['connection'], - }); + this.logger( + 'info', + `client:recoverState() - Start of recoverState with connectionID ${this._getConnectionID()}`, + { + tags: ['connection'], + }, + ); const cids = Object.keys(this.activeChannels); if (cids.length && this.recoverStateOnReconnect) { - this.logger('info', `client:recoverState() - Start the querying of ${cids.length} channels`, { - tags: ['connection', 'client'], - }); + this.logger( + 'info', + `client:recoverState() - Start the querying of ${cids.length} channels`, + { + tags: ['connection', 'client'], + }, + ); - await this.queryChannels({ cid: { $in: cids } } as ChannelFilters, { last_message_at: -1 }, { limit: 30 }); + await this.queryChannels( + { cid: { $in: cids } } as ChannelFilters, + { last_message_at: -1 }, + { limit: 30 }, + ); - this.logger('info', 'client:recoverState() - Querying channels finished', { tags: ['connection', 'client'] }); + this.logger('info', 'client:recoverState() - Querying channels finished', { + tags: ['connection', 'client'], + }); this.dispatchEvent({ type: 'connection.recovered', } as Event); @@ -1425,7 +1532,9 @@ export class StreamChat { */ async connect() { if (!this.userID || !this._user) { - throw Error('Call connectUser or connectAnonymousUser before starting the connection'); + throw Error( + 'Call connectUser or connectAnonymousUser before starting the connection', + ); } if (!this.wsBaseURL) { throw Error('Websocket base url not set'); @@ -1440,8 +1549,8 @@ export class StreamChat { // The StableWSConnection handles all the reconnection logic. if (this.options.wsConnection && this.node) { // Intentionally avoiding adding ts generics on wsConnection in options since its only useful for unit test purpose. - ((this.options.wsConnection as unknown) as StableWSConnection).setClient(this); - this.wsConnection = (this.options.wsConnection as unknown) as StableWSConnection; + (this.options.wsConnection as unknown as StableWSConnection).setClient(this); + this.wsConnection = this.options.wsConnection as unknown as StableWSConnection; } else { this.wsConnection = new StableWSConnection({ client: this, @@ -1456,14 +1565,18 @@ export class StreamChat { // if WSFallback is enabled, ws connect should timeout faster so fallback can try return await this.wsConnection.connect( - this.options.enableWSFallback ? this.defaultWSTimeoutWithFallback : this.defaultWSTimeout, + this.options.enableWSFallback + ? this.defaultWSTimeoutWithFallback + : this.defaultWSTimeout, ); // eslint-disable-next-line @typescript-eslint/no-explicit-any } catch (error: any) { // run fallback only if it's WS/Network error and not a normal API error // make sure browser is online before even trying the longpoll if (this.options.enableWSFallback && isWSFailure(error) && isOnline()) { - this.logger('info', 'client:connect() - WS failed, fallback to longpoll', { tags: ['connection', 'client'] }); + this.logger('info', 'client:connect() - WS failed, fallback to longpoll', { + tags: ['connection', 'client'], + }); this.dispatchEvent({ type: 'transport.changed', mode: 'longpoll' }); this.wsConnection._destroyCurrentWSConnection(); @@ -1507,7 +1620,11 @@ export class StreamChat { * * @return {Promise<{ users: Array }>} User Query Response */ - async queryUsers(filterConditions: UserFilters, sort: UserSort = [], options: UserOptions = {}) { + async queryUsers( + filterConditions: UserFilters, + sort: UserSort = [], + options: UserOptions = {}, + ) { const defaultOptions = { presence: false, }; @@ -1520,14 +1637,17 @@ export class StreamChat { } // Return a list of users - const data = await this.get }>(this.baseURL + '/users', { - payload: { - filter_conditions: filterConditions, - sort: normalizeQuerySort(sort), - ...defaultOptions, - ...options, + const data = await this.get }>( + this.baseURL + '/users', + { + payload: { + filter_conditions: filterConditions, + sort: normalizeQuerySort(sort), + ...defaultOptions, + ...options, + }, }, - }); + ); this.state.updateUsers(data.users); @@ -1566,11 +1686,17 @@ export class StreamChat { * * @return {Promise} Message Flags Response */ - async queryMessageFlags(filterConditions: MessageFlagsFilters = {}, options: MessageFlagsPaginationOptions = {}) { + async queryMessageFlags( + filterConditions: MessageFlagsFilters = {}, + options: MessageFlagsPaginationOptions = {}, + ) { // Return a list of message flags - return await this.get(this.baseURL + '/moderation/flags/message', { - payload: { filter_conditions: filterConditions, ...options }, - }); + return await this.get( + this.baseURL + '/moderation/flags/message', + { + payload: { filter_conditions: filterConditions, ...options }, + }, + ); } /** @@ -1611,7 +1737,10 @@ export class StreamChat { ...options, }; - const data = await this.post(this.baseURL + '/channels', payload); + const data = await this.post( + this.baseURL + '/channels', + payload, + ); this.dispatchEvent({ type: 'channels.queried', @@ -1686,7 +1815,9 @@ export class StreamChat { ...updatedMessagesSet.pagination, ...messageSetPagination({ parentSet: updatedMessagesSet, - requestedPageSize: queryChannelsOptions?.message_limit || DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE, + requestedPageSize: + queryChannelsOptions?.message_limit || + DEFAULT_QUERY_CHANNELS_MESSAGE_LIST_PAGE_SIZE, returnedPage: channelState.messages, logger: this.logger, }), @@ -1709,14 +1840,20 @@ export class StreamChat { * * @return {Promise} search messages response */ - async search(filterConditions: ChannelFilters, query: string | MessageFilters, options: SearchOptions = {}) { + async search( + filterConditions: ChannelFilters, + query: string | MessageFilters, + options: SearchOptions = {}, + ) { if (options.offset && options.next) { throw Error(`Cannot specify offset with next`); } const payload: SearchPayload = { filter_conditions: filterConditions, ...options, - sort: options.sort ? normalizeQuerySort(options.sort) : undefined, + sort: options.sort + ? normalizeQuerySort(options.sort) + : undefined, }; if (typeof query === 'string') { payload.query = query; @@ -1743,7 +1880,8 @@ export class StreamChat { setLocalDevice(device: BaseDeviceFields) { if ( (this.wsConnection?.isConnecting && this.wsPromise) || - ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) && this._hasConnectionID()) + ((this.wsConnection?.isHealthy || this.wsFallback?.isHealthy()) && + this._hasConnectionID()) ) { throw new Error('you can only set device before opening a websocket connection'); } @@ -1760,7 +1898,12 @@ export class StreamChat { * @param {string} [push_provider_name] user provided push provider name for multi bundle support * */ - async addDevice(id: string, push_provider: PushProvider, userID?: string, push_provider_name?: string) { + async addDevice( + id: string, + push_provider: PushProvider, + userID?: string, + push_provider_name?: string, + ) { return await this.post(this.baseURL + '/devices', { id, push_provider, @@ -1791,7 +1934,10 @@ export class StreamChat { * @return {} */ async getUnreadCount(userID?: string) { - return await this.get(this.baseURL + '/unread', userID ? { user_id: userID } : {}); + return await this.get( + this.baseURL + '/unread', + userID ? { user_id: userID } : {}, + ); } /** @@ -1802,7 +1948,10 @@ export class StreamChat { * @return {} */ async getUnreadCountBatch(userIDs: string[]) { - return await this.post(this.baseURL + '/unread_batch', { user_ids: userIDs }); + return await this.post( + this.baseURL + '/unread_batch', + { user_ids: userIDs }, + ); } /** @@ -1813,7 +1962,10 @@ export class StreamChat { * @return {} */ async setPushPreferences(preferences: PushPreference[]) { - return await this.post(this.baseURL + '/push_preferences', { preferences }); + return await this.post( + this.baseURL + '/push_preferences', + { preferences }, + ); } /** @@ -1837,7 +1989,7 @@ export class StreamChat { * @param {object} [params] The params for the call. If none of the params are set, all limits for all platforms are returned. * @returns {Promise} */ - async getRateLimits(params?: { + getRateLimits(params?: { android?: boolean; endpoints?: EndpointName[]; ios?: boolean; @@ -1876,13 +2028,19 @@ export class StreamChat { */ channel(channelType: string, channelID?: string | null, custom?: ChannelData): Channel; channel(channelType: string, custom?: ChannelData): Channel; - channel(channelType: string, channelIDOrCustom?: string | ChannelData | null, custom: ChannelData = {}) { + channel( + channelType: string, + channelIDOrCustom?: string | ChannelData | null, + custom: ChannelData = {}, + ) { if (!this.userID && !this._isUsingServerAuth()) { throw Error('Call connectUser or connectAnonymousUser before creating a channel'); } if (~channelType.indexOf(':')) { - throw new Error(`Invalid channel group ${channelType}, can't contain the : character`); + throw new Error( + `Invalid channel group ${channelType}, can't contain the : character`, + ); } // support channel("messaging", {options}) @@ -1925,7 +2083,7 @@ export class StreamChat { // Check if the channel already exists. // Only allow 1 channel object per cid const memberIds = (custom.members ?? []).map((member: string | NewMemberPayload) => - typeof member === 'string' ? member : member.user_id ?? '', + typeof member === 'string' ? member : (member.user_id ?? ''), ); const membersStr = memberIds.sort().join(','); const tempCid = generateChannelTempCid(channelType, memberIds); @@ -1950,7 +2108,9 @@ export class StreamChat { } if (key.indexOf(`${channelType}:!members-`) === 0) { - const membersStrInExistingChannel = Object.keys(channel.state.members).sort().join(','); + const membersStrInExistingChannel = Object.keys(channel.state.members) + .sort() + .join(','); if (membersStrInExistingChannel === membersStr) { return channel; } @@ -1991,7 +2151,11 @@ export class StreamChat { // only allow 1 channel object per cid const cid = `${channelType}:${channelID}`; - if (cid in this.activeChannels && this.activeChannels[cid] && !this.activeChannels[cid].disconnected) { + if ( + cid in this.activeChannels && + this.activeChannels[cid] && + !this.activeChannels[cid].disconnected + ) { const channel = this.activeChannels[cid]; if (Object.keys(custom).length > 0) { channel.data = { ...channel.data, ...custom }; @@ -2146,7 +2310,10 @@ export class StreamChat { * @return {TaskResponse} A task ID */ async reactivateUsers(user_ids: string[], options?: ReactivateUsersOptions) { - return await this.post(this.baseURL + `/users/reactivate`, { user_ids, ...options }); + return await this.post( + this.baseURL + `/users/reactivate`, + { user_ids, ...options }, + ); } /** @@ -2173,7 +2340,10 @@ export class StreamChat { * @return {TaskResponse} A task ID */ async deactivateUsers(user_ids: string[], options?: DeactivateUsersOptions) { - return await this.post(this.baseURL + `/users/deactivate`, { user_ids, ...options }); + return await this.post( + this.baseURL + `/users/deactivate`, + { user_ids, ...options }, + ); } async exportUser(userID: string, options?: Record) { @@ -2305,7 +2475,10 @@ export class StreamChat { * @param {string} [options.user_id] currentUserID, only used with serverside auth * @returns {Promise} */ - async flagMessage(targetMessageID: string, options: { reason?: string; user_id?: string } = {}) { + async flagMessage( + targetMessageID: string, + options: { reason?: string; user_id?: string } = {}, + ) { return await this.post(this.baseURL + '/moderation/flag', { target_message_id: targetMessageID, ...options, @@ -2359,7 +2532,10 @@ export class StreamChat { * @returns {Promise} */ async getCallToken(callID: string, options: { user_id?: string } = {}) { - return await this.post(this.baseURL + `/calls/${encodeURIComponent(callID)}`, { ...options }); + return await this.post( + this.baseURL + `/calls/${encodeURIComponent(callID)}`, + { ...options }, + ); } /** @@ -2375,7 +2551,10 @@ export class StreamChat { * * @return {Promise} Flags Response */ - async _queryFlags(filterConditions: FlagsFilters = {}, options: FlagsPaginationOptions = {}) { + async _queryFlags( + filterConditions: FlagsFilters = {}, + options: FlagsPaginationOptions = {}, + ) { // Return a list of flags return await this.post(this.baseURL + '/moderation/flags', { filter_conditions: filterConditions, @@ -2396,7 +2575,10 @@ export class StreamChat { * * @return {Promise} Flag Reports Response */ - async _queryFlagReports(filterConditions: FlagReportsFilters = {}, options: FlagReportsPaginationOptions = {}) { + async _queryFlagReports( + filterConditions: FlagReportsFilters = {}, + options: FlagReportsPaginationOptions = {}, + ) { // Return a list of message flags return await this.post(this.baseURL + '/moderation/reports', { filter_conditions: filterConditions, @@ -2418,11 +2600,18 @@ export class StreamChat { * @param {string} [options.review_details] custom information about review result * @returns {Promise>} */ - async _reviewFlagReport(id: string, reviewResult: string, options: ReviewFlagReportOptions = {}) { - return await this.patch(this.baseURL + `/moderation/reports/${encodeURIComponent(id)}`, { - review_result: reviewResult, - ...options, - }); + async _reviewFlagReport( + id: string, + reviewResult: string, + options: ReviewFlagReportOptions = {}, + ) { + return await this.patch( + this.baseURL + `/moderation/reports/${encodeURIComponent(id)}`, + { + review_result: reviewResult, + ...options, + }, + ); } /** @@ -2469,15 +2658,22 @@ export class StreamChat { } getCommand(name: string) { - return this.get(this.baseURL + `/commands/${encodeURIComponent(name)}`); + return this.get( + this.baseURL + `/commands/${encodeURIComponent(name)}`, + ); } updateCommand(name: string, data: UpdateCommandOptions) { - return this.put(this.baseURL + `/commands/${encodeURIComponent(name)}`, data); + return this.put( + this.baseURL + `/commands/${encodeURIComponent(name)}`, + data, + ); } deleteCommand(name: string) { - return this.delete(this.baseURL + `/commands/${encodeURIComponent(name)}`); + return this.delete( + this.baseURL + `/commands/${encodeURIComponent(name)}`, + ); } listCommands() { @@ -2490,15 +2686,22 @@ export class StreamChat { } getChannelType(channelType: string) { - return this.get(this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`); + return this.get( + this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`, + ); } updateChannelType(channelType: string, data: UpdateChannelTypeRequest) { - return this.put(this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`, data); + return this.put( + this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`, + data, + ); } deleteChannelType(channelType: string) { - return this.delete(this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`); + return this.delete( + this.baseURL + `/channeltypes/${encodeURIComponent(channelType)}`, + ); } listChannelTypes() { @@ -2560,7 +2763,10 @@ export class StreamChat { * @param {string | { id: string }} messageOrMessageId message object or message id * @param {string} errorText error message to report in case of message id absence */ - _validateAndGetMessageId(messageOrMessageId: string | { id: string }, errorText: string) { + _validateAndGetMessageId( + messageOrMessageId: string | { id: string }, + errorText: string, + ) { let messageId: string; if (typeof messageOrMessageId === 'string') { messageId = messageOrMessageId; @@ -2592,13 +2798,13 @@ export class StreamChat { ); return this.partialUpdateMessage( messageId, - ({ + { set: { pinned: true, pin_expires: this._normalizeExpiration(timeoutOrExpirationDate), pinned_at: this._normalizeExpiration(pinnedAt), }, - } as unknown) as PartialMessageUpdate, + } as unknown as PartialMessageUpdate, pinnedBy, ); } @@ -2608,16 +2814,19 @@ export class StreamChat { * @param {string | { id: string }} messageOrMessageId message object or message id * @param {string | { id: string }} [userId] */ - unpinMessage(messageOrMessageId: string | { id: string }, userId?: string | { id: string }) { + unpinMessage( + messageOrMessageId: string | { id: string }, + userId?: string | { id: string }, + ) { const messageId = this._validateAndGetMessageId( messageOrMessageId, 'Please specify the message id when calling unpinMessage', ); return this.partialUpdateMessage( messageId, - ({ + { set: { pinned: false }, - } as unknown) as PartialMessageUpdate, + } as unknown as PartialMessageUpdate, userId, ); } @@ -2631,7 +2840,11 @@ export class StreamChat { * * @return {{ message: MessageResponse }} Response that includes the message */ - async updateMessage(message: UpdatedMessage, userId?: string | { id: string }, options?: UpdateMessageOptions) { + async updateMessage( + message: UpdatedMessage, + userId?: string | { id: string }, + options?: UpdateMessageOptions, + ) { if (!message.id) { throw Error('Please specify the message id when calling updateMessage'); } @@ -2674,8 +2887,13 @@ export class StreamChat { * Server always expects mentioned_users to be array of string. We are adding extra check, just in case * SDK missed this conversion. */ - if (Array.isArray(clonedMessage.mentioned_users) && !isString(clonedMessage.mentioned_users[0])) { - clonedMessage.mentioned_users = clonedMessage.mentioned_users.map((mu) => ((mu as unknown) as UserResponse).id); + if ( + Array.isArray(clonedMessage.mentioned_users) && + !isString(clonedMessage.mentioned_users[0]) + ) { + clonedMessage.mentioned_users = clonedMessage.mentioned_users.map( + (mu) => (mu as unknown as UserResponse).id, + ); } return await this.post( @@ -2713,11 +2931,14 @@ export class StreamChat { if (userId != null && isString(userId)) { user = { id: userId }; } - return await this.put(this.baseURL + `/messages/${encodeURIComponent(id)}`, { - ...partialMessageObject, - ...options, - user, - }); + return await this.put( + this.baseURL + `/messages/${encodeURIComponent(id)}`, + { + ...partialMessageObject, + ...options, + user, + }, + ); } async deleteMessage(messageID: string, hardDelete?: boolean) { @@ -2751,9 +2972,12 @@ export class StreamChat { } async getMessage(messageID: string, options?: GetMessageOptions) { - return await this.get(this.baseURL + `/messages/${encodeURIComponent(messageID)}`, { - ...options, - }); + return await this.get( + this.baseURL + `/messages/${encodeURIComponent(messageID)}`, + { + ...options, + }, + ); } /** @@ -2776,10 +3000,15 @@ export class StreamChat { ...options, }; - const response = await this.post(`${this.baseURL}/threads`, optionsWithDefaults); + const response = await this.post( + `${this.baseURL}/threads`, + optionsWithDefaults, + ); return { - threads: response.threads.map((thread) => new Thread({ client: this, threadData: thread })), + threads: response.threads.map( + (thread) => new Thread({ client: this, threadData: thread }), + ), next: response.next, }; } @@ -2874,16 +3103,20 @@ export class StreamChat { const { os, model } = this.deviceIdentifier ?? {}; - return ([ - // reports the device OS, if provided - ['os', os], - // reports the device model, if provided - ['device_model', model], - // reports which bundle is being picked from the exports - ['client_bundle', clientBundle], - ] as const).reduce( + return ( + [ + // reports the device OS, if provided + ['os', os], + // reports the device model, if provided + ['device_model', model], + // reports which bundle is being picked from the exports + ['client_bundle', clientBundle], + ] as const + ).reduce( (withArguments, [key, value]) => - value && value.length > 0 ? withArguments.concat(`|${key}=${value}`) : withArguments, + value && value.length > 0 + ? withArguments.concat(`|${key}=${value}`) + : withArguments, userAgentString, ); } @@ -2925,8 +3158,11 @@ export class StreamChat { }; } - const { params: axiosRequestConfigParams, headers: axiosRequestConfigHeaders, ...axiosRequestConfigRest } = - this.options.axiosRequestConfig || {}; + const { + params: axiosRequestConfigParams, + headers: axiosRequestConfigHeaders, + ...axiosRequestConfigRest + } = this.options.axiosRequestConfig || {}; return { params: { @@ -2956,6 +3192,7 @@ export class StreamChat { } _startCleaning() { + // eslint-disable-next-line @typescript-eslint/no-this-alias const that = this; if (this.cleaningIntervalRef != null) { return; @@ -2973,14 +3210,13 @@ export class StreamChat { * @private * @returns json string */ - _buildWSPayload = (client_request_id?: string) => { - return JSON.stringify({ + _buildWSPayload = (client_request_id?: string) => + JSON.stringify({ user_id: this.userID, user_details: this._user, device: this.options.device, client_request_id, }); - }; /** * checks signature of a request @@ -2998,7 +3234,9 @@ export class StreamChat { * @returns {Promise} */ getPermission(name: string) { - return this.get(`${this.baseURL}/permissions/${encodeURIComponent(name)}`); + return this.get( + `${this.baseURL}/permissions/${encodeURIComponent(name)}`, + ); } /** createPermission - creates a custom permission @@ -3019,9 +3257,12 @@ export class StreamChat { * @returns {Promise} */ updatePermission(id: string, permissionData: Omit) { - return this.put(`${this.baseURL}/permissions/${encodeURIComponent(id)}`, { - ...permissionData, - }); + return this.put( + `${this.baseURL}/permissions/${encodeURIComponent(id)}`, + { + ...permissionData, + }, + ); } /** deletePermission - deletes a custom permission @@ -3030,7 +3271,9 @@ export class StreamChat { * @returns {Promise} */ deletePermission(name: string) { - return this.delete(`${this.baseURL}/permissions/${encodeURIComponent(name)}`); + return this.delete( + `${this.baseURL}/permissions/${encodeURIComponent(name)}`, + ); } /** listPermissions - returns the list of all permissions for this application @@ -3091,9 +3334,12 @@ export class StreamChat { * @return {Promise} The Server Response */ async sendUserCustomEvent(targetUserID: string, event: UserCustomEvent) { - return await this.post(`${this.baseURL}/users/${encodeURIComponent(targetUserID)}/event`, { - event, - }); + return await this.post( + `${this.baseURL}/users/${encodeURIComponent(targetUserID)}/event`, + { + event, + }, + ); } /** @@ -3119,7 +3365,10 @@ export class StreamChat { * @returns {Promise} Response containing array of block lists */ listBlockLists(data?: { team?: string }) { - return this.get(`${this.baseURL}/blocklists`, data); + return this.get( + `${this.baseURL}/blocklists`, + data, + ); } /** @@ -3149,7 +3398,10 @@ export class StreamChat { * @returns {Promise} The server response */ updateBlockList(name: string, data: { words: string[]; team?: string }) { - return this.put(`${this.baseURL}/blocklists/${encodeURIComponent(name)}`, data); + return this.put( + `${this.baseURL}/blocklists/${encodeURIComponent(name)}`, + data, + ); } /** @@ -3162,16 +3414,28 @@ export class StreamChat { * @returns {Promise} The server response */ deleteBlockList(name: string, data?: { team?: string }) { - return this.delete(`${this.baseURL}/blocklists/${encodeURIComponent(name)}`, data); + return this.delete( + `${this.baseURL}/blocklists/${encodeURIComponent(name)}`, + data, + ); } - exportChannels(request: Array, options: ExportChannelOptions = {}) { + exportChannels( + request: Array, + options: ExportChannelOptions = {}, + ) { const payload = { channels: request, ...options }; - return this.post(`${this.baseURL}/export_channels`, payload); + return this.post( + `${this.baseURL}/export_channels`, + payload, + ); } exportUsers(request: ExportUsersRequest) { - return this.post(`${this.baseURL}/export/users`, request); + return this.post( + `${this.baseURL}/export/users`, + request, + ); } exportChannel(request: ExportChannelRequest, options?: ExportChannelOptions) { @@ -3219,7 +3483,7 @@ export class StreamChat { * * @return {{segment: SegmentResponse} & APIResponse} The created Segment */ - async createSegment(type: SegmentType, id: string | null, data?: SegmentData) { + createSegment(type: SegmentType, id: string | null, data?: SegmentData) { this.validateServerSideAuth(); const body = { id, @@ -3238,7 +3502,7 @@ export class StreamChat { * * @return {Segment} The created Segment */ - async createUserSegment(id: string | null, data?: SegmentData) { + createUserSegment(id: string | null, data?: SegmentData) { this.validateServerSideAuth(); return this.createSegment('user', id, data); } @@ -3252,14 +3516,16 @@ export class StreamChat { * * @return {Segment} The created Segment */ - async createChannelSegment(id: string | null, data?: SegmentData) { + createChannelSegment(id: string | null, data?: SegmentData) { this.validateServerSideAuth(); return this.createSegment('channel', id, data); } - async getSegment(id: string) { + getSegment(id: string) { this.validateServerSideAuth(); - return this.get<{ segment: SegmentResponse } & APIResponse>(this.baseURL + `/segments/${encodeURIComponent(id)}`); + return this.get<{ segment: SegmentResponse } & APIResponse>( + this.baseURL + `/segments/${encodeURIComponent(id)}`, + ); } /** @@ -3270,9 +3536,12 @@ export class StreamChat { * * @return {Segment} Updated Segment */ - async updateSegment(id: string, data: Partial) { + updateSegment(id: string, data: Partial) { this.validateServerSideAuth(); - return this.put<{ segment: SegmentResponse }>(this.baseURL + `/segments/${encodeURIComponent(id)}`, data); + return this.put<{ segment: SegmentResponse }>( + this.baseURL + `/segments/${encodeURIComponent(id)}`, + data, + ); } /** @@ -3283,13 +3552,16 @@ export class StreamChat { * * @return {APIResponse} API response */ - async addSegmentTargets(id: string, targets: string[]) { + addSegmentTargets(id: string, targets: string[]) { this.validateServerSideAuth(); const body = { target_ids: targets }; - return this.post(this.baseURL + `/segments/${encodeURIComponent(id)}/addtargets`, body); + return this.post( + this.baseURL + `/segments/${encodeURIComponent(id)}/addtargets`, + body, + ); } - async querySegmentTargets( + querySegmentTargets( id: string, filter: QuerySegmentTargetsFilter | null = {}, sort: SortParam[] | null | [] = [], @@ -3313,10 +3585,13 @@ export class StreamChat { * * @return {APIResponse} API response */ - async removeSegmentTargets(id: string, targets: string[]) { + removeSegmentTargets(id: string, targets: string[]) { this.validateServerSideAuth(); const body = { target_ids: targets }; - return this.post(this.baseURL + `/segments/${encodeURIComponent(id)}/deletetargets`, body); + return this.post( + this.baseURL + `/segments/${encodeURIComponent(id)}/deletetargets`, + body, + ); } /** @@ -3327,7 +3602,7 @@ export class StreamChat { * * @return {Segment[]} Segments */ - async querySegments(filter: {}, sort?: SortParam[], options: QuerySegmentsOptions = {}) { + querySegments(filter: {}, sort?: SortParam[], options: QuerySegmentsOptions = {}) { this.validateServerSideAuth(); return this.post< { @@ -3349,7 +3624,7 @@ export class StreamChat { * * @return {Promise} The Server Response */ - async deleteSegment(id: string) { + deleteSegment(id: string) { this.validateServerSideAuth(); return this.delete(this.baseURL + `/segments/${encodeURIComponent(id)}`); } @@ -3362,10 +3637,11 @@ export class StreamChat { * * @return {Promise} The Server Response */ - async segmentTargetExists(segmentId: string, targetId: string) { + segmentTargetExists(segmentId: string, targetId: string) { this.validateServerSideAuth(); return this.get( - this.baseURL + `/segments/${encodeURIComponent(segmentId)}/target/${encodeURIComponent(targetId)}`, + this.baseURL + + `/segments/${encodeURIComponent(segmentId)}/target/${encodeURIComponent(targetId)}`, ); } @@ -3376,7 +3652,7 @@ export class StreamChat { * * @return {Campaign} The Created Campaign */ - async createCampaign(params: CampaignData) { + createCampaign(params: CampaignData) { this.validateServerSideAuth(); return this.post< { @@ -3389,7 +3665,7 @@ export class StreamChat { >(this.baseURL + `/campaigns`, { ...params }); } - async getCampaign(id: string, options?: GetCampaignOptions) { + getCampaign(id: string, options?: GetCampaignOptions) { this.validateServerSideAuth(); return this.get< { @@ -3402,7 +3678,7 @@ export class StreamChat { >(this.baseURL + `/campaigns/${encodeURIComponent(id)}`, { ...options?.users }); } - async startCampaign(id: string, options?: { scheduledFor?: string; stopAt?: string }) { + startCampaign(id: string, options?: { scheduledFor?: string; stopAt?: string }) { this.validateServerSideAuth(); return this.post< { @@ -3423,7 +3699,11 @@ export class StreamChat { * * @return {Campaign[]} Campaigns */ - async queryCampaigns(filter: CampaignFilters, sort?: CampaignSort, options?: CampaignQueryOptions) { + async queryCampaigns( + filter: CampaignFilters, + sort?: CampaignSort, + options?: CampaignQueryOptions, + ) { this.validateServerSideAuth(); return await this.post< { @@ -3446,7 +3726,7 @@ export class StreamChat { * * @return {Campaign} Updated Campaign */ - async updateCampaign(id: string, params: Partial) { + updateCampaign(id: string, params: Partial) { this.validateServerSideAuth(); return this.put<{ campaign: CampaignResponse; @@ -3464,9 +3744,11 @@ export class StreamChat { * * @return {Promise} The Server Response */ - async deleteCampaign(id: string) { + deleteCampaign(id: string) { this.validateServerSideAuth(); - return this.delete(this.baseURL + `/campaigns/${encodeURIComponent(id)}`); + return this.delete( + this.baseURL + `/campaigns/${encodeURIComponent(id)}`, + ); } /** @@ -3476,9 +3758,11 @@ export class StreamChat { * * @return {Campaign} Stopped Campaign */ - async stopCampaign(id: string) { + stopCampaign(id: string) { this.validateServerSideAuth(); - return this.post<{ campaign: CampaignResponse }>(this.baseURL + `/campaigns/${encodeURIComponent(id)}/stop`); + return this.post<{ campaign: CampaignResponse }>( + this.baseURL + `/campaigns/${encodeURIComponent(id)}/stop`, + ); } /** @@ -3487,7 +3771,7 @@ export class StreamChat { * @param {string} url link * @return {OGAttachment} OG Attachment */ - async enrichURL(url: string) { + enrichURL(url: string) { return this.get(this.baseURL + `/og`, { url }); } @@ -3498,8 +3782,10 @@ export class StreamChat { * * @return {TaskStatus} The task status */ - async getTask(id: string) { - return this.get(`${this.baseURL}/tasks/${encodeURIComponent(id)}`); + getTask(id: string) { + return this.get( + `${this.baseURL}/tasks/${encodeURIComponent(id)}`, + ); } /** @@ -3511,10 +3797,13 @@ export class StreamChat { * @return {DeleteChannelsResponse} Result of the soft deletion, if server-side, it holds the task ID as well */ async deleteChannels(cids: string[], options: { hard_delete?: boolean } = {}) { - return await this.post(this.baseURL + `/channels/delete`, { - cids, - ...options, - }); + return await this.post( + this.baseURL + `/channels/delete`, + { + cids, + ...options, + }, + ); } /** @@ -3526,14 +3815,29 @@ export class StreamChat { * @return {TaskResponse} A task ID */ async deleteUsers(user_ids: string[], options: DeleteUserOptions = {}) { - if (typeof options.user !== 'undefined' && !['soft', 'hard', 'pruning'].includes(options.user)) { - throw new Error('Invalid delete user options. user must be one of [soft hard pruning]'); + if ( + typeof options.user !== 'undefined' && + !['soft', 'hard', 'pruning'].includes(options.user) + ) { + throw new Error( + 'Invalid delete user options. user must be one of [soft hard pruning]', + ); } - if (typeof options.conversations !== 'undefined' && !['soft', 'hard'].includes(options.conversations)) { - throw new Error('Invalid delete user options. conversations must be one of [soft hard]'); + if ( + typeof options.conversations !== 'undefined' && + !['soft', 'hard'].includes(options.conversations) + ) { + throw new Error( + 'Invalid delete user options. conversations must be one of [soft hard]', + ); } - if (typeof options.messages !== 'undefined' && !['soft', 'hard', 'pruning'].includes(options.messages)) { - throw new Error('Invalid delete user options. messages must be one of [soft hard pruning]'); + if ( + typeof options.messages !== 'undefined' && + !['soft', 'hard', 'pruning'].includes(options.messages) + ) { + throw new Error( + 'Invalid delete user options. messages must be one of [soft hard pruning]', + ); } return await this.post(this.baseURL + `/users/delete`, { user_ids, @@ -3553,9 +3857,12 @@ export class StreamChat { * @return {APIResponse & CreateImportResponse} An ImportTask */ async _createImportURL(filename: string) { - return await this.post(this.baseURL + `/import_urls`, { - filename, - }); + return await this.post( + this.baseURL + `/import_urls`, + { + filename, + }, + ); } /** @@ -3571,10 +3878,13 @@ export class StreamChat { * @return {APIResponse & CreateImportResponse} An ImportTask */ async _createImport(path: string, options: CreateImportOptions = { mode: 'upsert' }) { - return await this.post(this.baseURL + `/imports`, { - path, - ...options, - }); + return await this.post( + this.baseURL + `/imports`, + { + path, + ...options, + }, + ); } /** @@ -3590,7 +3900,9 @@ export class StreamChat { * @return {APIResponse & GetImportResponse} An ImportTask */ async _getImport(id: string) { - return await this.get(this.baseURL + `/imports/${encodeURIComponent(id)}`); + return await this.get( + this.baseURL + `/imports/${encodeURIComponent(id)}`, + ); } /** @@ -3606,7 +3918,10 @@ export class StreamChat { * @return {APIResponse & ListImportsResponse} An ImportTask */ async _listImports(options: ListImportsPaginationOptions) { - return await this.get(this.baseURL + `/imports`, options); + return await this.get( + this.baseURL + `/imports`, + options, + ); } /** @@ -3619,9 +3934,12 @@ export class StreamChat { * @return {APIResponse & PushProviderUpsertResponse} A push provider */ async upsertPushProvider(pushProvider: PushProviderConfig) { - return await this.post(this.baseURL + `/push_providers`, { - push_provider: pushProvider, - }); + return await this.post( + this.baseURL + `/push_providers`, + { + push_provider: pushProvider, + }, + ); } /** @@ -3635,7 +3953,8 @@ export class StreamChat { */ async deletePushProvider({ type, name }: PushProviderID) { return await this.delete( - this.baseURL + `/push_providers/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, + this.baseURL + + `/push_providers/${encodeURIComponent(type)}/${encodeURIComponent(name)}`, ); } @@ -3647,7 +3966,9 @@ export class StreamChat { * @return {APIResponse & PushProviderListResponse} A push provider */ async listPushProviders() { - return await this.get(this.baseURL + `/push_providers`); + return await this.get( + this.baseURL + `/push_providers`, + ); } /** @@ -3664,7 +3985,9 @@ export class StreamChat { * @return {APIResponse & MessageResponse} The message */ async commitMessage(id: string) { - return await this.post(this.baseURL + `/messages/${encodeURIComponent(id)}/commit`); + return await this.post( + this.baseURL + `/messages/${encodeURIComponent(id)}/commit`, + ); } /** @@ -3719,10 +4042,13 @@ export class StreamChat { partialPollObject: PartialPollUpdate, userId?: string, ): Promise { - return await this.patch(this.baseURL + `/polls/${encodeURIComponent(id)}`, { - ...partialPollObject, - ...(userId ? { user_id: userId } : {}), - }); + return await this.patch( + this.baseURL + `/polls/${encodeURIComponent(id)}`, + { + ...partialPollObject, + ...(userId ? { user_id: userId } : {}), + }, + ); } /** @@ -3732,9 +4058,12 @@ export class StreamChat { * @returns */ async deletePoll(id: string, userId?: string): Promise { - return await this.delete(this.baseURL + `/polls/${encodeURIComponent(id)}`, { - ...(userId ? { user_id: userId } : {}), - }); + return await this.delete( + this.baseURL + `/polls/${encodeURIComponent(id)}`, + { + ...(userId ? { user_id: userId } : {}), + }, + ); } /** @@ -3743,7 +4072,7 @@ export class StreamChat { * @param userId string The user id (only serverside) * @returns {APIResponse & UpdatePollAPIResponse} The poll */ - async closePoll(id: string, userId?: string): Promise { + closePoll(id: string, userId?: string): Promise { return this.partialUpdatePoll( id, { @@ -3781,7 +4110,8 @@ export class StreamChat { */ async getPollOption(pollId: string, optionId: string, userId?: string) { return await this.get( - this.baseURL + `/polls/${encodeURIComponent(pollId)}/options/${encodeURIComponent(optionId)}`, + this.baseURL + + `/polls/${encodeURIComponent(pollId)}/options/${encodeURIComponent(optionId)}`, userId ? { user_id: userId } : {}, ); } @@ -3812,7 +4142,8 @@ export class StreamChat { */ async deletePollOption(pollId: string, optionId: string, userId?: string) { return await this.delete( - this.baseURL + `/polls/${encodeURIComponent(pollId)}/options/${encodeURIComponent(optionId)}`, + this.baseURL + + `/polls/${encodeURIComponent(pollId)}/options/${encodeURIComponent(optionId)}`, userId ? { user_id: userId } : {}, ); } @@ -3825,9 +4156,15 @@ export class StreamChat { * @param userId string The user id (only serverside) * @returns {APIResponse & CastVoteAPIResponse} The poll vote */ - async castPollVote(messageId: string, pollId: string, vote: PollVoteData, userId?: string) { + async castPollVote( + messageId: string, + pollId: string, + vote: PollVoteData, + userId?: string, + ) { return await this.post( - this.baseURL + `/messages/${encodeURIComponent(messageId)}/polls/${encodeURIComponent(pollId)}/vote`, + this.baseURL + + `/messages/${encodeURIComponent(messageId)}/polls/${encodeURIComponent(pollId)}/vote`, { vote, ...(userId ? { user_id: userId } : {}), @@ -3842,7 +4179,7 @@ export class StreamChat { * @param answerText string The answer text * @param userId string The user id (only serverside) */ - async addPollAnswer(messageId: string, pollId: string, answerText: string, userId?: string) { + addPollAnswer(messageId: string, pollId: string, answerText: string, userId?: string) { return this.castPollVote( messageId, pollId, @@ -3853,7 +4190,12 @@ export class StreamChat { ); } - async removePollVote(messageId: string, pollId: string, voteId: string, userId?: string) { + async removePollVote( + messageId: string, + pollId: string, + voteId: string, + userId?: string, + ) { return await this.delete( this.baseURL + `/messages/${encodeURIComponent(messageId)}/polls/${encodeURIComponent(pollId)}/vote/${encodeURIComponent( @@ -3880,11 +4222,14 @@ export class StreamChat { userId?: string, ): Promise { const q = userId ? `?user_id=${userId}` : ''; - return await this.post(this.baseURL + `/polls/query${q}`, { - filter, - sort: normalizeQuerySort(sort), - ...options, - }); + return await this.post( + this.baseURL + `/polls/query${q}`, + { + filter, + sort: normalizeQuerySort(sort), + ...options, + }, + ); } /** @@ -3953,11 +4298,14 @@ export class StreamChat { sort: QueryMessageHistorySort = [], options: QueryMessageHistoryOptions = {}, ): Promise { - return await this.post(this.baseURL + '/messages/history', { - filter, - sort: normalizeQuerySort(sort), - ...options, - }); + return await this.post( + this.baseURL + '/messages/history', + { + filter, + sort: normalizeQuerySort(sort), + ...options, + }, + ); } /** @@ -3968,11 +4316,18 @@ export class StreamChat { * @param {string} reviewed_by user ID who reviewed the flagged message * @returns {APIResponse} */ - async updateFlags(message_ids: string[], reviewed_by: string, options: { user_id?: string } = {}) { - return await this.post(this.baseURL + '/automod/v1/moderation/update_flags', { - message_ids, - reviewed_by, - ...options, - }); + async updateFlags( + message_ids: string[], + reviewed_by: string, + options: { user_id?: string } = {}, + ) { + return await this.post( + this.baseURL + '/automod/v1/moderation/update_flags', + { + message_ids, + reviewed_by, + ...options, + }, + ); } } diff --git a/src/client_state.ts b/src/client_state.ts index 71f0080e9..2bcf1a3cb 100644 --- a/src/client_state.ts +++ b/src/client_state.ts @@ -1,5 +1,5 @@ -import { UserResponse } from './types'; -import { StreamChat } from './client'; +import type { UserResponse } from './types'; +import type { StreamChat } from './client'; /** * ClientState - A container class for the client state. diff --git a/src/connection.ts b/src/connection.ts index ebf492553..fa94aae8e 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -1,24 +1,30 @@ import WebSocket from 'isomorphic-ws'; import { + addConnectionEventListeners, chatCodes, convertErrorToJson, - sleep, - retryInterval, randomId, removeConnectionEventListeners, - addConnectionEventListeners, + retryInterval, + sleep, } from './utils'; -import { buildWsFatalInsight, buildWsSuccessAfterFailureInsight, postInsights } from './insights'; -import { ConnectAPIResponse, ConnectionOpen, UR, LogLevel } from './types'; -import { StreamChat } from './client'; -import { APIError } from './errors'; +import { + buildWsFatalInsight, + buildWsSuccessAfterFailureInsight, + postInsights, +} from './insights'; +import type { ConnectAPIResponse, ConnectionOpen, LogLevel, UR } from './types'; +import type { StreamChat } from './client'; +import type { APIError } from './errors'; // Type guards to check WebSocket error type -const isCloseEvent = (res: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent): res is WebSocket.CloseEvent => - (res as WebSocket.CloseEvent).code !== undefined; +const isCloseEvent = ( + res: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent, +): res is WebSocket.CloseEvent => (res as WebSocket.CloseEvent).code !== undefined; -const isErrorEvent = (res: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent): res is WebSocket.ErrorEvent => - (res as WebSocket.ErrorEvent).error !== undefined; +const isErrorEvent = ( + res: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent, +): res is WebSocket.ErrorEvent => (res as WebSocket.ErrorEvent).error !== undefined; /** * StableWSConnection - A WS connection that reconnects upon failure. @@ -55,7 +61,11 @@ export class StableWSConnection { connectionCheckTimeout: number; connectionCheckTimeoutRef?: NodeJS.Timeout; rejectPromise?: ( - reason?: Error & { code?: string | number; isWSFailure?: boolean; StatusCode?: string | number }, + reason?: Error & { + code?: string | number; + isWSFailure?: boolean; + StatusCode?: string | number; + }, ) => void; requestID: string | undefined; resolvePromise?: (value: ConnectionOpen) => void; @@ -104,7 +114,9 @@ export class StableWSConnection { */ async connect(timeout = 15000) { if (this.isConnecting) { - throw Error(`You've called connect twice, can only attempt 1 connection at the time`); + throw Error( + `You've called connect twice, can only attempt 1 connection at the time`, + ); } this.isDisconnected = false; @@ -122,7 +134,9 @@ export class StableWSConnection { const e = error as APIError; if (e.code === chatCodes.TOKEN_EXPIRED && !this.client.tokenManager.isStatic()) { - this._log('connect() - WS failure due to expired token, so going to try to reload token and reconnect'); + this._log( + 'connect() - WS failure due to expired token, so going to try to reload token and reconnect', + ); this._reconnect({ refreshToken: true }); } else if (!e.isWSFailure) { // API rejected the connection and we should not retry @@ -145,7 +159,7 @@ export class StableWSConnection { * the default 15s timeout allows between 2~3 tries * @param timeout duration(ms) */ - async _waitForHealthy(timeout = 15000) { + _waitForHealthy(timeout = 15000) { return Promise.race([ (async () => { const interval = 50; // ms @@ -235,7 +249,10 @@ export class StableWSConnection { if (ws && ws.close && ws.readyState === ws.OPEN) { isClosedPromise = new Promise((resolve) => { const onclose = (event: WebSocket.CloseEvent) => { - this._log(`disconnect() - resolving isClosedPromise ${event ? 'with' : 'without'} close frame`, { event }); + this._log( + `disconnect() - resolving isClosedPromise ${event ? 'with' : 'without'} close frame`, + { event }, + ); resolve(); }; @@ -245,9 +262,14 @@ export class StableWSConnection { setTimeout(onclose, timeout != null ? timeout : 1000); }); - this._log(`disconnect() - Manually closed connection by calling client.disconnect()`); + this._log( + `disconnect() - Manually closed connection by calling client.disconnect()`, + ); - ws.close(chatCodes.WS_CLOSED_SUCCESS, 'Manually closed connection by calling client.disconnect()'); + ws.close( + chatCodes.WS_CLOSED_SUCCESS, + 'Manually closed connection by calling client.disconnect()', + ); } else { this._log(`disconnect() - ws connection doesn't exist or it is already closed.`); isClosedPromise = Promise.resolve(); @@ -264,7 +286,11 @@ export class StableWSConnection { * @return {ConnectAPIResponse} Promise that completes once the first health check message is received */ async _connect() { - if (this.isConnecting || (this.isDisconnected && this.client.options.enableWSFallback)) return; // simply ignore _connect if it's currently trying to connect + if ( + this.isConnecting || + (this.isDisconnected && this.client.options.enableWSFallback) + ) + return; // simply ignore _connect if it's currently trying to connect this.isConnecting = true; this.requestID = randomId(); this.client.insightMetrics.connectionStartTimestamp = new Date().getTime(); @@ -285,7 +311,10 @@ export class StableWSConnection { this._setupConnectionPromise(); const wsURL = this._buildUrl(); - this._log(`_connect() - Connecting to ${wsURL}`, { wsURL, requestID: this.requestID }); + this._log(`_connect() - Connecting to ${wsURL}`, { + wsURL, + requestID: this.requestID, + }); this.ws = new WebSocket(wsURL); this.ws.onopen = this.onopen.bind(this, this.wsID); this.ws.onclose = this.onclose.bind(this, this.wsID); @@ -296,10 +325,13 @@ export class StableWSConnection { if (response) { this.connectionID = response.connection_id; - if (this.client.insightMetrics.wsConsecutiveFailures > 0 && this.client.options.enableInsights) { + if ( + this.client.insightMetrics.wsConsecutiveFailures > 0 && + this.client.options.enableInsights + ) { postInsights( 'ws_success_after_failure', - buildWsSuccessAfterFailureInsight((this as unknown) as StableWSConnection), + buildWsSuccessAfterFailureInsight(this as unknown as StableWSConnection), ); this.client.insightMetrics.wsConsecutiveFailures = 0; } @@ -314,7 +346,7 @@ export class StableWSConnection { this.client.insightMetrics.wsTotalFailures++; const insights = buildWsFatalInsight( - (this as unknown) as StableWSConnection, + this as unknown as StableWSConnection, convertErrorToJson(error as Error), ); postInsights?.('ws_fatal', insights); @@ -331,7 +363,9 @@ export class StableWSConnection { * - `interval` {int} number of ms that function should wait before reconnecting * - `refreshToken` {boolean} reload/refresh user token be refreshed before attempting reconnection. */ - async _reconnect(options: { interval?: number; refreshToken?: boolean } = {}): Promise { + async _reconnect( + options: { interval?: number; refreshToken?: boolean } = {}, + ): Promise { this._log('_reconnect() - Initiating the reconnect'); // only allow 1 connection at the time @@ -381,8 +415,13 @@ export class StableWSConnection { } catch (error: any) { this.isHealthy = false; this.consecutiveFailures += 1; - if (error.code === chatCodes.TOKEN_EXPIRED && !this.client.tokenManager.isStatic()) { - this._log('_reconnect() - WS failure due to expired token, so going to try to reload token and reconnect'); + if ( + error.code === chatCodes.TOKEN_EXPIRED && + !this.client.tokenManager.isStatic() + ) { + this._log( + '_reconnect() - WS failure due to expired token, so going to try to reload token and reconnect', + ); return this._reconnect({ refreshToken: true }); } @@ -413,7 +452,9 @@ export class StableWSConnection { // We check this.isHealthy, not sure if it's always // smart to create a new WS connection if the old one is still up and running. // it's possible we didn't miss any messages, so this process is just expensive and not needed. - this._log(`onlineStatusChanged() - Status changing to online. isHealthy: ${this.isHealthy}`); + this._log( + `onlineStatusChanged() - Status changing to online. isHealthy: ${this.isHealthy}`, + ); if (!this.isHealthy) { this._reconnect({ interval: 10 }); } @@ -465,7 +506,9 @@ export class StableWSConnection { if (event.code === chatCodes.WS_CLOSED_SUCCESS) { // this is a permanent error raised by stream.. // usually caused by invalid auth details - const error = new Error(`WS connection reject with error ${event.reason}`) as Error & WebSocket.CloseEvent; + const error = new Error( + `WS connection reject with error ${event.reason}`, + ) as Error & WebSocket.CloseEvent; error.reason = event.reason; error.code = event.code; @@ -531,7 +574,10 @@ export class StableWSConnection { * _errorFromWSEvent - Creates an error object for the WS event * */ - _errorFromWSEvent = (event: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent, isWSFailure = true) => { + _errorFromWSEvent = ( + event: WebSocket.CloseEvent | WebSocket.Data | WebSocket.ErrorEvent, + isWSFailure = true, + ) => { let code; let statusCode; let message; @@ -550,7 +596,9 @@ export class StableWSConnection { // Keeping this `warn` level log, to avoid cluttering of error logs from ws failures. this._log(`_errorFromWSEvent() - WS failed with code ${code}`, { event }, 'warn'); - const error = new Error(`WS failed with code ${code} and reason - ${message}`) as Error & { + const error = new Error( + `WS failed with code ${code} and reason - ${message}`, + ) as Error & { code?: string | number; isWSFailure?: boolean; StatusCode?: string | number; @@ -627,7 +675,10 @@ export class StableWSConnection { this.connectionCheckTimeoutRef = setTimeout(() => { const now = new Date(); - if (this.lastEvent && now.getTime() - this.lastEvent.getTime() > this.connectionCheckTimeout) { + if ( + this.lastEvent && + now.getTime() - this.lastEvent.getTime() > this.connectionCheckTimeout + ) { this._log('scheduleConnectionCheck - going to reconnect'); this._setHealth(false); this._reconnect(); diff --git a/src/connection_fallback.ts b/src/connection_fallback.ts index c7e8010fc..c0552b1a1 100644 --- a/src/connection_fallback.ts +++ b/src/connection_fallback.ts @@ -1,8 +1,14 @@ -import axios, { AxiosRequestConfig, CancelTokenSource } from 'axios'; -import { StreamChat } from './client'; -import { addConnectionEventListeners, removeConnectionEventListeners, retryInterval, sleep } from './utils'; +import type { AxiosRequestConfig, CancelTokenSource } from 'axios'; +import axios from 'axios'; +import type { StreamChat } from './client'; +import { + addConnectionEventListeners, + removeConnectionEventListeners, + retryInterval, + sleep, +} from './utils'; import { isAPIError, isConnectionIDError, isErrorRetryable } from './errors'; -import { ConnectionOpen, Event, UR, LogLevel } from './types'; +import type { ConnectionOpen, Event, LogLevel, UR } from './types'; export enum ConnectionState { Closed = 'CLOSED', @@ -28,14 +34,20 @@ export class WSConnectionFallback { } _log(msg: string, extra: UR = {}, level: LogLevel = 'info') { - this.client.logger(level, 'WSConnectionFallback:' + msg, { tags: ['connection_fallback', 'connection'], ...extra }); + this.client.logger(level, 'WSConnectionFallback:' + msg, { + tags: ['connection_fallback', 'connection'], + ...extra, + }); } _setState(state: ConnectionState) { this._log(`_setState() - ${state}`); // transition from connecting => connected - if (this.state === ConnectionState.Connecting && state === ConnectionState.Connected) { + if ( + this.state === ConnectionState.Connecting && + state === ConnectionState.Connected + ) { this.client.dispatchEvent({ type: 'connection.changed', online: true }); } @@ -63,7 +75,11 @@ export class WSConnectionFallback { }; /** @private */ - _req = async (params: UR, config: AxiosRequestConfig, retry: boolean): Promise => { + _req = async ( + params: UR, + config: AxiosRequestConfig, + retry: boolean, + ): Promise => { if (!this.cancelToken && !params.close) { this.cancelToken = axios.CancelToken.source(); } @@ -159,7 +175,7 @@ export class WSConnectionFallback { this._setState(ConnectionState.Connected); this.connectionID = event.connection_id; - // @ts-expect-error + // @ts-expect-error type mismatch this.client.dispatchEvent(event); this._poll(); if (reconnect) { @@ -175,9 +191,7 @@ export class WSConnectionFallback { /** * isHealthy checks if there is a connectionID and connection is in Connected state */ - isHealthy = () => { - return !!this.connectionID && this.state === ConnectionState.Connected; - }; + isHealthy = () => !!this.connectionID && this.state === ConnectionState.Connected; disconnect = async (timeout = 2000) => { removeConnectionEventListeners(this._onlineStatusChanged); diff --git a/src/custom_types.ts b/src/custom_types.ts index 62eb9a384..29b178bc9 100644 --- a/src/custom_types.ts +++ b/src/custom_types.ts @@ -1,5 +1,3 @@ -/* eslint-disable @typescript-eslint/no-empty-interface */ - export interface CustomAttachmentData {} export interface CustomChannelData {} export interface CustomCommandData {} diff --git a/src/errors.ts b/src/errors.ts index cdaa2c9d6..3688a656c 100644 --- a/src/errors.ts +++ b/src/errors.ts @@ -1,5 +1,5 @@ -import { AxiosResponse } from 'axios'; -import { APIErrorResponse } from './types'; +import type { AxiosResponse } from 'axios'; +import type { APIErrorResponse } from './types'; export const APIErrorCodes: Record = { '-1': { name: 'InternalSystemError', retryable: true }, @@ -31,7 +31,11 @@ export const APIErrorCodes: Record '99': { name: 'AppSuspendedError', retryable: false }, }; -export type APIError = Error & { code: number; isWSFailure?: boolean; StatusCode?: number }; +export type APIError = Error & { + code: number; + isWSFailure?: boolean; + StatusCode?: number; +}; export function isAPIError(error: Error): error is APIError { return (error as APIError).code !== undefined; @@ -60,6 +64,8 @@ export function isWSFailure(err: APIError): boolean { } } -export function isErrorResponse(res: AxiosResponse): res is AxiosResponse { +export function isErrorResponse( + res: AxiosResponse, +): res is AxiosResponse { return !res.status || res.status < 200 || 300 <= res.status; } diff --git a/src/index.ts b/src/index.ts index d0d7fb19e..d414c5883 100644 --- a/src/index.ts +++ b/src/index.ts @@ -16,10 +16,21 @@ export * from './segment'; export * from './signing'; export * from './store'; export { Thread } from './thread'; -export type { ThreadState, ThreadReadState, ThreadRepliesPagination, ThreadUserReadState } from './thread'; +export type { + ThreadState, + ThreadReadState, + ThreadRepliesPagination, + ThreadUserReadState, +} from './thread'; export * from './thread_manager'; export * from './token_manager'; export * from './types'; export * from './channel_manager'; export * from './custom_types'; -export { isOwnUser, chatCodes, logChatPromiseExecution, formatMessage, promoteChannel } from './utils'; +export { + isOwnUser, + chatCodes, + logChatPromiseExecution, + formatMessage, + promoteChannel, +} from './utils'; diff --git a/src/insights.ts b/src/insights.ts index 4549effe8..bc11790d3 100644 --- a/src/insights.ts +++ b/src/insights.ts @@ -1,5 +1,5 @@ import axios from 'axios'; -import { StableWSConnection } from './connection'; +import type { StableWSConnection } from './connection'; import { randomId, sleep } from './utils'; export type InsightTypes = 'ws_fatal' | 'ws_success_after_failure' | 'http_hi_failed'; @@ -24,11 +24,17 @@ export class InsightMetrics { * @param insightType * @param insights */ -export const postInsights = async (insightType: InsightTypes, insights: Record) => { +export const postInsights = async ( + insightType: InsightTypes, + insights: Record, +) => { const maxAttempts = 3; for (let i = 0; i < maxAttempts; i++) { try { - await axios.post(`https://chat-insights.getstream.io/insights/${insightType}`, insights); + await axios.post( + `https://chat-insights.getstream.io/insights/${insightType}`, + insights, + ); } catch (e) { await sleep((i + 1) * 3000); continue; @@ -37,7 +43,10 @@ export const postInsights = async (insightType: InsightTypes, insights: Record) { +export function buildWsFatalInsight( + connection: StableWSConnection, + event: Record, +) { return { ...event, ...buildWsBaseInsight(connection), diff --git a/src/moderation.ts b/src/moderation.ts index 40b0f9fd8..2c510ce70 100644 --- a/src/moderation.ts +++ b/src/moderation.ts @@ -1,26 +1,26 @@ -import { +import type { APIResponse, - ModerationConfig, + CustomCheckFlag, GetConfigResponse, + GetUserModerationReportOptions, GetUserModerationReportResponse, + ModerationConfig, + ModerationFlagOptions, + ModerationMuteOptions, MuteUserResponse, + Pager, + QueryConfigsResponse, + QueryModerationConfigsFilters, + QueryModerationConfigsSort, ReviewQueueFilters, + ReviewQueueItem, ReviewQueuePaginationOptions, ReviewQueueResponse, ReviewQueueSort, - UpsertConfigResponse, - ModerationFlagOptions, - ModerationMuteOptions, - GetUserModerationReportOptions, SubmitActionOptions, - QueryModerationConfigsFilters, - QueryModerationConfigsSort, - Pager, - CustomCheckFlag, - ReviewQueueItem, - QueryConfigsResponse, + UpsertConfigResponse, } from './types'; -import { StreamChat } from './client'; +import type { StreamChat } from './client'; import { normalizeQuerySort } from './utils'; export const MODERATION_ENTITY_TYPES = { @@ -46,7 +46,7 @@ export class Moderation { * @param {Object} options.custom Additional data to be stored with the flag * @returns */ - async flagUser(flaggedUserID: string, reason: string, options: ModerationFlagOptions = {}) { + flagUser(flaggedUserID: string, reason: string, options: ModerationFlagOptions = {}) { return this.flag(MODERATION_ENTITY_TYPES.user, flaggedUserID, '', reason, options); } @@ -60,7 +60,7 @@ export class Moderation { * @param {Object} options.custom Additional data to be stored with the flag * @returns */ - async flagMessage(messageID: string, reason: string, options: ModerationFlagOptions = {}) { + flagMessage(messageID: string, reason: string, options: ModerationFlagOptions = {}) { return this.flag(MODERATION_ENTITY_TYPES.message, messageID, '', reason, options); } @@ -84,13 +84,16 @@ export class Moderation { reason: string, options: ModerationFlagOptions = {}, ) { - return await this.client.post<{ item_id: string } & APIResponse>(this.client.baseURL + '/api/v2/moderation/flag', { - entity_type: entityType, - entity_id: entityId, - entity_creator_id: entityCreatorID, - reason, - ...options, - }); + return await this.client.post<{ item_id: string } & APIResponse>( + this.client.baseURL + '/api/v2/moderation/flag', + { + entity_type: entityType, + entity_id: entityId, + entity_creator_id: entityCreatorID, + reason, + ...options, + }, + ); } /** @@ -102,10 +105,13 @@ export class Moderation { * @returns */ async muteUser(targetID: string, options: ModerationMuteOptions = {}) { - return await this.client.post(this.client.baseURL + '/api/v2/moderation/mute', { - target_ids: [targetID], - ...options, - }); + return await this.client.post( + this.client.baseURL + '/api/v2/moderation/mute', + { + target_ids: [targetID], + ...options, + }, + ); } /** @@ -138,7 +144,10 @@ export class Moderation { * @param {boolean} options.include_user_blocks Include user blocks * @param {boolean} options.include_user_mutes Include user mutes */ - async getUserModerationReport(userID: string, options: GetUserModerationReportOptions = {}) { + async getUserModerationReport( + userID: string, + options: GetUserModerationReportOptions = {}, + ) { return await this.client.get( this.client.baseURL + `/api/v2/moderation/user_report`, { @@ -159,11 +168,14 @@ export class Moderation { sort: ReviewQueueSort = [], options: ReviewQueuePaginationOptions = {}, ) { - return await this.client.post(this.client.baseURL + '/api/v2/moderation/review_queue', { - filter: filterConditions, - sort: normalizeQuerySort(sort), - ...options, - }); + return await this.client.post( + this.client.baseURL + '/api/v2/moderation/review_queue', + { + filter: filterConditions, + sort: normalizeQuerySort(sort), + ...options, + }, + ); } /** @@ -171,7 +183,10 @@ export class Moderation { * @param {Object} config Moderation config to be upserted */ async upsertConfig(config: ModerationConfig) { - return await this.client.post(this.client.baseURL + '/api/v2/moderation/config', config); + return await this.client.post( + this.client.baseURL + '/api/v2/moderation/config', + config, + ); } /** @@ -179,11 +194,17 @@ export class Moderation { * @param {string} key Key for which moderation config is to be fetched */ async getConfig(key: string, data?: { team?: string }) { - return await this.client.get(this.client.baseURL + '/api/v2/moderation/config/' + key, data); + return await this.client.get( + this.client.baseURL + '/api/v2/moderation/config/' + key, + data, + ); } async deleteConfig(key: string, data?: { team?: string }) { - return await this.client.delete(this.client.baseURL + '/api/v2/moderation/config/' + key, data); + return await this.client.delete( + this.client.baseURL + '/api/v2/moderation/config/' + key, + data, + ); } /** @@ -197,14 +218,21 @@ export class Moderation { sort: QueryModerationConfigsSort, options: Pager = {}, ) { - return await this.client.post(this.client.baseURL + '/api/v2/moderation/configs', { - filter: filterConditions, - sort, - ...options, - }); + return await this.client.post( + this.client.baseURL + '/api/v2/moderation/configs', + { + filter: filterConditions, + sort, + ...options, + }, + ); } - async submitAction(actionType: string, itemID: string, options: SubmitActionOptions = {}) { + async submitAction( + actionType: string, + itemID: string, + options: SubmitActionOptions = {}, + ) { return await this.client.post<{ item_id: string } & APIResponse>( this.client.baseURL + '/api/v2/moderation/submit_action', { @@ -277,16 +305,15 @@ export class Moderation { }, flags: CustomCheckFlag[], ) { - return await this.client.post<{ id: string; item: ReviewQueueItem; status: string } & APIResponse>( - this.client.baseURL + `/api/v2/moderation/custom_check`, - { - entity_type: entityType, - entity_id: entityID, - entity_creator_id: entityCreatorID, - moderation_payload: moderationPayload, - flags, - }, - ); + return await this.client.post< + { id: string; item: ReviewQueueItem; status: string } & APIResponse + >(this.client.baseURL + `/api/v2/moderation/custom_check`, { + entity_type: entityType, + entity_id: entityID, + entity_creator_id: entityCreatorID, + moderation_payload: moderationPayload, + flags, + }); } /** @@ -296,6 +323,12 @@ export class Moderation { * @returns */ async addCustomMessageFlags(messageID: string, flags: CustomCheckFlag[]) { - return await this.addCustomFlags(MODERATION_ENTITY_TYPES.message, messageID, '', {}, flags); + return await this.addCustomFlags( + MODERATION_ENTITY_TYPES.message, + messageID, + '', + {}, + flags, + ); } } diff --git a/src/permissions.ts b/src/permissions.ts index 4bc530160..a46332776 100644 --- a/src/permissions.ts +++ b/src/permissions.ts @@ -1,4 +1,4 @@ -import { PermissionObject } from './types'; +import type { PermissionObject } from './types'; type RequiredPermissionObject = Required; @@ -37,12 +37,33 @@ export class Permission { } // deprecated -export const AllowAll = new Permission('Allow all', MaxPriority, AnyResource, AnyRole, false, Allow); +export const AllowAll = new Permission( + 'Allow all', + MaxPriority, + AnyResource, + AnyRole, + false, + Allow, +); // deprecated -export const DenyAll = new Permission('Deny all', MinPriority, AnyResource, AnyRole, false, Deny); +export const DenyAll = new Permission( + 'Deny all', + MinPriority, + AnyResource, + AnyRole, + false, + Deny, +); -export type Role = 'admin' | 'user' | 'guest' | 'anonymous' | 'channel_member' | 'channel_moderator' | (string & {}); +export type Role = + | 'admin' + | 'user' + | 'guest' + | 'anonymous' + | 'channel_member' + | 'channel_moderator' + | (string & {}); export const BuiltinRoles = { Admin: 'admin', diff --git a/src/poll.ts b/src/poll.ts index b75ff0565..93480c588 100644 --- a/src/poll.ts +++ b/src/poll.ts @@ -48,12 +48,17 @@ type PollVoteCastedRemoved = PollVoteEvent & { }; const isPollUpdatedEvent = (e: Event): e is PollUpdatedEvent => e.type === 'poll.updated'; -const isPollClosedEventEvent = (e: Event): e is PollClosedEvent => e.type === 'poll.closed'; -const isPollVoteCastedEvent = (e: Event): e is PollVoteCastedEvent => e.type === 'poll.vote_casted'; -const isPollVoteChangedEvent = (e: Event): e is PollVoteCastedChanged => e.type === 'poll.vote_changed'; -const isPollVoteRemovedEvent = (e: Event): e is PollVoteCastedRemoved => e.type === 'poll.vote_removed'; - -export const isVoteAnswer = (vote: PollVote | PollAnswer): vote is PollAnswer => !!(vote as PollAnswer)?.answer_text; +const isPollClosedEventEvent = (e: Event): e is PollClosedEvent => + e.type === 'poll.closed'; +const isPollVoteCastedEvent = (e: Event): e is PollVoteCastedEvent => + e.type === 'poll.vote_casted'; +const isPollVoteChangedEvent = (e: Event): e is PollVoteCastedChanged => + e.type === 'poll.vote_changed'; +const isPollVoteRemovedEvent = (e: Event): e is PollVoteCastedRemoved => + e.type === 'poll.vote_removed'; + +export const isVoteAnswer = (vote: PollVote | PollAnswer): vote is PollAnswer => + !!(vote as PollAnswer)?.answer_text; export type PollAnswersQueryParams = { filter?: QueryVotesFilters; @@ -97,7 +102,10 @@ export class Poll { private getInitialStateFromPollResponse = (poll: PollInitOptions['poll']) => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { own_votes, id, ...pollResponseForState } = poll; - const { ownAnswer, ownVotes } = own_votes?.reduce<{ ownVotes: PollVote[]; ownAnswer?: PollAnswer }>( + const { ownAnswer, ownVotes } = own_votes?.reduce<{ + ownVotes: PollVote[]; + ownAnswer?: PollAnswer; + }>( (acc, voteOrAnswer) => { if (isVoteAnswer(voteOrAnswer)) { acc.ownAnswer = voteOrAnswer; @@ -133,15 +141,17 @@ export class Poll { if (!isPollUpdatedEvent(event)) return; // eslint-disable-next-line @typescript-eslint/no-unused-vars const { id, ...pollData } = extractPollData(event.poll); - // @ts-ignore + // @ts-expect-error type mismatch this.state.partialNext({ ...pollData, lastActivityAt: new Date(event.created_at) }); }; public handlePollClosed = (event: Event) => { if (event.poll?.id && event.poll.id !== this.id) return; if (!isPollClosedEventEvent(event)) return; - // @ts-ignore - this.state.partialNext({ is_closed: true, lastActivityAt: new Date(event.created_at) }); + this.state.partialNext({ + is_closed: true, + lastActivityAt: new Date(event.created_at), + }); }; public handleVoteCasted = (event: Event) => { @@ -169,7 +179,6 @@ export class Poll { } const pollEnrichData = extractPollEnrichedData(event.poll); - // @ts-ignore this.state.partialNext({ ...pollEnrichData, latest_answers: latestAnswers, @@ -193,22 +202,27 @@ export class Poll { if (isOwnVote) { if (isVoteAnswer(event.poll_vote)) { - latestAnswers = [event.poll_vote, ...latestAnswers.filter((answer) => answer.id !== event.poll_vote.id)]; + latestAnswers = [ + event.poll_vote, + ...latestAnswers.filter((answer) => answer.id !== event.poll_vote.id), + ]; ownAnswer = event.poll_vote; } else if (event.poll_vote.option_id) { if (event.poll.enforce_unique_votes) { ownVotesByOptionId = { [event.poll_vote.option_id]: event.poll_vote }; } else { - ownVotesByOptionId = Object.entries(ownVotesByOptionId).reduce>( - (acc, [optionId, vote]) => { - if (optionId !== event.poll_vote.option_id && vote.id === event.poll_vote.id) { - return acc; - } - acc[optionId] = vote; + ownVotesByOptionId = Object.entries(ownVotesByOptionId).reduce< + Record + >((acc, [optionId, vote]) => { + if ( + optionId !== event.poll_vote.option_id && + vote.id === event.poll_vote.id + ) { return acc; - }, - {}, - ); + } + acc[optionId] = vote; + return acc; + }, {}); ownVotesByOptionId[event.poll_vote.option_id] = event.poll_vote; } @@ -224,7 +238,6 @@ export class Poll { } const pollEnrichData = extractPollEnrichedData(event.poll); - // @ts-ignore this.state.partialNext({ ...pollEnrichData, latest_answers: latestAnswers, @@ -258,7 +271,6 @@ export class Poll { } const pollEnrichData = extractPollEnrichedData(event.poll); - // @ts-ignore this.state.partialNext({ ...pollEnrichData, latest_answers: latestAnswers, @@ -271,50 +283,44 @@ export class Poll { query = async (id: string) => { const { poll } = await this.client.getPoll(id); - // @ts-ignore this.state.partialNext({ ...poll, lastActivityAt: new Date() }); return poll; }; - update = async (data: Exclude) => { - return await this.client.updatePoll({ ...data, id: this.id }); - }; + update = async (data: Exclude) => + await this.client.updatePoll({ ...data, id: this.id }); - partialUpdate = async (partialPollObject: PartialPollUpdate) => { - return await this.client.partialUpdatePoll(this.id as string, partialPollObject); - }; + partialUpdate = async (partialPollObject: PartialPollUpdate) => + await this.client.partialUpdatePoll(this.id as string, partialPollObject); - close = async () => { - return await this.client.closePoll(this.id as string); - }; + close = async () => await this.client.closePoll(this.id as string); - delete = async () => { - return await this.client.deletePoll(this.id as string); - }; + delete = async () => await this.client.deletePoll(this.id as string); - createOption = async (option: PollOptionData) => { - return await this.client.createPollOption(this.id as string, option); - }; + createOption = async (option: PollOptionData) => + await this.client.createPollOption(this.id as string, option); - updateOption = async (option: PollOptionData) => { - return await this.client.updatePollOption(this.id as string, option); - }; + updateOption = async (option: PollOptionData) => + await this.client.updatePollOption(this.id as string, option); - deleteOption = async (optionId: string) => { - return await this.client.deletePollOption(this.id as string, optionId); - }; + deleteOption = async (optionId: string) => + await this.client.deletePollOption(this.id as string, optionId); castVote = async (optionId: string, messageId: string) => { const { max_votes_allowed, ownVotesByOptionId } = this.data; - const reachedVoteLimit = max_votes_allowed && max_votes_allowed === Object.keys(ownVotesByOptionId).length; + const reachedVoteLimit = + max_votes_allowed && max_votes_allowed === Object.keys(ownVotesByOptionId).length; if (reachedVoteLimit) { let oldestVote = Object.values(ownVotesByOptionId)[0]; Object.values(ownVotesByOptionId) .slice(1) .forEach((vote) => { - if (!oldestVote?.created_at || new Date(vote.created_at) < new Date(oldestVote.created_at)) { + if ( + !oldestVote?.created_at || + new Date(vote.created_at) < new Date(oldestVote.created_at) + ) { oldestVote = vote; } }); @@ -322,28 +328,35 @@ export class Poll { await this.removeVote(oldestVote.id, messageId); } } - return await this.client.castPollVote(messageId, this.id as string, { option_id: optionId }); - }; - - removeVote = async (voteId: string, messageId: string) => { - return await this.client.removePollVote(messageId, this.id as string, voteId); - }; - - addAnswer = async (answerText: string, messageId: string) => { - return await this.client.addPollAnswer(messageId, this.id as string, answerText); - }; - - removeAnswer = async (answerId: string, messageId: string) => { - return await this.client.removePollVote(messageId, this.id as string, answerId); - }; - - queryAnswers = async (params: PollAnswersQueryParams) => { - return await this.client.queryPollAnswers(this.id as string, params.filter, params.sort, params.options); + return await this.client.castPollVote(messageId, this.id as string, { + option_id: optionId, + }); }; - queryOptionVotes = async (params: PollOptionVotesQueryParams) => { - return await this.client.queryPollVotes(this.id as string, params.filter, params.sort, params.options); - }; + removeVote = async (voteId: string, messageId: string) => + await this.client.removePollVote(messageId, this.id as string, voteId); + + addAnswer = async (answerText: string, messageId: string) => + await this.client.addPollAnswer(messageId, this.id as string, answerText); + + removeAnswer = async (answerId: string, messageId: string) => + await this.client.removePollVote(messageId, this.id as string, answerId); + + queryAnswers = async (params: PollAnswersQueryParams) => + await this.client.queryPollAnswers( + this.id as string, + params.filter, + params.sort, + params.options, + ); + + queryOptionVotes = async (params: PollOptionVotesQueryParams) => + await this.client.queryPollVotes( + this.id as string, + params.filter, + params.sort, + params.options, + ); } function getMaxVotedOptionIds(voteCountsByOption: PollResponse['vote_counts_by_option']) { diff --git a/src/poll_manager.ts b/src/poll_manager.ts index d81f8ee21..c5b5447e2 100644 --- a/src/poll_manager.ts +++ b/src/poll_manager.ts @@ -8,7 +8,7 @@ import type { QueryPollsOptions, } from './types'; import { Poll } from './poll'; -import { FormatMessageResponse } from './types'; +import type { FormatMessageResponse } from './types'; import { formatMessage } from './utils'; export class PollManager { @@ -29,9 +29,7 @@ export class PollManager { return this.pollCache; } - public fromState = (id: string) => { - return this.pollCache.get(id); - }; + public fromState = (id: string) => this.pollCache.get(id); public registerSubscriptions = () => { if (this.unsubscribeFunctions.size) { @@ -74,7 +72,11 @@ export class PollManager { return this.fromState(id); }; - public queryPolls = async (filter: QueryPollsFilters, sort: PollSort = [], options: QueryPollsOptions = {}) => { + public queryPolls = async ( + filter: QueryPollsFilters, + sort: PollSort = [], + options: QueryPollsOptions = {}, + ) => { const { polls, next } = await this.client.queryPolls(filter, sort, options); const pollInstances = polls.map((poll) => { @@ -89,7 +91,10 @@ export class PollManager { }; }; - public hydratePollCache = (messages: FormatMessageResponse[] | MessageResponse[], overwriteState?: boolean) => { + public hydratePollCache = ( + messages: FormatMessageResponse[] | MessageResponse[], + overwriteState?: boolean, + ) => { for (const message of messages) { if (!message.poll) { continue; @@ -99,7 +104,10 @@ export class PollManager { } }; - private setOrOverwriteInCache = (pollResponse: PollResponse, overwriteState?: boolean) => { + private setOrOverwriteInCache = ( + pollResponse: PollResponse, + overwriteState?: boolean, + ) => { if (!this.client._cacheEnabled()) { return; } @@ -112,53 +120,47 @@ export class PollManager { } }; - private subscribePollUpdated = () => { - return this.client.on('poll.updated', (event) => { + private subscribePollUpdated = () => + this.client.on('poll.updated', (event) => { if (event.poll?.id) { this.fromState(event.poll.id)?.handlePollUpdated(event); } }).unsubscribe; - }; - private subscribePollClosed = () => { - return this.client.on('poll.closed', (event) => { + private subscribePollClosed = () => + this.client.on('poll.closed', (event) => { if (event.poll?.id) { this.fromState(event.poll.id)?.handlePollClosed(event); } }).unsubscribe; - }; - private subscribeVoteCasted = () => { - return this.client.on('poll.vote_casted', (event) => { + private subscribeVoteCasted = () => + this.client.on('poll.vote_casted', (event) => { if (event.poll?.id) { this.fromState(event.poll.id)?.handleVoteCasted(event); } }).unsubscribe; - }; - private subscribeVoteChanged = () => { - return this.client.on('poll.vote_changed', (event) => { + private subscribeVoteChanged = () => + this.client.on('poll.vote_changed', (event) => { if (event.poll?.id) { this.fromState(event.poll.id)?.handleVoteChanged(event); } }).unsubscribe; - }; - private subscribeVoteRemoved = () => { - return this.client.on('poll.vote_removed', (event) => { + private subscribeVoteRemoved = () => + this.client.on('poll.vote_removed', (event) => { if (event.poll?.id) { this.fromState(event.poll.id)?.handleVoteRemoved(event); } }).unsubscribe; - }; - private subscribeMessageNew = () => { - return this.client.on('message.new', (event) => { + private subscribeMessageNew = () => + this.client.on('message.new', (event) => { const { message } = event; if (message) { const formattedMessage = formatMessage(message); this.hydratePollCache([formattedMessage]); } }).unsubscribe; - }; } diff --git a/src/search_controller.ts b/src/search_controller.ts index 1f14e469c..f46cf212b 100644 --- a/src/search_controller.ts +++ b/src/search_controller.ts @@ -1,4 +1,5 @@ -import { debounce, DebouncedFunc } from './utils'; +import type { DebouncedFunc } from './utils'; +import { debounce } from './utils'; import { StateStore } from './store'; import type { Channel } from './channel'; import type { StreamChat } from './client'; @@ -151,7 +152,13 @@ export abstract class BaseSearchSource implements SearchSource { async executeQuery(newSearchString?: string) { const hasNewSearchQuery = typeof newSearchString !== 'undefined'; const searchString = newSearchString ?? this.searchQuery; - if (!this.isActive || this.isLoading || (!this.hasNext && !hasNewSearchQuery) || !searchString) return; + if ( + !this.isActive || + this.isLoading || + (!this.hasNext && !hasNewSearchQuery) || + !searchString + ) + return; if (hasNewSearchQuery) { this.state.next({ @@ -215,7 +222,10 @@ export class UserSearchSource extends BaseSearchSource { protected async query(searchQuery: string) { const filters = { - $or: [{ id: { $autocomplete: searchQuery } }, { name: { $autocomplete: searchQuery } }], + $or: [ + { id: { $autocomplete: searchQuery } }, + { name: { $autocomplete: searchQuery } }, + ], ...this.filters, } as UserFilters; const sort = { id: 1, ...this.sort } as UserSort; @@ -298,7 +308,11 @@ export class MessageSearchSource extends BaseSearchSource { sort, } as SearchOptions; - const { next, results } = await this.client.search(channelFilters, messageFilters, options); + const { next, results } = await this.client.search( + channelFilters, + messageFilters, + options, + ); const items = results.map(({ message }) => message); const cids = Array.from( @@ -330,7 +344,11 @@ export class MessageSearchSource extends BaseSearchSource { } } -export type DefaultSearchSources = [UserSearchSource, ChannelSearchSource, MessageSearchSource]; +export type DefaultSearchSources = [ + UserSearchSource, + ChannelSearchSource, + MessageSearchSource, +]; export type SearchControllerState = { isActive: boolean; @@ -402,7 +420,8 @@ export class SearchController { }); }; - getSource = (sourceType: SearchSource['type']) => this.sources.find((s) => s.type === sourceType); + getSource = (sourceType: SearchSource['type']) => + this.sources.find((s) => s.type === sourceType); removeSource = (sourceType: SearchSource['type']) => { const newSources = this.sources.filter((s) => s.type !== sourceType); @@ -434,7 +453,9 @@ export class SearchController { activate = () => { if (!this.activeSources.length) { - const sourcesToActivate = this.config.keepSingleActiveSource ? this.sources.slice(0, 1) : this.sources; + const sourcesToActivate = this.config.keepSingleActiveSource + ? this.sources.slice(0, 1) + : this.sources; sourcesToActivate.forEach((s) => s.activate()); } if (this.isActive) return; @@ -455,7 +476,9 @@ export class SearchController { clear = () => { this.cancelSearchQueries(); - this.sources.forEach((source) => source.state.next({ ...source.initialState, isActive: source.isActive })); + this.sources.forEach((source) => + source.state.next({ ...source.initialState, isActive: source.isActive }), + ); this.state.next((current) => ({ ...current, isActive: true, @@ -466,7 +489,9 @@ export class SearchController { exit = () => { this.cancelSearchQueries(); - this.sources.forEach((source) => source.state.next({ ...source.initialState, isActive: source.isActive })); + this.sources.forEach((source) => + source.state.next({ ...source.initialState, isActive: source.isActive }), + ); this.state.next((current) => ({ ...current, isActive: false, diff --git a/src/segment.ts b/src/segment.ts index 2f60985c8..a3091fd36 100644 --- a/src/segment.ts +++ b/src/segment.ts @@ -1,5 +1,10 @@ -import { StreamChat } from './client'; -import { QuerySegmentTargetsFilter, SegmentData, SegmentResponse, SortParam } from './types'; +import type { StreamChat } from './client'; +import type { + QuerySegmentTargetsFilter, + SegmentData, + SegmentResponse, + SortParam, +} from './types'; type SegmentType = 'user' | 'channel'; @@ -15,14 +20,19 @@ export class Segment { client: StreamChat; data?: SegmentData | SegmentResponse; - constructor(client: StreamChat, type: SegmentType, id: string | null, data?: SegmentData) { + constructor( + client: StreamChat, + type: SegmentType, + id: string | null, + data?: SegmentData, + ) { this.client = client; this.type = type; this.id = id; this.data = data; } - async create() { + create() { const body = { name: this.data?.name, filter: this.data?.filter, @@ -42,38 +52,42 @@ export class Segment { } } - async get() { + get() { this.verifySegmentId(); return this.client.getSegment(this.id as string); } - async update(data: Partial) { + update(data: Partial) { this.verifySegmentId(); return this.client.updateSegment(this.id as string, data); } - async addTargets(targets: string[]) { + addTargets(targets: string[]) { this.verifySegmentId(); return this.client.addSegmentTargets(this.id as string, targets); } - async removeTargets(targets: string[]) { + removeTargets(targets: string[]) { this.verifySegmentId(); return this.client.removeSegmentTargets(this.id as string, targets); } - async delete() { + delete() { this.verifySegmentId(); return this.client.deleteSegment(this.id as string); } - async targetExists(targetId: string) { + targetExists(targetId: string) { this.verifySegmentId(); return this.client.segmentTargetExists(this.id as string, targetId); } - async queryTargets(filter: QuerySegmentTargetsFilter | null = {}, sort: SortParam[] | null | [] = [], options = {}) { + queryTargets( + filter: QuerySegmentTargetsFilter | null = {}, + sort: SortParam[] | null | [] = [], + options = {}, + ) { this.verifySegmentId(); return this.client.querySegmentTargets(this.id as string, filter, sort, options); diff --git a/src/signing.ts b/src/signing.ts index 1ef1e0e72..661a77190 100644 --- a/src/signing.ts +++ b/src/signing.ts @@ -1,7 +1,7 @@ import jwt from 'jsonwebtoken'; import crypto from 'crypto'; -import { encodeBase64, decodeBase64 } from './base64'; -import { UR } from './types'; +import { decodeBase64, encodeBase64 } from './base64'; +import type { UR } from './types'; /** * Creates the JWT token that can be used for a UserSession @@ -36,7 +36,10 @@ export function JWTUserToken( ); } - const opts: jwt.SignOptions = Object.assign({ algorithm: 'HS256', noTimestamp: true }, jwtOptions); + const opts: jwt.SignOptions = Object.assign( + { algorithm: 'HS256', noTimestamp: true }, + jwtOptions, + ); if (payload.iat) { opts.noTimestamp = false; @@ -49,7 +52,10 @@ export function JWTServerToken(apiSecret: jwt.Secret, jwtOptions: jwt.SignOption server: true, }; - const opts: jwt.SignOptions = Object.assign({ algorithm: 'HS256', noTimestamp: true }, jwtOptions); + const opts: jwt.SignOptions = Object.assign( + { algorithm: 'HS256', noTimestamp: true }, + jwtOptions, + ); return jwt.sign(payload, apiSecret, opts); } diff --git a/src/store.ts b/src/store.ts index a2c18e755..8c71116f5 100644 --- a/src/store.ts +++ b/src/store.ts @@ -3,20 +3,19 @@ export type ValueOrPatch = T | Patch; export type Handler = (nextValue: T, previousValue: T | undefined) => void; export type Unsubscribe = () => void; -export const isPatch = (value: ValueOrPatch): value is Patch => { - return typeof value === 'function'; -}; +export const isPatch = (value: ValueOrPatch): value is Patch => + typeof value === 'function'; export class StateStore> { private handlerSet = new Set>(); - private static logCount = 5; - constructor(private value: T) {} public next = (newValueOrPatch: ValueOrPatch): void => { // newValue (or patch output) should never be mutated previous value - const newValue = isPatch(newValueOrPatch) ? newValueOrPatch(this.value) : newValueOrPatch; + const newValue = isPatch(newValueOrPatch) + ? newValueOrPatch(this.value) + : newValueOrPatch; // do not notify subscribers if the value hasn't changed if (newValue === this.value) return; @@ -27,7 +26,8 @@ export class StateStore> { this.handlerSet.forEach((handler) => handler(this.value, oldValue)); }; - public partialNext = (partial: Partial): void => this.next((current) => ({ ...current, ...partial })); + public partialNext = (partial: Partial): void => + this.next((current) => ({ ...current, ...partial })); public getLatestValue = (): T => this.value; @@ -39,7 +39,9 @@ export class StateStore> { }; }; - public subscribeWithSelector = > | Readonly>( + public subscribeWithSelector = < + O extends Readonly> | Readonly, + >( selector: (nextValue: T) => O, handler: Handler, ) => { @@ -51,15 +53,7 @@ export class StateStore> { let hasUpdatedValues = !selectedValues; - if (Array.isArray(newlySelectedValues) && StateStore.logCount > 0) { - console.warn( - '[StreamChat]: The API of our StateStore has changed. Instead of returning an array in the selector, please return a named object of properties.', - ); - StateStore.logCount--; - } - for (const key in selectedValues) { - // @ts-ignore TODO: remove array support (Readonly) if (selectedValues[key] === newlySelectedValues[key]) continue; hasUpdatedValues = true; break; diff --git a/src/thread.ts b/src/thread.ts index 5ed74ddd3..844f04980 100644 --- a/src/thread.ts +++ b/src/thread.ts @@ -1,5 +1,10 @@ import { StateStore } from './store'; -import { addToMessageList, findIndexInSortedArray, formatMessage, throttle } from './utils'; +import { + addToMessageList, + findIndexInSortedArray, + formatMessage, + throttle, +} from './utils'; import type { AscDesc, EventTypes, @@ -109,16 +114,31 @@ export class Thread { private unsubscribeFunctions: Set<() => void> = new Set(); private failedRepliesMap: Map = new Map(); - constructor({ client, threadData }: { client: StreamChat; threadData: ThreadResponse }) { + constructor({ + client, + threadData, + }: { + client: StreamChat; + threadData: ThreadResponse; + }) { const channel = client.channel(threadData.channel.type, threadData.channel.id, { name: threadData.channel.name, }); - channel._hydrateMembers({ members: threadData.channel.members ?? [], overrideCurrentState: false }); + channel._hydrateMembers({ + members: threadData.channel.members ?? [], + overrideCurrentState: false, + }); // For when read object is undefined and due to that unreadMessageCount for // the current user isn't being incremented on message.new const placeholderReadResponse: ReadResponse[] = client.userID - ? [{ user: { id: client.userID }, unread_messages: 0, last_read: new Date().toISOString() }] + ? [ + { + user: { id: client.userID }, + unread_messages: 0, + last_read: new Date().toISOString(), + }, + ] : []; this.state = new StateStore({ @@ -135,7 +155,9 @@ export class Thread { parentMessage: formatMessage(threadData.parent_message), participants: threadData.thread_participants, read: formatReadState( - !threadData.read || threadData.read.length === 0 ? placeholderReadResponse : threadData.read, + !threadData.read || threadData.read.length === 0 + ? placeholderReadResponse + : threadData.read, ), replies: threadData.latest_replies.map(formatMessage), replyCount: threadData.reply_count ?? 0, @@ -236,8 +258,8 @@ export class Thread { this.unsubscribeFunctions.add(this.subscribeMessageUpdated()); }; - private subscribeThreadUpdated = () => { - return this.client.on('thread.updated', (event) => { + private subscribeThreadUpdated = () => + this.client.on('thread.updated', (event) => { if (!event.thread || event.thread.parent_message_id !== this.id) { return; } @@ -252,10 +274,9 @@ export class Thread { custom: constructCustomDataObject(threadData), }); }).unsubscribe; - }; - private subscribeMarkActiveThreadRead = () => { - return this.state.subscribeWithSelector( + private subscribeMarkActiveThreadRead = () => + this.state.subscribeWithSelector( (nextValue) => ({ active: nextValue.active, unreadMessageCount: ownUnreadCountSelector(this.client.userID)(nextValue), @@ -265,7 +286,6 @@ export class Thread { this.throttledMarkAsRead(); }, ); - }; private subscribeReloadActiveStaleThread = () => this.state.subscribeWithSelector( @@ -281,7 +301,11 @@ export class Thread { this.client.on('user.watching.stop', (event) => { const { channel } = this.state.getLatestValue(); - if (!this.client.userID || this.client.userID !== event.user?.id || event.channel?.cid !== channel.cid) { + if ( + !this.client.userID || + this.client.userID !== event.user?.id || + event.channel?.cid !== channel.cid + ) { return; } @@ -386,7 +410,12 @@ export class Thread { }).unsubscribe; private subscribeMessageUpdated = () => { - const eventTypes: EventTypes[] = ['message.updated', 'reaction.new', 'reaction.deleted', 'reaction.updated']; + const eventTypes: EventTypes[] = [ + 'message.updated', + 'reaction.new', + 'reaction.deleted', + 'reaction.updated', + ]; const unsubscribeFunctions = eventTypes.map( (eventType) => @@ -489,23 +518,24 @@ export class Thread { return await this.channel.markRead({ thread_id: this.id }); }; - private throttledMarkAsRead = throttle(() => this.markAsRead(), MARK_AS_READ_THROTTLE_TIMEOUT, { trailing: true }); + private throttledMarkAsRead = throttle( + () => this.markAsRead(), + MARK_AS_READ_THROTTLE_TIMEOUT, + { trailing: true }, + ); public queryReplies = ({ limit = DEFAULT_PAGE_LIMIT, sort = DEFAULT_SORT, ...otherOptions - }: QueryRepliesOptions = {}) => { - return this.channel.getReplies(this.id, { limit, ...otherOptions }, sort); - }; + }: QueryRepliesOptions = {}) => + this.channel.getReplies(this.id, { limit, ...otherOptions }, sort); - public loadNextPage = ({ limit = DEFAULT_PAGE_LIMIT }: { limit?: number } = {}) => { - return this.loadPage(limit); - }; + public loadNextPage = ({ limit = DEFAULT_PAGE_LIMIT }: { limit?: number } = {}) => + this.loadPage(limit); - public loadPrevPage = ({ limit = DEFAULT_PAGE_LIMIT }: { limit?: number } = {}) => { - return this.loadPage(-limit); - }; + public loadPrevPage = ({ limit = DEFAULT_PAGE_LIMIT }: { limit?: number } = {}) => + this.loadPage(-limit); private loadPage = async (count: number) => { const { pagination } = this.state.getLatestValue(); @@ -569,16 +599,22 @@ const formatReadState = (read: ReadResponse[]): ThreadReadState => return state; }, {}); -const repliesPaginationFromInitialThread = (thread: ThreadResponse): ThreadRepliesPagination => { - const latestRepliesContainsAllReplies = thread.latest_replies.length === thread.reply_count; +const repliesPaginationFromInitialThread = ( + thread: ThreadResponse, +): ThreadRepliesPagination => { + const latestRepliesContainsAllReplies = + thread.latest_replies.length === thread.reply_count; return { nextCursor: null, - prevCursor: latestRepliesContainsAllReplies ? null : thread.latest_replies.at(0)?.id ?? null, + prevCursor: latestRepliesContainsAllReplies + ? null + : (thread.latest_replies.at(0)?.id ?? null), isLoadingNext: false, isLoadingPrev: false, }; }; -const ownUnreadCountSelector = (currentUserId: string | undefined) => (state: ThreadState) => - (currentUserId && state.read[currentUserId]?.unreadMessageCount) || 0; +const ownUnreadCountSelector = + (currentUserId: string | undefined) => (state: ThreadState) => + (currentUserId && state.read[currentUserId]?.unreadMessageCount) || 0; diff --git a/src/thread_manager.ts b/src/thread_manager.ts index 4a4568ba0..b70f0d11f 100644 --- a/src/thread_manager.ts +++ b/src/thread_manager.ts @@ -66,10 +66,13 @@ export class ThreadManager { return this.threadsByIdGetterCache.threadsById; } - const threadsById = threads.reduce>((newThreadsById, thread) => { - newThreadsById[thread.id] = thread; - return newThreadsById; - }, {}); + const threadsById = threads.reduce>( + (newThreadsById, thread) => { + newThreadsById[thread.id] = thread; + return newThreadsById; + }, + {}, + ); this.threadsByIdGetterCache.threads = threads; this.threadsByIdGetterCache.threadsById = threadsById; @@ -102,7 +105,8 @@ export class ThreadManager { private subscribeUnreadThreadsCountChange = () => { // initiate - const { unread_threads: unreadThreadCount = 0 } = (this.client.user as OwnUserResponse) ?? {}; + const { unread_threads: unreadThreadCount = 0 } = + (this.client.user as OwnUserResponse) ?? {}; this.state.partialNext({ unreadThreadCount }); const unsubscribeFunctions = [ @@ -139,7 +143,9 @@ export class ThreadManager { const { threads: prevThreads = [] } = prev ?? {}; // Thread instance was removed if there's no thread with the given id at all, // or it was replaced with a new instance - const removedThreads = prevThreads.filter((thread) => thread !== this.threadsById[thread.id]); + const removedThreads = prevThreads.filter( + (thread) => thread !== this.threadsById[thread.id], + ); nextThreads.forEach((thread) => thread.registerSubscriptions()); removedThreads.forEach((thread) => thread.unregisterSubscriptions()); @@ -193,8 +199,10 @@ export class ThreadManager { { trailing: true }, ); - const unsubscribeConnectionRecovered = this.client.on('connection.recovered', throttledHandleConnectionRecovered) - .unsubscribe; + const unsubscribeConnectionRecovered = this.client.on( + 'connection.recovered', + throttledHandleConnectionRecovered, + ).unsubscribe; return () => { unsubscribeConnectionDropped(); @@ -203,13 +211,16 @@ export class ThreadManager { }; public unregisterSubscriptions = () => { - this.state.getLatestValue().threads.forEach((thread) => thread.unregisterSubscriptions()); + this.state + .getLatestValue() + .threads.forEach((thread) => thread.unregisterSubscriptions()); this.unsubscribeFunctions.forEach((cleanupFunction) => cleanupFunction()); this.unsubscribeFunctions.clear(); }; public reload = async ({ force = false } = {}) => { - const { threads, unseenThreadIds, isThreadOrderStale, pagination, ready } = this.state.getLatestValue(); + const { threads, unseenThreadIds, isThreadOrderStale, pagination, ready } = + this.state.getLatestValue(); if (pagination.isLoading) return; if (!force && ready && !unseenThreadIds.length && !isThreadOrderStale) return; const limit = threads.length + unseenThreadIds.length; @@ -268,15 +279,14 @@ export class ThreadManager { } }; - public queryThreads = (options: QueryThreadsOptions = {}) => { - return this.client.queryThreads({ + public queryThreads = (options: QueryThreadsOptions = {}) => + this.client.queryThreads({ limit: 25, participant_limit: 10, reply_limit: 10, watch: true, ...options, }); - }; public loadNextPage = async (options: Omit = {}) => { const { pagination } = this.state.getLatestValue(); @@ -293,7 +303,9 @@ export class ThreadManager { this.state.next((current) => ({ ...current, - threads: response.threads.length ? current.threads.concat(response.threads) : current.threads, + threads: response.threads.length + ? current.threads.concat(response.threads) + : current.threads, pagination: { ...current.pagination, nextCursor: response.next ?? null, diff --git a/src/token_manager.ts b/src/token_manager.ts index d0775de16..0366c6a48 100644 --- a/src/token_manager.ts +++ b/src/token_manager.ts @@ -1,6 +1,6 @@ -import jwt from 'jsonwebtoken'; +import type jwt from 'jsonwebtoken'; -import { UserFromToken, JWTServerToken, JWTUserToken } from './signing'; +import { JWTServerToken, JWTUserToken, UserFromToken } from './signing'; import { isFunction } from './utils'; import type { TokenOrProvider, UserResponse } from './types'; @@ -85,7 +85,11 @@ export class TokenManager { throw new Error('User token can not be empty'); } - if (tokenOrProvider && typeof tokenOrProvider !== 'string' && !isFunction(tokenOrProvider)) { + if ( + tokenOrProvider && + typeof tokenOrProvider !== 'string' && + !isFunction(tokenOrProvider) + ) { throw new Error('user token should either be a string or a function'); } @@ -94,8 +98,13 @@ export class TokenManager { if (user.anon && tokenOrProvider === '') return; const tokenUserId = UserFromToken(tokenOrProvider); - if (tokenOrProvider != null && (tokenUserId == null || tokenUserId === '' || tokenUserId !== user.id)) { - throw new Error('userToken does not have a user_id or is not matching with user.id'); + if ( + tokenOrProvider != null && + (tokenUserId == null || tokenUserId === '' || tokenUserId !== user.id) + ) { + throw new Error( + 'userToken does not have a user_id or is not matching with user.id', + ); } } }; diff --git a/src/types.ts b/src/types.ts index 3998f31e7..e988cd412 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,20 +1,20 @@ -import { EVENT_MAP } from './events'; +import type { EVENT_MAP } from './events'; import type { Channel } from './channel'; import type { AxiosRequestConfig, AxiosResponse } from 'axios'; import type { StableWSConnection } from './connection'; import type { Role } from './permissions'; import type { + CustomAttachmentData, CustomChannelData, - CustomMemberData, - CustomThreadData, + CustomCommandData, CustomEventData, + CustomMemberData, CustomMessageData, - CustomUserData, - CustomReactionData, - CustomAttachmentData, - CustomCommandData, CustomPollData, CustomPollOptionData, + CustomReactionData, + CustomThreadData, + CustomUserData, } from './custom_types'; /** @@ -56,10 +56,10 @@ export type UnknownType = UR; // alias to avoid breaking change export type Unpacked = T extends (infer U)[] ? U // eslint-disable-next-line @typescript-eslint/no-explicit-any : T extends (...args: any[]) => infer U - ? U - : T extends Promise - ? U - : T; + ? U + : T extends Promise + ? U + : T; /** * Response Types @@ -441,7 +441,7 @@ export type FlagMessageResponse = APIResponse & { user: UserResponse; approved_at?: string; channel_cid?: string; - details?: Object; // Any JSON + details?: object; // Any JSON message_user_id?: string; rejected_at?: string; reviewed_at?: string; @@ -458,7 +458,7 @@ export type FlagUserResponse = APIResponse & { updated_at: string; user: UserResponse; approved_at?: string; - details?: Object; // Any JSON + details?: object; // Any JSON rejected_at?: string; reviewed_at?: string; reviewed_by?: string; @@ -893,11 +893,14 @@ export type FlagReportsPaginationOptions = { }; export type ReviewFlagReportOptions = { - review_details?: Object; + review_details?: object; user_id?: string; }; -export type BannedUsersPaginationOptions = Omit & { +export type BannedUsersPaginationOptions = Omit< + PaginationOptions, + 'id_gt' | 'id_gte' | 'id_lt' | 'id_lte' +> & { exclude_expired_bans?: boolean; }; @@ -994,9 +997,13 @@ export type DeactivateUsersOptions = { mark_messages_deleted?: boolean; }; -export type NewMemberPayload = CustomMemberData & Pick; +export type NewMemberPayload = CustomMemberData & + Pick; -export type Thresholds = Record<'explicit' | 'spam' | 'toxic', Partial<{ block: number; flag: number }>>; +export type Thresholds = Record< + 'explicit' | 'spam' | 'toxic', + Partial<{ block: number; flag: number }> +>; export type BlockListOptions = { behavior: BlocklistBehavior; @@ -1445,21 +1452,30 @@ export type MessageFlagsFiltersOptions = { export type MessageFlagsFilters = QueryFilters< { channel_cid?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { team?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { user_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { - [Key in keyof Omit]: - | RequireOnlyOne> - | PrimitiveFilter; - } + [Key in keyof Omit< + MessageFlagsFiltersOptions, + 'channel_cid' | 'user_id' | 'is_reviewed' + >]: + | RequireOnlyOne> + | PrimitiveFilter; + } >; export type FlagsFiltersOptions = { @@ -1478,19 +1494,27 @@ export type FlagsFilters = QueryFilters< | PrimitiveFilter; } & { message_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { message_user_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { channel_cid?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { reporter_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { team?: @@ -1514,42 +1538,60 @@ export type FlagReportsFiltersOptions = { export type FlagReportsFilters = QueryFilters< { report_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { review_result?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { reviewed_by?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { user_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { message_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { message_user_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { channel_cid?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { team?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { - [Key in keyof Omit< - FlagReportsFiltersOptions, - 'report_id' | 'user_id' | 'message_id' | 'review_result' | 'reviewed_by' - >]: RequireOnlyOne> | PrimitiveFilter; - } + [Key in keyof Omit< + FlagReportsFiltersOptions, + 'report_id' | 'user_id' | 'message_id' | 'review_result' | 'reviewed_by' + >]: + | RequireOnlyOne> + | PrimitiveFilter; + } >; export type BannedUsersFilterOptions = { @@ -1563,7 +1605,9 @@ export type BannedUsersFilterOptions = { export type BannedUsersFilters = QueryFilters< { channel_cid?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { reason?: @@ -1574,10 +1618,10 @@ export type BannedUsersFilters = QueryFilters< > | PrimitiveFilter; } & { - [Key in keyof Omit]: - | RequireOnlyOne> - | PrimitiveFilter; - } + [Key in keyof Omit]: + | RequireOnlyOne> + | PrimitiveFilter; + } >; export type ReactionFilters = QueryFilters< @@ -1591,7 +1635,12 @@ export type ReactionFilters = QueryFilters< | PrimitiveFilter; } & { created_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } >; @@ -1619,10 +1668,10 @@ export type ChannelFilters = QueryFilters< | PrimitiveFilter; pinned?: boolean; } & { - [Key in keyof Omit]: - | RequireOnlyOne> - | PrimitiveFilter; - } + [Key in keyof Omit]: + | RequireOnlyOne> + | PrimitiveFilter; + } >; export type QueryPollsParams = { @@ -1643,7 +1692,9 @@ export type QueryVotesOptions = Pager; export type QueryPollsFilters = QueryFilters< { - id?: RequireOnlyOne, '$eq' | '$in'>> | PrimitiveFilter; + id?: + | RequireOnlyOne, '$eq' | '$in'>> + | PrimitiveFilter; } & { user_id?: | RequireOnlyOne, '$eq' | '$in'>> @@ -1654,7 +1705,12 @@ export type QueryPollsFilters = QueryFilters< | PrimitiveFilter; } & { max_votes_allowed?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { allow_answers?: @@ -1662,7 +1718,9 @@ export type QueryPollsFilters = QueryFilters< | PrimitiveFilter; } & { allow_user_suggested_options?: - | RequireOnlyOne, '$eq'>> + | RequireOnlyOne< + Pick, '$eq'> + > | PrimitiveFilter; } & { voting_visibility?: @@ -1670,7 +1728,12 @@ export type QueryPollsFilters = QueryFilters< | PrimitiveFilter; } & { created_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { created_by_id?: @@ -1678,7 +1741,12 @@ export type QueryPollsFilters = QueryFilters< | PrimitiveFilter; } & { updated_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { name?: @@ -1689,7 +1757,9 @@ export type QueryPollsFilters = QueryFilters< export type QueryVotesFilters = QueryFilters< { - id?: RequireOnlyOne, '$eq' | '$in'>> | PrimitiveFilter; + id?: + | RequireOnlyOne, '$eq' | '$in'>> + | PrimitiveFilter; } & { option_id?: | RequireOnlyOne, '$eq' | '$in'>> @@ -1704,7 +1774,12 @@ export type QueryVotesFilters = QueryFilters< | PrimitiveFilter; } & { created_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { created_by_id?: @@ -1712,7 +1787,12 @@ export type QueryVotesFilters = QueryFilters< | PrimitiveFilter; } & { updated_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } >; @@ -1739,7 +1819,9 @@ export type MessageFilters = QueryFilters< $in: PrimitiveFilter[]; }> | PrimitiveFilter; - 'mentioned_users.id'?: RequireOnlyOne<{ $contains: PrimitiveFilter }>; + 'mentioned_users.id'?: RequireOnlyOne<{ + $contains: PrimitiveFilter; + }>; text?: | RequireOnlyOne< { @@ -1756,10 +1838,10 @@ export type MessageFilters = QueryFilters< > | PrimitiveFilter; } & { - [Key in keyof Omit]?: - | RequireOnlyOne> - | PrimitiveFilter; - } + [Key in keyof Omit]?: + | RequireOnlyOne> + | PrimitiveFilter; + } >; export type MessageOptions = { @@ -1768,26 +1850,26 @@ export type MessageOptions = { export type PrimitiveFilter = ObjectType | null; -export type QueryFilter = NonNullable extends string | number | boolean - ? { - $eq?: PrimitiveFilter; - $exists?: boolean; - $gt?: PrimitiveFilter; - $gte?: PrimitiveFilter; - $in?: PrimitiveFilter[]; - $lt?: PrimitiveFilter; - $lte?: PrimitiveFilter; - } - : { - $eq?: PrimitiveFilter; - $exists?: boolean; - $in?: PrimitiveFilter[]; - }; +export type QueryFilter = + NonNullable extends string | number | boolean + ? { + $eq?: PrimitiveFilter; + $exists?: boolean; + $gt?: PrimitiveFilter; + $gte?: PrimitiveFilter; + $in?: PrimitiveFilter[]; + $lt?: PrimitiveFilter; + $lte?: PrimitiveFilter; + } + : { + $eq?: PrimitiveFilter; + $exists?: boolean; + $in?: PrimitiveFilter[]; + }; export type QueryFilters = { [Key in keyof Operators]?: Operators[Key]; -} & - QueryLogicalOperators; +} & QueryLogicalOperators; export type QueryLogicalOperators = { $and?: ArrayOneOrMore>; @@ -1798,10 +1880,14 @@ export type QueryLogicalOperators = { export type UserFilters = QueryFilters< ContainsOperator & { id?: - | RequireOnlyOne<{ $autocomplete?: UserResponse['id'] } & QueryFilter> + | RequireOnlyOne< + { $autocomplete?: UserResponse['id'] } & QueryFilter + > | PrimitiveFilter; name?: - | RequireOnlyOne<{ $autocomplete?: UserResponse['name'] } & QueryFilter> + | RequireOnlyOne< + { $autocomplete?: UserResponse['name'] } & QueryFilter + > | PrimitiveFilter; notifications_muted?: | RequireOnlyOne<{ @@ -1816,13 +1902,20 @@ export type UserFilters = QueryFilters< }> | PrimitiveFilter; username?: - | RequireOnlyOne<{ $autocomplete?: UserResponse['username'] } & QueryFilter> + | RequireOnlyOne< + { $autocomplete?: UserResponse['username'] } & QueryFilter< + UserResponse['username'] + > + > | PrimitiveFilter; } & { - [Key in keyof Omit]?: - | RequireOnlyOne> - | PrimitiveFilter; - } + [Key in keyof Omit< + UserResponse, + 'id' | 'name' | 'teams' | 'username' | keyof CustomUserData + >]?: + | RequireOnlyOne> + | PrimitiveFilter; + } >; export type InviteStatus = 'pending' | 'accepted' | 'rejected'; @@ -1831,7 +1924,9 @@ export type InviteStatus = 'pending' | 'accepted' | 'rejected'; export type MemberFilters = QueryFilters< { banned?: { $eq?: ChannelMemberResponse['banned'] } | ChannelMemberResponse['banned']; - channel_role?: { $eq?: ChannelMemberResponse['channel_role'] } | ChannelMemberResponse['channel_role']; + channel_role?: + | { $eq?: ChannelMemberResponse['channel_role'] } + | ChannelMemberResponse['channel_role']; cid?: { $eq?: ChannelResponse['cid'] } | ChannelResponse['cid']; created_at?: | { @@ -1940,7 +2035,11 @@ export type UserSort = Sort | Array>; export type MemberSort = | Sort> - | Array>>; + | Array< + Sort< + Pick + > + >; export type SearchMessageSortBase = Sort & { attachments?: AscDesc; @@ -2524,7 +2623,11 @@ export type LiteralStringForUnion = string & {}; export type LogLevel = 'info' | 'error' | 'warn'; -export type Logger = (logLevel: LogLevel, message: string, extraData?: Record) => void; +export type Logger = ( + logLevel: LogLevel, + message: string, + extraData?: Record, +) => void; export type Message = Partial & { mentioned_users?: string[]; @@ -2549,7 +2652,13 @@ export type MessageBase = CustomMessageData & { user_id?: string; }; -export type MessageLabel = 'deleted' | 'ephemeral' | 'error' | 'regular' | 'reply' | 'system'; +export type MessageLabel = + | 'deleted' + | 'ephemeral' + | 'error' + | 'regular' + | 'reply' + | 'system'; export type SendMessageOptions = { force_moderation?: boolean; @@ -3253,22 +3362,31 @@ export type CastVoteAPIResponse = { export type QueryMessageHistoryFilters = QueryFilters< { message_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { user_id?: - | RequireOnlyOne, '$eq' | '$in'>> + | RequireOnlyOne< + Pick, '$eq' | '$in'> + > | PrimitiveFilter; } & { created_at?: | RequireOnlyOne< - Pick, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'> + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > > | PrimitiveFilter; } >; -export type QueryMessageHistorySort = QueryMessageHistorySortBase | Array; +export type QueryMessageHistorySort = + | QueryMessageHistorySortBase + | Array; export type QueryMessageHistorySortBase = { message_updated_at?: AscDesc; @@ -3409,7 +3527,12 @@ export type ReviewQueueFilters = QueryFilters< | PrimitiveFilter; } & { completed_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { config_key?: @@ -3421,7 +3544,12 @@ export type ReviewQueueFilters = QueryFilters< | PrimitiveFilter; } & { created_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { id?: @@ -3435,7 +3563,12 @@ export type ReviewQueueFilters = QueryFilters< reviewed?: boolean; } & { reviewed_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { status?: @@ -3443,7 +3576,12 @@ export type ReviewQueueFilters = QueryFilters< | PrimitiveFilter; } & { updated_at?: - | RequireOnlyOne, '$eq' | '$gt' | '$lt' | '$gte' | '$lte'>> + | RequireOnlyOne< + Pick< + QueryFilter, + '$eq' | '$gt' | '$lt' | '$gte' | '$lte' + > + > | PrimitiveFilter; } & { has_image?: boolean; @@ -3571,7 +3709,13 @@ export type AIState = | 'AI_STATE_GENERATING' | (string & {}); -export type ModerationActionType = 'flag' | 'shadow' | 'remove' | 'bounce' | 'bounce_flag' | 'bounce_remove'; +export type ModerationActionType = + | 'flag' + | 'shadow' + | 'remove' + | 'bounce' + | 'bounce_flag' + | 'bounce_remove'; export type AutomodRule = { action: ModerationActionType; @@ -3695,7 +3839,10 @@ export type PromoteChannelParams = { * An identifier containing information about the downstream SDK using stream-chat. It * is used to resolve the user agent. */ -export type SdkIdentifier = { name: 'react' | 'react-native' | 'expo' | 'angular'; version: string }; +export type SdkIdentifier = { + name: 'react' | 'react-native' | 'expo' | 'angular'; + version: string; +}; /** * An identifier containing information about the downstream device using stream-chat, if diff --git a/src/utils.ts b/src/utils.ts index fdbcb196b..c57c1aa5e 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,25 +1,25 @@ import FormData from 'form-data'; -import { +import type { AscDesc, - Logger, - OwnUserBase, - OwnUserResponse, - UserResponse, - MessageResponse, - FormatMessageResponse, - ReactionGroupResponse, - MessageSet, - MessagePaginationOptions, + ChannelFilters, ChannelQueryOptions, - QueryChannelAPIResponse, ChannelSort, - ChannelFilters, ChannelSortBase, + FormatMessageResponse, + Logger, + MessagePaginationOptions, + MessageResponse, + MessageSet, + OwnUserBase, + OwnUserResponse, PromoteChannelParams, + QueryChannelAPIResponse, + ReactionGroupResponse, + UserResponse, } from './types'; -import { StreamChat } from './client'; -import { Channel } from './channel'; -import { AxiosRequestConfig } from 'axios'; +import type { StreamChat } from './client'; +import type { Channel } from './channel'; +import type { AxiosRequestConfig } from 'axios'; /** * logChatPromiseExecution - utility function for logging the execution of a promise.. @@ -37,12 +37,11 @@ export function logChatPromiseExecution(promise: Promise, name: string) { export const sleep = (m: number): Promise => new Promise((r) => setTimeout(r, m)); -export function isFunction(value: Function | T): value is Function { +export function isFunction(value: unknown): value is (...args: unknown[]) => unknown { return ( - value && - (Object.prototype.toString.call(value) === '[object Function]' || - 'function' === typeof value || - value instanceof Function) + typeof value === 'function' || + value instanceof Function || + Object.prototype.toString.call(value) === '[object Function]' ); } @@ -55,7 +54,8 @@ function isReadableStream(obj: unknown): obj is NodeJS.ReadStream { return ( obj !== null && typeof obj === 'object' && - ((obj as NodeJS.ReadStream).readable || typeof (obj as NodeJS.ReadStream)._read === 'function') + ((obj as NodeJS.ReadStream).readable || + typeof (obj as NodeJS.ReadStream)._read === 'function') ); } @@ -63,9 +63,9 @@ function isBuffer(obj: unknown): obj is Buffer { return ( obj != null && (obj as Buffer).constructor != null && - // @ts-expect-error + // @ts-expect-error expected typeof obj.constructor.isBuffer === 'function' && - // @ts-expect-error + // @ts-expect-error expected obj.constructor.isBuffer(obj) ); } @@ -74,7 +74,9 @@ function isFileWebAPI(uri: unknown): uri is File { return typeof window !== 'undefined' && 'File' in window && uri instanceof File; } -export function isOwnUser(user?: OwnUserResponse | UserResponse): user is OwnUserResponse { +export function isOwnUser( + user?: OwnUserResponse | UserResponse, +): user is OwnUserResponse { return (user as OwnUserResponse)?.total_unread_count !== undefined; } @@ -123,7 +125,9 @@ export function addFileToFormData( return data; } -export function normalizeQuerySort>(sort: T | T[]) { +export function normalizeQuerySort>( + sort: T | T[], +) { const sortFields: Array<{ direction: AscDesc; field: keyof T }> = []; const sortArr = Array.isArray(sort) ? sort : [sort]; for (const item of sortArr) { @@ -234,11 +238,13 @@ export function isOnline() { typeof navigator !== 'undefined' ? navigator : typeof window !== 'undefined' && window.navigator - ? window.navigator - : undefined; + ? window.navigator + : undefined; if (!nav) { - console.warn('isOnline failed to access window.navigator and assume browser is online'); + console.warn( + 'isOnline failed to access window.navigator and assume browser is online', + ); return true; } @@ -290,7 +296,9 @@ export const axiosParamsSerializer: AxiosRequestConfig['paramsSerializer'] = (pa * * @param {MessageResponse} message `MessageResponse` object */ -export function formatMessage(message: MessageResponse | FormatMessageResponse): FormatMessageResponse { +export function formatMessage( + message: MessageResponse | FormatMessageResponse, +): FormatMessageResponse { return { ...message, // parse the dates @@ -382,7 +390,9 @@ export const findIndexInSortedArray = ({ const step = sortDirection === 'ascending' ? -1 : +1; for ( let i = left + step; - 0 <= i && i < sortedArray.length && selectValueToCompare(sortedArray[i]) === comparableNeedle; + 0 <= i && + i < sortedArray.length && + selectValueToCompare(sortedArray[i]) === comparableNeedle; i += step ) { if (selectKey(sortedArray[i]) === needleKey) { @@ -407,7 +417,9 @@ export function addToMessageList( // if created_at has changed, message should be filtered and re-inserted in correct order // slow op but usually this only happens for a message inserted to state before actual response with correct timestamp if (timestampChanged) { - newMessages = newMessages.filter((message) => !(message.id && newMessage.id === message.id)); + newMessages = newMessages.filter( + (message) => !(message.id && newMessage.id === message.id), + ); } // for empty list just concat and return unless it's an update or deletion @@ -601,12 +613,16 @@ const get = (obj: T, path: string): unknown => }, obj); // works exactly the same as lodash.uniqBy -export const uniqBy = (array: T[] | unknown, iteratee: ((item: T) => unknown) | keyof T): T[] => { +export const uniqBy = ( + array: T[] | unknown, + iteratee: ((item: T) => unknown) | keyof T, +): T[] => { if (!Array.isArray(array)) return []; const seen = new Set(); return array.filter((item) => { - const key = typeof iteratee === 'function' ? iteratee(item) : get(item, iteratee as string); + const key = + typeof iteratee === 'function' ? iteratee(item) : get(item, iteratee as string); if (seen.has(key)) return false; seen.add(key); return true; @@ -669,12 +685,15 @@ const messagePaginationCreatedAtAround = ({ // expect ASC order (from oldest to newest) const wholePageHasNewerMessages = !!firstPageMsg?.created_at && new Date(firstPageMsg.created_at) > createdAtAroundDate; - const wholePageHasOlderMessages = !!lastPageMsg?.created_at && new Date(lastPageMsg.created_at) < createdAtAroundDate; + const wholePageHasOlderMessages = + !!lastPageMsg?.created_at && new Date(lastPageMsg.created_at) < createdAtAroundDate; const requestedPageSizeNotMet = - requestedPageSize > parentSet.messages.length && requestedPageSize > returnedPage.length; + requestedPageSize > parentSet.messages.length && + requestedPageSize > returnedPage.length; const noMoreMessages = - (requestedPageSize > parentSet.messages.length || parentSet.messages.length >= returnedPage.length) && + (requestedPageSize > parentSet.messages.length || + parentSet.messages.length >= returnedPage.length) && requestedPageSize > returnedPage.length; if (wholePageHasNewerMessages) { @@ -702,7 +721,10 @@ const messagePaginationCreatedAtAround = ({ updateHasPrev = firstPageMsgIsFirstInSet; updateHasNext = lastPageMsgIsLastInSet; const midPointByCount = Math.floor(returnedPage.length / 2); - const midPointByCreationDate = binarySearchByDateEqualOrNearestGreater(returnedPage, createdAtAroundDate); + const midPointByCreationDate = binarySearchByDateEqualOrNearestGreater( + returnedPage, + createdAtAroundDate, + ); if (midPointByCreationDate !== -1) { hasPrev = midPointByCount <= midPointByCreationDate; @@ -738,7 +760,8 @@ const messagePaginationIdAround = ({ const midPoint = Math.floor(returnedPage.length / 2); const noMoreMessages = - (requestedPageSize > parentSet.messages.length || parentSet.messages.length >= returnedPage.length) && + (requestedPageSize > parentSet.messages.length || + parentSet.messages.length >= returnedPage.length) && requestedPageSize > returnedPage.length; if (noMoreMessages) { @@ -828,7 +851,10 @@ const messagePaginationLinear = ({ export const messageSetPagination = (params: MessagePaginationUpdatedParams) => { if (params.parentSet.messages.length < params.returnedPage.length) { - params.logger?.('error', 'Corrupted message set state: parent set size < returned page size'); + params.logger?.( + 'error', + 'Corrupted message set state: parent set size < returned page size', + ); return params.parentSet.pagination; } @@ -845,7 +871,10 @@ export const messageSetPagination = (params: MessagePaginationUpdatedParams) => * A utility object used to prevent duplicate invocation of channel.watch() to be triggered when * 'notification.message_new' and 'notification.added_to_channel' events arrive at the same time. */ -const WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL: Record | undefined> = {}; +const WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL: Record< + string, + Promise | undefined +> = {}; type GetChannelParams = { client: StreamChat; @@ -865,7 +894,14 @@ type GetChannelParams = { * @param id * @param channel */ -export const getAndWatchChannel = async ({ channel, client, id, members, options, type }: GetChannelParams) => { +export const getAndWatchChannel = async ({ + channel, + client, + id, + members, + options, + type, +}: GetChannelParams) => { if (!channel && !type) { throw new Error('Channel or channel type have to be provided to query a channel.'); } @@ -878,11 +914,13 @@ export const getAndWatchChannel = async ({ channel, client, id, members, options const originalCid = channelToWatch.id ? channelToWatch.cid : members && members.length - ? generateChannelTempCid(channelToWatch.type, members) - : undefined; + ? generateChannelTempCid(channelToWatch.type, members) + : undefined; if (!originalCid) { - throw new Error('Channel ID or channel members array have to be provided to query a channel.'); + throw new Error( + 'Channel ID or channel members array have to be provided to query a channel.', + ); } const queryPromise = WATCH_QUERY_IN_PROGRESS_FOR_CHANNEL[originalCid]; @@ -1055,7 +1093,8 @@ export const promoteChannel = ({ }: PromoteChannelParams) => { // get index of channel to move up const targetChannelIndex = - channelToMoveIndexWithinChannels ?? channels.findIndex((channel) => channel.cid === channelToMove.cid); + channelToMoveIndexWithinChannels ?? + channels.findIndex((channel) => channel.cid === channelToMove.cid); const targetChannelExistsWithinList = targetChannelIndex >= 0; const targetChannelAlreadyAtTheTop = targetChannelIndex === 0; @@ -1085,7 +1124,11 @@ export const promoteChannel = ({ } // re-insert it at the new place (to specific index if pinned channels are considered) - newChannels.splice(typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0, 0, channelToMove); + newChannels.splice( + typeof lastPinnedChannelIndex === 'number' ? lastPinnedChannelIndex + 1 : 0, + 0, + channelToMove, + ); return newChannels; }; diff --git a/test/typescript/index.js b/test/typescript/index.js index a5a5b8eaf..f76141204 100644 --- a/test/typescript/index.js +++ b/test/typescript/index.js @@ -10,8 +10,7 @@ const executables = [ { f: rg.acceptInvite, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['acceptInvite']>>", + type: "Unpacked['acceptInvite']>>", }, { f: rg.addDevice, @@ -21,14 +20,12 @@ const executables = [ { f: rg.addMembers, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['addMembers']>>", + type: "Unpacked['addMembers']>>", }, { f: rg.addModerators, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['addModerators']>>", + type: "Unpacked['addModerators']>>", }, { f: rg.banUsers, @@ -59,14 +56,12 @@ const executables = [ { f: rg.create, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['create']>>", + type: "Unpacked['create']>>", }, { f: rg.createBlockList, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['createBlockList']>>", + type: "Unpacked['createBlockList']>>", }, // createChannelType has a limit. So only run this when needed. // { @@ -77,8 +72,7 @@ const executables = [ { f: rg.createCommand, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['createCommand']>>", + type: "Unpacked['createCommand']>>", }, { f: rg.createPermission, @@ -93,14 +87,12 @@ const executables = [ { f: rg.deleteBlockList, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['deleteBlockList']>>", + type: "Unpacked['deleteBlockList']>>", }, { f: rg.deleteChannel, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['delete']>>", + type: "Unpacked['delete']>>", }, // TODO: Fix the error which results from deleteChannelType api call: // `deleteChannelType failed with error: { Error: StreamChat error code 16: DeleteChannelType failed with error: "bc0b09df-2cfd-4e80-93e7-1f0091e6a435 is not a defined channel type"` @@ -113,20 +105,17 @@ const executables = [ { f: rg.deleteCommand, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['deleteCommand']>>", + type: "Unpacked['deleteCommand']>>", }, { f: rg.deleteFile, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['deleteFile']>>", + type: "Unpacked['deleteFile']>>", }, { f: rg.deleteImage, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['deleteImage']>>", + type: "Unpacked['deleteImage']>>", }, { f: rg.deleteMessage, @@ -141,8 +130,7 @@ const executables = [ { f: rg.deleteReaction, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['deleteReaction']>>", + type: "Unpacked['deleteReaction']>>", }, { f: rg.deleteUser, @@ -152,8 +140,7 @@ const executables = [ { f: rg.demoteModerators, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['demoteModerators']>>", + type: "Unpacked['demoteModerators']>>", }, // { // f: rg.disconnect, @@ -168,14 +155,12 @@ const executables = [ { f: rg.flagMessage, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['flagMessage']>>", + type: "Unpacked['flagMessage']>>", }, { f: rg.flagUser, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['flagUser']>>", + type: "Unpacked['flagUser']>>", }, { f: rg.getAppSettings, @@ -195,14 +180,12 @@ const executables = [ { f: rg.getCommand, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['getCommand']>>", + type: "Unpacked['getCommand']>>", }, { f: rg.getConfig, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['getConfig']>>", + type: "Unpacked['getConfig']>>", }, { f: rg.getDevices, @@ -217,14 +200,12 @@ const executables = [ { f: rg.getMessagesById, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['getMessagesById']>>", + type: "Unpacked['getMessagesById']>>", }, { f: rg.getMessageWithReply, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['getMessage']>>", + type: "Unpacked['getMessage']>>", }, { f: rg.getPermission, @@ -234,38 +215,32 @@ const executables = [ { f: rg.getReactions, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['getReactions']>>", + type: "Unpacked['getReactions']>>", }, { f: rg.getReplies, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['getReplies']>>", + type: "Unpacked['getReplies']>>", }, { f: rg.hide, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['hide']>>", + type: "Unpacked['hide']>>", }, { f: rg.inviteMembers, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['inviteMembers']>>", + type: "Unpacked['inviteMembers']>>", }, { f: rg.keystroke, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['keystroke']>>", + type: "Unpacked['keystroke']>>", }, { f: rg.lastMessage, imports: ['Channel', 'FormatMessageResponse', 'Unpacked'], - type: - "Omit, 'created_at' | 'updated_at'> & { created_at?: string; updated_at?: string } | undefined", + type: "Omit, 'created_at' | 'updated_at'> & { created_at?: string; updated_at?: string } | undefined", }, { f: rg.listBlockLists, @@ -280,8 +255,7 @@ const executables = [ { f: rg.listCommands, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['listCommands']>>", + type: "Unpacked['listCommands']>>", }, { f: rg.listPermissions, @@ -296,20 +270,17 @@ const executables = [ { f: rg.markRead, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['markRead']>>", + type: "Unpacked['markRead']>>", }, { f: rg.mute, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['mute']>>", + type: "Unpacked['mute']>>", }, { f: rg.muteStatus, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['muteStatus']>>", + type: "Unpacked['muteStatus']>>", }, { f: rg.muteUser, @@ -319,20 +290,17 @@ const executables = [ { f: rg.partialUpdateUser, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['partialUpdateUser']>>", + type: "Unpacked['partialUpdateUser']>>", }, { f: rg.partialUpdateUsers, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['partialUpdateUsers']>>", + type: "Unpacked['partialUpdateUsers']>>", }, { f: rg.query, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['query']>>", + type: "Unpacked['query']>>", }, // TODO: Add this back in when queryBannedUsers is deployed to all shards for testing // { @@ -344,14 +312,12 @@ const executables = [ { f: rg.queryMembers, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['queryMembers']>>", + type: "Unpacked['queryMembers']>>", }, { f: rg.queryUsers, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['queryUsers']>>", + type: "Unpacked['queryUsers']>>", }, { f: rg.reactivateUser, @@ -361,14 +327,12 @@ const executables = [ { f: rg.rejectInvite, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['rejectInvite']>>", + type: "Unpacked['rejectInvite']>>", }, { f: rg.removeMembers, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['removeMembers']>>", + type: "Unpacked['removeMembers']>>", }, { f: rg.removeShadowBan, @@ -378,38 +342,32 @@ const executables = [ { f: rg.sendAction, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['sendAction']>>", + type: "Unpacked['sendAction']>>", }, { f: rg.sendFile, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['sendFile']>>", + type: "Unpacked['sendFile']>>", }, { f: rg.sendImage, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['sendImage']>>", + type: "Unpacked['sendImage']>>", }, { f: rg.sendMessage, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['sendMessage']>>", + type: "Unpacked['sendMessage']>>", }, { f: rg.sendMessageReadEvent, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['sendEvent']>>", + type: "Unpacked['sendEvent']>>", }, { f: rg.sendReaction, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['sendReaction']>>", + type: "Unpacked['sendReaction']>>", }, { f: rg.setGuestUser, @@ -424,32 +382,27 @@ const executables = [ { f: rg.show, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['show']>>", + type: "Unpacked['show']>>", }, { f: rg.stopTyping, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['stopTyping']>>", + type: "Unpacked['stopTyping']>>", }, { f: rg.stopWatching, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['stopWatching']>>", + type: "Unpacked['stopWatching']>>", }, { f: rg.sync, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['sync']>>", + type: "Unpacked['sync']>>", }, { f: rg.syncTeam, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['sync']>>", + type: "Unpacked['sync']>>", }, // Need translation on the account to run this test // { @@ -461,8 +414,7 @@ const executables = [ { f: rg.truncateChannel, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['truncate']>>", + type: "Unpacked['truncate']>>", }, { f: rg.unbanUsers, @@ -472,8 +424,7 @@ const executables = [ { f: rg.unmute, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['unmute']>>", + type: "Unpacked['unmute']>>", }, { f: rg.unmuteUser, @@ -488,20 +439,17 @@ const executables = [ { f: rg.updateBlockList, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['updateBlockList']>>", + type: "Unpacked['updateBlockList']>>", }, { f: rg.updateChannel, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['update']>>", + type: "Unpacked['update']>>", }, { f: rg.updateChannelFromOriginal, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['update']>>", + type: "Unpacked['update']>>", }, { f: rg.updateChannelType, @@ -511,14 +459,12 @@ const executables = [ { f: rg.updateCommand, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['updateCommand']>>", + type: "Unpacked['updateCommand']>>", }, { f: rg.updateMessage, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['updateMessage']>>", + type: "Unpacked['updateMessage']>>", }, { f: rg.updatePermission, @@ -528,20 +474,17 @@ const executables = [ { f: rg.upsertUsers, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['upsertUsers']>>", + type: "Unpacked['upsertUsers']>>", }, { f: rg.upsertUser, imports: ['StreamChat', 'Unpacked'], - type: - "Unpacked['upsertUser']>>", + type: "Unpacked['upsertUser']>>", }, { f: rg.watch, imports: ['Channel', 'Unpacked'], - type: - "Unpacked['watch']>>", + type: "Unpacked['watch']>>", }, // Currently roles do not return diff --git a/test/typescript/response-generators/channel.js b/test/typescript/response-generators/channel.js index 7675ca529..0153e89c2 100644 --- a/test/typescript/response-generators/channel.js +++ b/test/typescript/response-generators/channel.js @@ -62,7 +62,9 @@ async function deleteChannel() { async function deleteFile() { const channel = await utils.createTestChannelForUser(uuidv4(), johnID); - const rs = fs.createReadStream(url.pathToFileURL('./test/typescript/response-generators/index.js')); + const rs = fs.createReadStream( + url.pathToFileURL('./test/typescript/response-generators/index.js'), + ); const file = await channel.sendFile(rs, 'testFile'); return channel.deleteFile(file.file); } @@ -70,7 +72,9 @@ async function deleteFile() { async function deleteImage() { const channel = await utils.createTestChannelForUser(uuidv4(), johnID); - const rs = fs.createReadStream(url.pathToFileURL('./test/typescript/response-generators/stream.png')); + const rs = fs.createReadStream( + url.pathToFileURL('./test/typescript/response-generators/stream.png'), + ); const image = await channel.sendImage(rs, 'testImage'); return channel.deleteImage(image.file); } @@ -164,14 +168,18 @@ async function removeMembers() { async function sendFile() { const channel = await utils.createTestChannelForUser(uuidv4(), johnID); - const rs = fs.createReadStream(url.pathToFileURL('./test/typescript/response-generators/index.js')); + const rs = fs.createReadStream( + url.pathToFileURL('./test/typescript/response-generators/index.js'), + ); return await channel.sendFile(rs, 'testFile'); } async function sendImage() { const channel = await utils.createTestChannelForUser(uuidv4(), johnID); - const rs = fs.createReadStream(url.pathToFileURL('./test/typescript/response-generators/stream.png')); + const rs = fs.createReadStream( + url.pathToFileURL('./test/typescript/response-generators/stream.png'), + ); return await channel.sendImage(rs, 'testImage'); } diff --git a/test/typescript/response-generators/client.js b/test/typescript/response-generators/client.js index d6f3d9984..ad0a0f636 100644 --- a/test/typescript/response-generators/client.js +++ b/test/typescript/response-generators/client.js @@ -173,7 +173,11 @@ async function syncTeam() { await utils.createMultiTenancyUsers([user1], [team]); const client = await utils.getMultiTenancyTestClientForUser(user1); const channelId = uuidv4(); - const channel = await utils.createTestMultiTenancyChannelForUser(channelId, user1, team); + const channel = await utils.createTestMultiTenancyChannelForUser( + channelId, + user1, + team, + ); await channel.sendMessage({ text: 'New Event?', user: { id: user1 }, @@ -184,7 +188,8 @@ async function syncTeam() { async function updateAppSettings() { const authClient = await utils.getTestClient(true); return await authClient.updateAppSettings({ - custom_action_handler_url: 'https://example.com/webhooks/stream/custom-commands?type={type}', + custom_action_handler_url: + 'https://example.com/webhooks/stream/custom-commands?type={type}', enforce_unique_usernames: 'no', }); } diff --git a/test/typescript/unit-test.ts b/test/typescript/unit-test.ts index cb15fce26..308b837fb 100644 --- a/test/typescript/unit-test.ts +++ b/test/typescript/unit-test.ts @@ -186,7 +186,13 @@ clientRes = client.post('https://chat.stream-io-api.com/', { id: 2 }); clientRes = client.patch('https://chat.stream-io-api.com/', { id: 2 }); clientRes = client.delete('https://chat.stream-io-api.com/', { id: 2 }); -const file: Promise = client.sendFile('aa', 'bb', 'text.jpg', 'image/jpg', { id: 'james' }); +const file: Promise = client.sendFile( + 'aa', + 'bb', + 'text.jpg', + 'image/jpg', + { id: 'james' }, +); const type: EventTypes = 'user.updated'; const event: Event = { @@ -224,15 +230,20 @@ channels.then((response) => { const cid: string = response[0].cid; }); -const channel: Channel = client.channel('messaging', 'channelName', { color: 'green' }); +const channel: Channel = client.channel('messaging', 'channelName', { + color: 'green', +}); const channelState: ChannelState = channel.state; const chUser1: ChannelMemberResponse = channelState.members.someUser12433222; -const chUser2: ChannelMemberResponse = channelState.members.someUser124332221; +const chUser2: ChannelMemberResponse = + channelState.members.someUser124332221; const chUser3: UserResponse = channelState.read.someUserId.user; const typing: Event = channelState.typing['someUserId']; -const acceptInvite: Promise> = channel.acceptInvite({}); +const acceptInvite: Promise> = channel.acceptInvite( + {}, +); voidReturn = channel.on(eventHandler); voidReturn = channel.off(eventHandler); @@ -242,11 +253,39 @@ voidReturn = channel.off('message.new', eventHandler); channel.sendMessage({ text: 'text' }); // send a msg without id const permissions = [ - new Permission('Admin users can perform any action', MaxPriority, AnyResource, AnyRole, false, Allow), - new Permission('Anonymous users are not allowed', 500, AnyResource, ['anonymous'], false, Deny), - new Permission('Users can modify their own messages', 400, AnyResource, ['user'], true, Allow), + new Permission( + 'Admin users can perform any action', + MaxPriority, + AnyResource, + AnyRole, + false, + Allow, + ), + new Permission( + 'Anonymous users are not allowed', + 500, + AnyResource, + ['anonymous'], + false, + Deny, + ), + new Permission( + 'Users can modify their own messages', + 400, + AnyResource, + ['user'], + true, + Allow, + ), new Permission('Users can create channels', 300, AnyResource, ['user'], false, Allow), - new Permission('Channel Members', 200, ['ReadChannel', 'CreateMessage'], ['channel_member'], false, Allow), + new Permission( + 'Channel Members', + 200, + ['ReadChannel', 'CreateMessage'], + ['channel_member'], + false, + Allow, + ), new Permission('Discard all', 100, AnyResource, AnyRole, false, Deny), ]; diff --git a/test/typescript/utils.js b/test/typescript/utils.js index 03251c295..fee87fdf2 100644 --- a/test/typescript/utils.js +++ b/test/typescript/utils.js @@ -9,7 +9,11 @@ const multiTenancySecret = process.env.MULTITENANCY_API_SECRET; const multiTenancyKey = process.env.MULTITENANCY_API_KEY; module.exports = { - createMultiTenancyUsers: async function createMultiTenancyUsers(userIDs, teams = [], additionalInfo) { + createMultiTenancyUsers: async function createMultiTenancyUsers( + userIDs, + teams = [], + additionalInfo, + ) { const serverClient = await this.getMultiTenancyServerTestClient(); const users = []; for (const userID of userIDs) { @@ -41,28 +45,32 @@ module.exports = { await channel.create(); return channel; }, - createTestChannelForUser: async function createTestChannelForUser(id, userID, options = {}) { - const client = await this.getTestClientForUser(userID, options); - const channel = client.channel('messaging', id, { members: [userID] }); - await channel.create(); - return channel; - }, - createTestMultiTenancyChannelForUser: async function createTestMultiTenancyChannelForUser( + createTestChannelForUser: async function createTestChannelForUser( id, userID, - team, options = {}, ) { - const client = await this.getMultiTenancyTestClientForUser(userID, options); - const channel = client.channel('messaging', id, { members: [userID], team }); + const client = await this.getTestClientForUser(userID, options); + const channel = client.channel('messaging', id, { members: [userID] }); await channel.create(); return channel; }, + createTestMultiTenancyChannelForUser: + async function createTestMultiTenancyChannelForUser(id, userID, team, options = {}) { + const client = await this.getMultiTenancyTestClientForUser(userID, options); + const channel = client.channel('messaging', id, { members: [userID], team }); + await channel.create(); + return channel; + }, getMultiTenancyTestClient: async function getMultiTenancyTestClient(serverSide) { - const client = new StreamChat(multiTenancyKey, serverSide ? multiTenancySecret : null, { - timeout: 8000, - allowServerSideConnect: true, - }); + const client = new StreamChat( + multiTenancyKey, + serverSide ? multiTenancySecret : null, + { + timeout: 8000, + allowServerSideConnect: true, + }, + ); if (serverSide) { await client.updateAppSettings({ multi_tenant_enabled: true, @@ -70,9 +78,15 @@ module.exports = { } return client; }, - getMultiTenancyTestClientForUser: async function getMultiTenancyTestClientForUser(userID, options = {}) { + getMultiTenancyTestClientForUser: async function getMultiTenancyTestClientForUser( + userID, + options = {}, + ) { const client = await this.getMultiTenancyTestClient(false); - const health = await client.connectUser({ id: userID, ...options }, this.createMultiTenancyUserToken(userID)); + const health = await client.connectUser( + { id: userID, ...options }, + this.createMultiTenancyUserToken(userID), + ); client.health = health; return client; }, @@ -90,7 +104,10 @@ module.exports = { }, getTestClientForUser: async function getTestClientForUser(userID, options = {}) { const client = this.getTestClient(false); - const health = await client.connectUser({ id: userID, ...options }, this.createUserToken(userID)); + const health = await client.connectUser( + { id: userID, ...options }, + this.createUserToken(userID), + ); client.health = health; return client; }, diff --git a/test/unit/channel.js b/test/unit/channel.test.js similarity index 91% rename from test/unit/channel.js rename to test/unit/channel.test.js index b4215cab0..9ddedb896 100644 --- a/test/unit/channel.js +++ b/test/unit/channel.test.js @@ -1,4 +1,3 @@ -import chai from 'chai'; import { v4 as uuidv4 } from 'uuid'; import { generateChannel } from './test-utils/generateChannel'; @@ -13,7 +12,7 @@ import { mockChannelQueryResponse } from './test-utils/mockChannelQueryResponse' import { ChannelState, StreamChat } from '../../src'; import { DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE } from '../../src/constants'; -const expect = chai.expect; +import { describe, beforeEach, it, expect } from 'vitest'; describe('Channel count unread', function () { let lastRead; @@ -75,7 +74,10 @@ describe('Channel count unread', function () { }); it('_countMessageAsUnread should return false for channel with read_events off', function () { - const channel = client.channel('messaging', { members: ['tommaso'], own_capabilities: [] }); + const channel = client.channel('messaging', { + members: ['tommaso'], + own_capabilities: [], + }); expect(channel._countMessageAsUnread({ user: { id: 'random' } })).not.to.be.ok; }); @@ -125,7 +127,13 @@ describe('Channel count unread', function () { generateMsg({ date: '2021-01-01T00:00:00' }), generateMsg({ date: '2022-01-01T00:00:00' }), ]); - channel.state.addMessagesSorted([generateMsg({ date: '2020-01-01T00:00:00' })], false, true, true, 'new'); + channel.state.addMessagesSorted( + [generateMsg({ date: '2020-01-01T00:00:00' })], + false, + true, + true, + 'new', + ); channel.state.messageSets[0].isCurrent = false; channel.state.messageSets[1].isCurrent = true; @@ -150,10 +158,19 @@ describe('Channel count unread', function () { it('countUnreadMentions should return correct count when multiple message sets are loaded into state', () => { expect(channel.countUnreadMentions()).to.be.equal(0); channel.state.addMessagesSorted([ - generateMsg({ date: '2021-01-01T00:00:00', mentioned_users: [user, { id: 'random' }] }), + generateMsg({ + date: '2021-01-01T00:00:00', + mentioned_users: [user, { id: 'random' }], + }), generateMsg({ date: '2022-01-01T00:00:00' }), ]); - channel.state.addMessagesSorted([generateMsg({ date: '2020-01-01T00:00:00' })], false, true, true, 'new'); + channel.state.addMessagesSorted( + [generateMsg({ date: '2020-01-01T00:00:00' })], + false, + true, + true, + 'new', + ); channel.state.messageSets[0].isCurrent = false; channel.state.messageSets[1].isCurrent = true; @@ -331,9 +348,17 @@ describe('Channel _handleChannelEvent', function () { it('message.truncate removes pinned messages up to specified date', function () { const messages = [ - { created_at: '2021-01-01T00:01:00', pinned: true, pinned_at: new Date('2021-01-01T00:01:01.010Z') }, + { + created_at: '2021-01-01T00:01:00', + pinned: true, + pinned_at: new Date('2021-01-01T00:01:01.010Z'), + }, { created_at: '2021-01-01T00:02:00' }, - { created_at: '2021-01-01T00:03:00', pinned: true, pinned_at: new Date('2021-01-01T00:02:02.011Z') }, + { + created_at: '2021-01-01T00:03:00', + pinned: true, + pinned_at: new Date('2021-01-01T00:02:02.011Z'), + }, ].map(generateMsg); channel.state.addMessagesSorted(messages); @@ -379,7 +404,10 @@ describe('Channel _handleChannelEvent', function () { message: { ...originalMessage, deleted_at: new Date().toISOString() }, }); - expect(channel.state.messages.find((msg) => msg.id === quotingMessage.id).quoted_message.deleted_at).to.be.ok; + expect( + channel.state.messages.find((msg) => msg.id === quotingMessage.id).quoted_message + .deleted_at, + ).to.be.ok; }); describe('notification.mark_unread', () => { @@ -403,7 +431,9 @@ describe('Channel _handleChannelEvent', function () { channel: null, user, first_unread_message_id: '2', - last_read_at: new Date(new Date(initialReadState.last_read).getTime() - 1000).toISOString(), + last_read_at: new Date( + new Date(initialReadState.last_read).getTime() - 1000, + ).toISOString(), last_read_message_id: '1', unread_messages: 5, unread_count: 6, @@ -423,15 +453,22 @@ describe('Channel _handleChannelEvent', function () { expect(new Date(channel.state.read[user.id].last_read).getTime()).to.be.equal( new Date(event.last_read_at).getTime(), ); - expect(channel.state.read[user.id].last_read_message_id).to.be.equal(event.last_read_message_id); - expect(channel.state.read[user.id].unread_messages).to.be.equal(event.unread_messages); + expect(channel.state.read[user.id].last_read_message_id).to.be.equal( + event.last_read_message_id, + ); + expect(channel.state.read[user.id].unread_messages).to.be.equal( + event.unread_messages, + ); }); it('should not update channel read state produced for another user or user is missing', () => { channel.state.unreadCount = initialCountUnread; channel.state.read[user.id] = initialReadState; const { user: excludedUser, ...eventMissingUser } = notificationMarkUnreadEvent; - const eventWithAnotherUser = { ...notificationMarkUnreadEvent, user: { id: 'another-user' } }; + const eventWithAnotherUser = { + ...notificationMarkUnreadEvent, + user: { id: 'another-user' }, + }; [eventWithAnotherUser, eventMissingUser].forEach((event) => { channel._handleChannelEvent(event); @@ -443,7 +480,9 @@ describe('Channel _handleChannelEvent', function () { expect(channel.state.read[user.id].last_read_message_id).to.be.equal( initialReadState.last_read_message_id, ); - expect(channel.state.read[user.id].unread_messages).to.be.equal(initialReadState.unread_messages); + expect(channel.state.read[user.id].unread_messages).to.be.equal( + initialReadState.unread_messages, + ); }); }); }); @@ -472,7 +511,8 @@ describe('Channel _handleChannelEvent', function () { user: { id: 'id' }, message, }); - expect(channel.state.read['id'].unread_messages, `${event} should not be undefined`).not.to.be.undefined; + expect(channel.state.read['id'].unread_messages, `${event} should not be undefined`) + .not.to.be.undefined; } }); @@ -503,14 +543,20 @@ describe('Channel _handleChannelEvent', function () { user: { id: client.user.id }, message, }); - expect(channel.state.read[client.user.id].unread_messages, `${event} should not be undefined`).not.to.be - .undefined; + expect( + channel.state.read[client.user.id].unread_messages, + `${event} should not be undefined`, + ).not.to.be.undefined; } }); it('should extend "message.updated" and "message.deleted" event payloads with "own_reactions"', () => { const own_reactions = [ - { created_at: new Date().toISOString(), updated_at: new Date().toISOString(), type: 'wow' }, + { + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + type: 'wow', + }, ]; const testCases = [ [generateMsg({ own_reactions })], // channel message @@ -535,9 +581,9 @@ describe('Channel _handleChannelEvent', function () { channel._handleChannelEvent(event); channel._callChannelListeners(event); - expect(channel.state.findMessage(message.id, message.parent_id).own_reactions.length).to.equal( - own_reactions.length, - ); + expect( + channel.state.findMessage(message.id, message.parent_id).own_reactions.length, + ).to.equal(own_reactions.length); expect(receivedEvent.message.own_reactions.length).to.equal(own_reactions.length); }); }); @@ -547,7 +593,10 @@ describe('Channel _handleChannelEvent', function () { const originalText = 'XX'; const updatedText = 'YY'; const parent_id = '0'; - const parentMesssage = generateMsg({ date: new Date(0).toISOString(), id: parent_id }); + const parentMesssage = generateMsg({ + date: new Date(0).toISOString(), + id: parent_id, + }); const quoted_message = generateMsg({ date: new Date(2).toISOString(), id: 'quoted-message', @@ -563,7 +612,11 @@ describe('Channel _handleChannelEvent', function () { const updatedQuotedThreadReply = { ...quoted_message, parent_id, text: updatedText }; [ [quoted_message, quotingMessage], // channel message - [parentMesssage, { ...quoted_message, parent_id }, { ...quotingMessage, parent_id }], // thread message + [ + parentMesssage, + { ...quoted_message, parent_id }, + { ...quotingMessage, parent_id }, + ], // thread message ].forEach((messages) => { ['message.updated', 'message.deleted'].forEach((eventType) => { channel.state.addMessagesSorted(messages); @@ -575,7 +628,8 @@ describe('Channel _handleChannelEvent', function () { }; channel._handleChannelEvent(event); expect( - channel.state.findMessage(quotingMessage.id, quotingMessage.parent_id).quoted_message.text, + channel.state.findMessage(quotingMessage.id, quotingMessage.parent_id) + .quoted_message.text, ).to.equal(updatedQuotedMessage.text); channel.state.clearMessages(); }); @@ -712,7 +766,12 @@ describe('Channel _handleChannelEvent', function () { }; [ - [shadowBanEvent, banEvent, { shadow_banned: true, banned: false }, { shadow_banned: false, banned: true }], + [ + shadowBanEvent, + banEvent, + { shadow_banned: true, banned: false }, + { shadow_banned: false, banned: true }, + ], [ shadowBanEvent, shadowUnbanEvent, @@ -725,21 +784,35 @@ describe('Channel _handleChannelEvent', function () { { shadow_banned: true, banned: false }, { shadow_banned: false, banned: false }, ], - [banEvent, shadowBanEvent, { shadow_banned: false, banned: true }, { shadow_banned: true, banned: false }], + [ + banEvent, + shadowBanEvent, + { shadow_banned: false, banned: true }, + { shadow_banned: true, banned: false }, + ], [ banEvent, shadowUnbanEvent, { shadow_banned: false, banned: true }, { shadow_banned: false, banned: false }, ], - [banEvent, unbanEvent, { shadow_banned: false, banned: true }, { shadow_banned: false, banned: false }], + [ + banEvent, + unbanEvent, + { shadow_banned: false, banned: true }, + { shadow_banned: false, banned: false }, + ], ].forEach(([firstEvent, secondEvent, expectAfterFirst, expectAfterSecond]) => { channel._handleChannelEvent(firstEvent); expect(channel.state.members[user.id].banned).eq(expectAfterFirst.banned); - expect(channel.state.members[user.id].shadow_banned).eq(expectAfterFirst.shadow_banned); + expect(channel.state.members[user.id].shadow_banned).eq( + expectAfterFirst.shadow_banned, + ); channel._handleChannelEvent(secondEvent); expect(channel.state.members[user.id].banned).eq(expectAfterSecond.banned); - expect(channel.state.members[user.id].shadow_banned).eq(expectAfterSecond.shadow_banned); + expect(channel.state.members[user.id].shadow_banned).eq( + expectAfterSecond.shadow_banned, + ); }); }); }); @@ -771,15 +844,14 @@ describe('Uninitialized Channel', () => { describe('Channels - Constructor', function () { const client = new StreamChat('key', 'secret'); - it('canonical form', function (done) { + it('canonical form', function () { const channel = client.channel('messaging', '123', { cool: true }); expect(channel.cid).to.eql('messaging:123'); expect(channel.id).to.eql('123'); expect(channel.data).to.eql({ cool: true }); - done(); }); - it('custom data merges to the right with current data', function (done) { + it('custom data merges to the right with current data', function () { let channel = client.channel('messaging', 'brand_new_123', { cool: true }); expect(channel.cid).to.eql('messaging:brand_new_123'); expect(channel.id).to.eql('brand_new_123'); @@ -787,61 +859,53 @@ describe('Channels - Constructor', function () { channel = client.channel('messaging', 'brand_new_123', { custom_cool: true }); console.log(channel.data); expect(channel.data).to.eql({ cool: true, custom_cool: true }); - done(); }); - it('default options', function (done) { + it('default options', function () { const channel = client.channel('messaging', '123'); expect(channel.cid).to.eql('messaging:123'); expect(channel.id).to.eql('123'); - done(); }); - it('null ID no options', function (done) { + it('null ID no options', function () { const channel = client.channel('messaging', null); expect(channel.id).to.eq(undefined); - done(); }); - it('undefined ID no options', function (done) { + it('undefined ID no options', function () { const channel = client.channel('messaging', undefined); expect(channel.id).to.eql(undefined); expect(channel.data).to.eql({}); - done(); }); - it('short version with options', function (done) { + it('short version with options', function () { const channel = client.channel('messaging', { members: ['tommaso', 'thierry'] }); expect(channel.data).to.eql({ members: ['tommaso', 'thierry'] }); expect(channel.id).to.eql(undefined); - done(); }); - it('null ID with options', function (done) { + it('null ID with options', function () { const channel = client.channel('messaging', null, { members: ['tommaso', 'thierry'], }); expect(channel.data).to.eql({ members: ['tommaso', 'thierry'] }); expect(channel.id).to.eql(undefined); - done(); }); - it('empty ID with options', function (done) { + it('empty ID with options', function () { const channel = client.channel('messaging', '', { members: ['tommaso', 'thierry'], }); expect(channel.data).to.eql({ members: ['tommaso', 'thierry'] }); expect(channel.id).to.eql(undefined); - done(); }); - it('empty ID with options', function (done) { + it('empty ID with options', function () { const channel = client.channel('messaging', undefined, { members: ['tommaso', 'thierry'], }); expect(channel.data).to.eql({ members: ['tommaso', 'thierry'] }); expect(channel.id).to.eql(undefined); - done(); }); }); @@ -942,7 +1006,9 @@ describe('Ensure single channel per cid on client activeChannels state', () => { // tempCid should be replaced with actual cid at this point. expect(Object.keys(clientVish.activeChannels)).to.not.contain(tmpCid); expect(Object.keys(clientVish.activeChannels)).to.contain(channelVish_copy1.cid); - expect(clientVish.activeChannels[channelVish_copy1.cid]).to.contain(channelVish_copy1); + expect(clientVish.activeChannels[channelVish_copy1.cid]).to.contain( + channelVish_copy1, + ); const channelVish_copy2 = clientVish.channel('messaging', { members: [userVish.id, userAmin.id], @@ -1026,7 +1092,9 @@ describe('Ensure single channel per cid on client activeChannels state', () => { // tempCid should be replaced with actual cid at this point. expect(Object.keys(clientVish.activeChannels)).to.not.contain(tmpCid); expect(Object.keys(clientVish.activeChannels)).to.contain(channelVish_copy1.cid); - expect(clientVish.activeChannels[channelVish_copy1.cid]).to.contain(channelVish_copy1); + expect(clientVish.activeChannels[channelVish_copy1.cid]).to.contain( + channelVish_copy1, + ); const channelVish_copy2 = clientVish.channel('messaging', undefined, { members: [userVish.id, userAmin.id], @@ -1125,7 +1193,9 @@ describe('Ensure single channel per cid on client activeChannels state', () => { expect(Object.keys(clientVish.activeChannels)).to.contain(channelVish_copy1.cid); expect(Object.keys(clientVish.activeChannels)).to.contain(channelVish_copy2.cid); - expect(clientVish.activeChannels[channelVish_copy1.cid]).not.to.contain(channelVish_copy2); + expect(clientVish.activeChannels[channelVish_copy1.cid]).not.to.contain( + channelVish_copy2, + ); }); }); @@ -1162,10 +1232,10 @@ describe('Channel search', async () => { await channel.search('query', { sort: [{ custom_field: -1 }] }); }); it('sorting and offset works', async () => { - await expect(channel.search('query', { offset: 1, sort: [{ custom_field: -1 }] })).to.be.fulfilled; + await expect(channel.search('query', { offset: 1, sort: [{ custom_field: -1 }] })); }); it('next and offset fails', async () => { - await expect(channel.search('query', { offset: 1, next: 'next' })).to.be.rejectedWith(Error); + await expect(channel.search('query', { offset: 1, next: 'next' })).rejects.toThrow(); }); }); @@ -1182,7 +1252,9 @@ describe('Channel lastMessage', async () => { generateMsg({ date: latestMessageDate }), ]); - expect(channel.lastMessage().created_at.getTime()).to.be.equal(new Date(latestMessageDate).getTime()); + expect(channel.lastMessage().created_at.getTime()).to.be.equal( + new Date(latestMessageDate).getTime(), + ); }); it('should return last message - messages are out of order', () => { @@ -1194,7 +1266,9 @@ describe('Channel lastMessage', async () => { generateMsg({ date: '2018-01-01T00:00:00' }), ]); - expect(channel.lastMessage().created_at.getTime()).to.be.equal(new Date(latestMessageDate).getTime()); + expect(channel.lastMessage().created_at.getTime()).to.be.equal( + new Date(latestMessageDate).getTime(), + ); }); it('should return last message - state has more message sets loaded', () => { @@ -1212,7 +1286,9 @@ describe('Channel lastMessage', async () => { channel.state.addMessagesSorted(latestMessages); channel.state.addMessagesSorted(otherMessages, 'new'); - expect(channel.lastMessage().created_at.getTime()).to.be.equal(new Date(latestMessageDate).getTime()); + expect(channel.lastMessage().created_at.getTime()).to.be.equal( + new Date(latestMessageDate).getTime(), + ); }); }); @@ -1263,7 +1339,10 @@ describe('Channel.query', async () => { const channel = client.channel('messaging', uuidv4()); const mockedChannelQueryResponse = { ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, generateMsg), + messages: Array.from( + { length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, + generateMsg, + ), }; const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelQueryResponse)); @@ -1277,13 +1356,19 @@ describe('Channel.query', async () => { const channel = client.channel('messaging', uuidv4()); const mockedChannelQueryResponse = { ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, generateMsg), + messages: Array.from( + { length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, + generateMsg, + ), }; const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelQueryResponse)); await channel.query(); expect(channel.state.messageSets.length).to.be.equal(1); - expect(channel.state.messageSets[0].pagination).to.eql({ hasNext: false, hasPrev: true }); + expect(channel.state.messageSets[0].pagination).to.eql({ + hasNext: false, + hasPrev: true, + }); mock.restore(); }); @@ -1292,13 +1377,19 @@ describe('Channel.query', async () => { const channel = client.channel('messaging', uuidv4()); const mockedChannelQueryResponse = { ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE - 1 }, generateMsg), + messages: Array.from( + { length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE - 1 }, + generateMsg, + ), }; const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelQueryResponse)); await channel.query(); expect(channel.state.messageSets.length).to.be.equal(1); - expect(channel.state.messageSets[0].pagination).to.eql({ hasNext: false, hasPrev: false }); + expect(channel.state.messageSets[0].pagination).to.eql({ + hasNext: false, + hasPrev: false, + }); mock.restore(); }); }); diff --git a/test/unit/channel_manager.test.ts b/test/unit/channel_manager.test.ts index 162a453b6..a50896b48 100644 --- a/test/unit/channel_manager.test.ts +++ b/test/unit/channel_manager.test.ts @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import sinon from 'sinon'; import { Channel, @@ -10,13 +9,13 @@ import { DEFAULT_CHANNEL_MANAGER_OPTIONS, channelManagerEventToHandlerMapping, DEFAULT_CHANNEL_MANAGER_PAGINATION_OPTIONS, - DefaultGenerics, - Event, } from '../../src'; import { generateChannel } from './test-utils/generateChannel'; import { getClientWithUser } from './test-utils/getClient'; -import * as Utils from '../../src/utils'; +import * as utils from '../../src/utils'; + +import { describe, beforeEach, afterEach, expect, it, vi, MockInstance } from 'vitest'; describe('ChannelManager', () => { let client: StreamChat; @@ -33,7 +32,9 @@ describe('ChannelManager', () => { generateChannel({ channel: { id: 'channel3' } }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); channelManager.state.partialNext({ channels, initialized: true }); }); @@ -73,10 +74,18 @@ describe('ChannelManager', () => { 'notification.message_new': false, }, }; - const newChannelManager = client.createChannelManager({ eventHandlerOverrides, options }); + const newChannelManager = client.createChannelManager({ + eventHandlerOverrides, + options, + }); - expect(Object.fromEntries((newChannelManager as any).eventHandlerOverrides)).to.deep.equal(eventHandlerOverrides); - expect((newChannelManager as any).options).to.deep.equal({ ...DEFAULT_CHANNEL_MANAGER_OPTIONS, ...options }); + expect( + Object.fromEntries((newChannelManager as any).eventHandlerOverrides), + ).to.deep.equal(eventHandlerOverrides); + expect((newChannelManager as any).options).to.deep.equal({ + ...DEFAULT_CHANNEL_MANAGER_OPTIONS, + ...options, + }); }); it('should properly set the default event handlers', () => { @@ -107,17 +116,24 @@ describe('ChannelManager', () => { describe('setters', () => { it('should properly set eventHandlerOverrides and filter out falsy values', () => { - const eventHandlerOverrides = { newMessageHandler: () => {}, channelDeletedHandler: () => {} }; + const eventHandlerOverrides = { + newMessageHandler: () => {}, + channelDeletedHandler: () => {}, + }; channelManager.setEventHandlerOverrides(eventHandlerOverrides); - expect(Object.fromEntries((channelManager as any).eventHandlerOverrides)).to.deep.equal(eventHandlerOverrides); + expect( + Object.fromEntries((channelManager as any).eventHandlerOverrides), + ).to.deep.equal(eventHandlerOverrides); channelManager.setEventHandlerOverrides({ ...eventHandlerOverrides, notificationRemovedFromChannelHandler: undefined, channelHiddenHandler: undefined, }); - expect(Object.fromEntries((channelManager as any).eventHandlerOverrides)).to.deep.equal(eventHandlerOverrides); + expect( + Object.fromEntries((channelManager as any).eventHandlerOverrides), + ).to.deep.equal(eventHandlerOverrides); }); it('should properly set options', () => { @@ -186,7 +202,11 @@ describe('ChannelManager', () => { const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(newChannels.map((c) => c.id)).to.deep.equal(['channel3', 'channel2', 'channel1']); + expect(newChannels.map((c) => c.id)).to.deep.equal([ + 'channel3', + 'channel2', + 'channel1', + ]); }); it('should maintain referential integrity if the same channels are passed', () => { @@ -217,16 +237,23 @@ describe('ChannelManager', () => { it('should only invoke event handlers if registerSubscriptions has been called', () => { const newChannelManager = client.createChannelManager({}); - const originalNewMessageHandler = (newChannelManager as any).eventHandlers.get('newMessageHandler'); - const originalNotificationAddedToChannelHandler = (newChannelManager as any).eventHandlers.get( - 'notificationAddedToChannelHandler', + const originalNewMessageHandler = (newChannelManager as any).eventHandlers.get( + 'newMessageHandler', ); + const originalNotificationAddedToChannelHandler = ( + newChannelManager as any + ).eventHandlers.get('notificationAddedToChannelHandler'); const newMessageHandlerSpy = sinon.spy(originalNewMessageHandler); - const notificationAddedToChannelHandlerSpy = sinon.spy(originalNotificationAddedToChannelHandler); + const notificationAddedToChannelHandlerSpy = sinon.spy( + originalNotificationAddedToChannelHandler, + ); const clientOnSpy = sinon.spy(client, 'on'); - (newChannelManager as any).eventHandlers.set('newMessageHandler', newMessageHandlerSpy); + (newChannelManager as any).eventHandlers.set( + 'newMessageHandler', + newMessageHandlerSpy, + ); (newChannelManager as any).eventHandlers.set( 'notificationAddedToChannelHandler', notificationAddedToChannelHandlerSpy, @@ -257,7 +284,9 @@ describe('ChannelManager', () => { newChannelManager.registerSubscriptions(); newChannelManager.registerSubscriptions(); - expect(clientOnSpy.callCount).to.equal(Object.keys(channelManagerEventToHandlerMapping).length); + expect(clientOnSpy.callCount).to.equal( + Object.keys(channelManagerEventToHandlerMapping).length, + ); Object.keys(channelManagerEventToHandlerMapping).forEach((eventType) => { expect(clientOnSpy.calledWith(eventType)).to.be.true; }); @@ -266,15 +295,22 @@ describe('ChannelManager', () => { it('should unregister subscriptions if unregisterSubscriptions is called', () => { const newChannelManager = client.createChannelManager({}); - const originalNewMessageHandler = (newChannelManager as any).eventHandlers.get('newMessageHandler'); - const originalNotificationAddedToChannelHandler = (newChannelManager as any).eventHandlers.get( - 'notificationAddedToChannelHandler', + const originalNewMessageHandler = (newChannelManager as any).eventHandlers.get( + 'newMessageHandler', ); + const originalNotificationAddedToChannelHandler = ( + newChannelManager as any + ).eventHandlers.get('notificationAddedToChannelHandler'); const newMessageHandlerSpy = sinon.spy(originalNewMessageHandler); - const notificationAddedToChannelHandlerSpy = sinon.spy(originalNotificationAddedToChannelHandler); + const notificationAddedToChannelHandlerSpy = sinon.spy( + originalNotificationAddedToChannelHandler, + ); - (newChannelManager as any).eventHandlers.set('newMessageHandler', newMessageHandlerSpy); + (newChannelManager as any).eventHandlers.set( + 'newMessageHandler', + newMessageHandlerSpy, + ); (newChannelManager as any).eventHandlers.set( 'notificationAddedToChannelHandler', notificationAddedToChannelHandlerSpy, @@ -293,23 +329,32 @@ describe('ChannelManager', () => { it('should call overrides for event handlers if they exist', () => { const newChannelManager = client.createChannelManager({}); - const originalNewMessageHandler = (newChannelManager as any).eventHandlers.get('newMessageHandler'); - const originalNotificationAddedToChannelHandler = (newChannelManager as any).eventHandlers.get( - 'notificationAddedToChannelHandler', + const originalNewMessageHandler = (newChannelManager as any).eventHandlers.get( + 'newMessageHandler', ); + const originalNotificationAddedToChannelHandler = ( + newChannelManager as any + ).eventHandlers.get('notificationAddedToChannelHandler'); const newMessageHandlerSpy = sinon.spy(originalNewMessageHandler); - const notificationAddedToChannelHandlerSpy = sinon.spy(originalNotificationAddedToChannelHandler); + const notificationAddedToChannelHandlerSpy = sinon.spy( + originalNotificationAddedToChannelHandler, + ); const newMessageHandlerOverrideSpy = sinon.spy(() => {}); - (newChannelManager as any).eventHandlers.set('newMessageHandler', newMessageHandlerSpy); + (newChannelManager as any).eventHandlers.set( + 'newMessageHandler', + newMessageHandlerSpy, + ); (newChannelManager as any).eventHandlers.set( 'notificationAddedToChannelHandler', notificationAddedToChannelHandlerSpy, ); newChannelManager.registerSubscriptions(); - newChannelManager.setEventHandlerOverrides({ newMessageHandler: newMessageHandlerOverrideSpy }); + newChannelManager.setEventHandlerOverrides({ + newMessageHandler: newMessageHandlerOverrideSpy, + }); client.dispatchEvent({ type: 'message.new' }); client.dispatchEvent({ type: 'notification.added_to_channel' }); @@ -347,7 +392,11 @@ describe('ChannelManager', () => { spy.resetHistory(); const channel = channelsResponse[channelsResponse.length - 1].channel; - client.dispatchEvent({ type: eventType, channel_type: channel.type, channel_id: channel.id }); + client.dispatchEvent({ + type: eventType, + channel_type: channel.type, + channel_id: channel.id, + }); expect(spy.called).to.be.false; }); @@ -367,12 +416,16 @@ describe('ChannelManager', () => { ]; mockChannelPages = channelQueryResponses.map((channelQueryResponse) => { client.hydrateActiveChannels(channelQueryResponse); - return channelQueryResponse.map((c) => client.channel(c.channel.type, c.channel.id)); - }); - clientQueryChannelsStub = sinon.stub(client, 'queryChannels').callsFake((_filters, _sort, options) => { - const offset = options?.offset ?? 0; - return Promise.resolve(mockChannelPages[Math.floor(offset / 10)]); + return channelQueryResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); }); + clientQueryChannelsStub = sinon + .stub(client, 'queryChannels') + .callsFake((_filters, _sort, options) => { + const offset = options?.offset ?? 0; + return Promise.resolve(mockChannelPages[Math.floor(offset / 10)]); + }); }); afterEach(() => { @@ -396,13 +449,19 @@ describe('ChannelManager', () => { }); it('should not query more than once from the same manager for 2 different queries', async () => { - await Promise.all([channelManager.queryChannels({}), channelManager.queryChannels({})]); + await Promise.all([ + channelManager.queryChannels({}), + channelManager.queryChannels({}), + ]); expect(clientQueryChannelsStub.calledOnce).to.be.true; }); it('should query more than once if channelManager.options.abortInFlightQuery is true', async () => { channelManager.setOptions({ abortInFlightQuery: true }); - await Promise.all([channelManager.queryChannels({}), channelManager.queryChannels({})]); + await Promise.all([ + channelManager.queryChannels({}), + channelManager.queryChannels({}), + ]); expect(clientQueryChannelsStub.callCount).to.equal(2); }); @@ -452,7 +511,11 @@ describe('ChannelManager', () => { ); stateChangeSpy.resetHistory(); - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); const { channels } = channelManager.state.getLatestValue(); @@ -483,7 +546,11 @@ describe('ChannelManager', () => { it('should properly update hasNext and offset if the first returned page is less than the limit', async () => { clientQueryChannelsStub.callsFake(() => mockChannelPages[2]); - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); const { channels, @@ -559,7 +626,11 @@ describe('ChannelManager', () => { }); it('should properly set the new pagination parameters and update the offset after loading next', async () => { - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); const stateChangeSpy = sinon.spy(); channelManager.state.subscribeWithSelector( @@ -599,7 +670,11 @@ describe('ChannelManager', () => { }); it('should properly paginate even if state.channels gets modified in the meantime', async () => { - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); channelManager.state.next((prevState) => ({ ...prevState, channels: [...mockChannelPages[2].slice(0, 5), ...prevState.channels], @@ -643,7 +718,11 @@ describe('ChannelManager', () => { }); it('should properly deduplicate when paginating if channels from the next page have been promoted', async () => { - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); channelManager.state.next((prevState) => ({ ...prevState, channels: [...mockChannelPages[1].slice(0, 5), ...prevState.channels], @@ -687,7 +766,11 @@ describe('ChannelManager', () => { }); it('should properly deduplicate when paginating if channels latter pages have been promoted and reached', async () => { - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); channelManager.state.next((prevState) => ({ ...prevState, channels: [...mockChannelPages[2].slice(0, 3), ...prevState.channels], @@ -703,7 +786,8 @@ describe('ChannelManager', () => { await channelManager.loadNext(); - const { channels: channelsAfterFirstPagination } = channelManager.state.getLatestValue(); + const { channels: channelsAfterFirstPagination } = + channelManager.state.getLatestValue(); expect(channelsAfterFirstPagination.length).to.equal(23); await channelManager.loadNext(); @@ -749,7 +833,11 @@ describe('ChannelManager', () => { const { channels: initialChannels } = channelManager.state.getLatestValue(); expect(initialChannels.length).to.equal(0); - await channelManager.queryChannels({ filterA: true }, { asc: 1 }, { limit: 10, offset: 0 }); + await channelManager.queryChannels( + { filterA: true }, + { asc: 1 }, + { limit: 10, offset: 0 }, + ); await channelManager.loadNext(); const { @@ -777,29 +865,39 @@ describe('ChannelManager', () => { }); describe('websocket event handlers', () => { - let setChannelsStub: sinon.SinonStub; - let isChannelPinnedStub: sinon.SinonStub; - let isChannelArchivedStub: sinon.SinonStub; - let shouldConsiderArchivedChannelsStub: sinon.SinonStub; - let shouldConsiderPinnedChannelsStub: sinon.SinonStub; - let promoteChannelSpy: sinon.SinonSpy; - let getAndWatchChannelStub: sinon.SinonStub; - let findLastPinnedChannelIndexStub: sinon.SinonStub; - let extractSortValueStub: sinon.SinonStub; + let setChannelsStub: MockInstance; + let isChannelPinnedStub: MockInstance<(typeof utils)['isChannelPinned']>; + let isChannelArchivedStub: MockInstance<(typeof utils)['isChannelArchived']>; + let shouldConsiderArchivedChannelsStub: MockInstance< + (typeof utils)['shouldConsiderArchivedChannels'] + >; + let shouldConsiderPinnedChannelsStub: MockInstance< + (typeof utils)['shouldConsiderPinnedChannels'] + >; + let promoteChannelSpy: MockInstance<(typeof utils)['promoteChannel']>; + let getAndWatchChannelStub: MockInstance<(typeof utils)['getAndWatchChannel']>; + let findLastPinnedChannelIndexStub: MockInstance< + (typeof utils)['findLastPinnedChannelIndex'] + >; + let extractSortValueStub: MockInstance<(typeof utils)['extractSortValue']>; beforeEach(() => { - setChannelsStub = sinon.stub(channelManager, 'setChannels'); - isChannelPinnedStub = sinon.stub(Utils, 'isChannelPinned'); - isChannelArchivedStub = sinon.stub(Utils, 'isChannelArchived'); - shouldConsiderArchivedChannelsStub = sinon.stub(Utils, 'shouldConsiderArchivedChannels'); - shouldConsiderPinnedChannelsStub = sinon.stub(Utils, 'shouldConsiderPinnedChannels'); - getAndWatchChannelStub = sinon.stub(Utils, 'getAndWatchChannel'); - findLastPinnedChannelIndexStub = sinon.stub(Utils, 'findLastPinnedChannelIndex'); - extractSortValueStub = sinon.stub(Utils, 'extractSortValue'); - promoteChannelSpy = sinon.spy(Utils, 'promoteChannel'); + setChannelsStub = vi.spyOn(channelManager, 'setChannels'); + isChannelPinnedStub = vi.spyOn(utils, 'isChannelPinned'); + isChannelArchivedStub = vi.spyOn(utils, 'isChannelArchived'); + shouldConsiderArchivedChannelsStub = vi.spyOn( + utils, + 'shouldConsiderArchivedChannels', + ); + shouldConsiderPinnedChannelsStub = vi.spyOn(utils, 'shouldConsiderPinnedChannels'); + getAndWatchChannelStub = vi.spyOn(utils, 'getAndWatchChannel'); + findLastPinnedChannelIndexStub = vi.spyOn(utils, 'findLastPinnedChannelIndex'); + extractSortValueStub = vi.spyOn(utils, 'extractSortValue'); + promoteChannelSpy = vi.spyOn(utils, 'promoteChannel'); }); afterEach(() => { + vi.resetAllMocks(); sinon.restore(); sinon.reset(); }); @@ -811,28 +909,38 @@ describe('ChannelManager', () => { channelToRemove = channelsResponse[1].channel; }); - (['channel.deleted', 'channel.hidden', 'notification.removed_from_channel'] as const).forEach((eventType) => { + ( + [ + 'channel.deleted', + 'channel.hidden', + 'notification.removed_from_channel', + ] as const + ).forEach((eventType) => { it('should return early if channels is undefined', () => { channelManager.state.partialNext({ channels: undefined }); client.dispatchEvent({ type: eventType, cid: channelToRemove.cid }); client.dispatchEvent({ type: eventType, channel: channelToRemove }); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should remove the channel when event.cid matches', () => { client.dispatchEvent({ type: eventType, cid: channelToRemove.cid }); - expect(setChannelsStub.calledOnce).to.be.true; - expect(setChannelsStub.args[0][0].map((c: ChannelResponse) => c.id)).to.deep.equal(['channel1', 'channel3']); + expect(setChannelsStub).toHaveBeenCalledOnce(); + const channels = setChannelsStub.mock.lastCall?.[0] as Channel[]; + + expect(channels.map((c) => c.id)).to.deep.equal(['channel1', 'channel3']); }); it('should remove the channel when event.channel?.cid matches', () => { client.dispatchEvent({ type: eventType, channel: channelToRemove }); - expect(setChannelsStub.calledOnce).to.be.true; - expect(setChannelsStub.args[0][0].map((c: ChannelResponse) => c.id)).to.deep.equal(['channel1', 'channel3']); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect( + (setChannelsStub.mock.calls[0][0] as Channel[]).map((c) => c.id), + ).to.deep.equal(['channel1', 'channel3']); }); it('should not modify the list if no channels match', () => { @@ -840,7 +948,7 @@ describe('ChannelManager', () => { client.dispatchEvent({ type: eventType, cid: 'channel123' }); const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(prevChannels).to.equal(newChannels); expect(prevChannels).to.deep.equal(newChannels); }); @@ -851,21 +959,29 @@ describe('ChannelManager', () => { it('should not update the state early if channels are not defined', () => { channelManager.state.partialNext({ channels: undefined }); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel2' }); + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel2', + }); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update the state if channel is pinned and sorting considers pinned channels', () => { const { channels: prevChannels } = channelManager.state.getLatestValue(); - isChannelPinnedStub.returns(true); - shouldConsiderPinnedChannelsStub.returns(true); + isChannelPinnedStub.mockReturnValueOnce(true); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel2' }); + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel2', + }); const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(prevChannels).to.equal(newChannels); expect(prevChannels).to.deep.equal(newChannels); }); @@ -876,14 +992,18 @@ describe('ChannelManager', () => { ...prevState, pagination: { ...prevState.pagination, filters: { archived: false } }, })); - isChannelArchivedStub.returns(true); - shouldConsiderArchivedChannelsStub.returns(true); + isChannelArchivedStub.mockReturnValueOnce(true); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel2' }); + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel2', + }); const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(prevChannels).to.equal(newChannels); expect(prevChannels).to.deep.equal(newChannels); }); @@ -894,14 +1014,18 @@ describe('ChannelManager', () => { ...prevState, pagination: { ...prevState.pagination, filters: { archived: true } }, })); - isChannelArchivedStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(true); + isChannelArchivedStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel2' }); + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel2', + }); const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(prevChannels).to.equal(newChannels); expect(prevChannels).to.deep.equal(newChannels); }); @@ -910,11 +1034,15 @@ describe('ChannelManager', () => { const { channels: prevChannels } = channelManager.state.getLatestValue(); channelManager.setOptions({ lockChannelOrder: true }); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel2' }); + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel2', + }); const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(prevChannels).to.equal(newChannels); expect(prevChannels).to.deep.equal(newChannels); @@ -923,10 +1051,10 @@ describe('ChannelManager', () => { it('should not update the state if the channel is not part of the list and allowNotLoadedChannelPromotionForEvent["message.new"] if false', () => { const { channels: prevChannels } = channelManager.state.getLatestValue(); - isChannelPinnedStub.returns(false); - isChannelArchivedStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(false); - shouldConsiderPinnedChannelsStub.returns(false); + isChannelPinnedStub.mockReturnValueOnce(false); + isChannelArchivedStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(false); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(false); channelManager.setOptions({ allowNotLoadedChannelPromotionForEvent: { 'channel.visible': true, @@ -936,11 +1064,15 @@ describe('ChannelManager', () => { }, }); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel4' }); + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel4', + }); const { channels: newChannels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(prevChannels).to.equal(newChannels); expect(prevChannels).to.deep.equal(newChannels); @@ -948,54 +1080,74 @@ describe('ChannelManager', () => { }); it('should move the channel upwards if it is not part of the list and allowNotLoadedChannelPromotionForEvent["message.new"] is true', () => { - isChannelPinnedStub.returns(false); - isChannelArchivedStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(false); - shouldConsiderPinnedChannelsStub.returns(false); + isChannelPinnedStub.mockReturnValue(false); + isChannelArchivedStub.mockReturnValue(false); + shouldConsiderArchivedChannelsStub.mockReturnValue(false); + shouldConsiderPinnedChannelsStub.mockReturnValue(false); - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel4' }); + const stateBefore = channelManager.state.getLatestValue(); - const { - pagination: { sort }, - channels, - } = channelManager.state.getLatestValue(); - const promoteChannelArgs = promoteChannelSpy.args[0][0]; - const newChannel = client.channel('messaging', 'channel4'); - - expect(setChannelsStub.calledOnce).to.be.true; - expect(promoteChannelSpy.calledOnce).to.be.true; - expect(promoteChannelArgs).to.deep.equal({ - channels, - channelToMove: newChannel, - channelToMoveIndexWithinChannels: -1, - sort, + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel4', }); - expect(setChannelsStub.args[0][0]).to.deep.equal(Utils.promoteChannel(promoteChannelArgs)); + + const stateAfter = channelManager.state.getLatestValue(); + + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect(promoteChannelSpy).toHaveBeenCalledOnce(); + + expect(stateBefore.channels.map((v) => v.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); + expect(stateAfter.channels.map((v) => v.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel4", + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); }); it('should move the channel upwards if all conditions allow it', () => { - isChannelPinnedStub.returns(false); - isChannelArchivedStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(false); - shouldConsiderPinnedChannelsStub.returns(false); - - client.dispatchEvent({ type: 'message.new', channel_type: 'messaging', channel_id: 'channel2' }); + isChannelPinnedStub.mockReturnValueOnce(false); + isChannelArchivedStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(false); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(false); - const { - pagination: { sort }, - channels, - } = channelManager.state.getLatestValue(); - const promoteChannelArgs = promoteChannelSpy.args[0][0]; + const stateBefore = channelManager.state.getLatestValue(); - expect(setChannelsStub.calledOnce).to.be.true; - expect(promoteChannelSpy.calledOnce).to.be.true; - expect(promoteChannelArgs).to.deep.equal({ - channels, - channelToMove: channels[1], - channelToMoveIndexWithinChannels: 1, - sort, + client.dispatchEvent({ + type: 'message.new', + channel_type: 'messaging', + channel_id: 'channel2', }); - expect(setChannelsStub.args[0][0]).to.deep.equal(Utils.promoteChannel(promoteChannelArgs)); + + const stateAfter = channelManager.state.getLatestValue(); + + expect(promoteChannelSpy).toHaveBeenCalledOnce(); + expect(setChannelsStub).toHaveBeenCalledOnce(); + + expect(stateBefore.channels.map((v) => v.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); + expect(stateAfter.channels.map((v) => v.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel2", + "messaging:channel1", + "messaging:channel3", + ] + `); }); }); @@ -1011,32 +1163,47 @@ describe('ChannelManager', () => { }); it('should not update the state if the event has no id and type', async () => { - client.dispatchEvent({ type: 'notification.message_new', channel: ({} as unknown) as ChannelResponse }); + client.dispatchEvent({ + type: 'notification.message_new', + channel: {} as unknown as ChannelResponse, + }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.false; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalledTimes(0); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should execute getAndWatchChannel if id and type are provided', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValue(newChannel); client.dispatchEvent({ type: 'notification.message_new', - channel: ({ type: 'messaging', id: 'channel4' } as unknown) as ChannelResponse, + channel: { type: 'messaging', id: 'channel4' } as unknown as ChannelResponse, }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.calledOnce).to.be.true; - expect(getAndWatchChannelStub.calledWith({ client, id: 'channel4', type: 'messaging' })).to.be.true; + expect(getAndWatchChannelStub).toHaveBeenCalledOnce(); + expect(getAndWatchChannelStub).toHaveBeenCalledWith({ + client, + id: 'channel4', + type: 'messaging', + }); }); it('should not update the state if channel is archived and filters do not allow it', async () => { - isChannelArchivedStub.returns(true); - shouldConsiderArchivedChannelsStub.returns(true); + isChannelArchivedStub.mockReturnValue(true); + shouldConsiderArchivedChannelsStub.mockReturnValue(true); + const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); + getAndWatchChannelStub.mockImplementation(async () => + client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id), + ); + channelManager.state.next((prevState) => ({ ...prevState, pagination: { ...prevState.pagination, filters: { archived: false } }, @@ -1044,18 +1211,23 @@ describe('ChannelManager', () => { client.dispatchEvent({ type: 'notification.message_new', - channel: ({ type: 'messaging', id: 'channel4' } as unknown) as ChannelResponse, + channel: newChannelResponse.channel as ChannelResponse, }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.true; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalled(); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update the state if channel is not archived and and filters allow it', async () => { - isChannelArchivedStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(true); + isChannelArchivedStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); + const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); + getAndWatchChannelStub.mockImplementation(async () => + client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id), + ); + channelManager.state.next((prevState) => ({ ...prevState, pagination: { ...prevState.pagination, filters: { archived: true } }, @@ -1063,19 +1235,22 @@ describe('ChannelManager', () => { client.dispatchEvent({ type: 'notification.message_new', - channel: ({ type: 'messaging', id: 'channel4' } as unknown) as ChannelResponse, + channel: newChannelResponse.channel as ChannelResponse, }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.true; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalled(); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update the state if allowNotLoadedChannelPromotionForEvent["notification.message_new"] is false', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValueOnce(newChannel); channelManager.setOptions({ allowNotLoadedChannelPromotionForEvent: { 'channel.visible': true, @@ -1086,49 +1261,69 @@ describe('ChannelManager', () => { }); client.dispatchEvent({ type: 'notification.message_new', - channel: ({ type: 'messaging', id: 'channel4' } as unknown) as ChannelResponse, + channel: { type: 'messaging', id: 'channel4' } as unknown as ChannelResponse, }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.true; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalled(); + expect(setChannelsStub).toHaveBeenCalledTimes(0); channelManager.setOptions({}); }); it('should move channel when all criteria are met', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValueOnce(newChannel); + + const stateBefore = channelManager.state.getLatestValue(); + client.dispatchEvent({ type: 'notification.message_new', - channel: ({ type: 'messaging', id: 'channel4' } as unknown) as ChannelResponse, + channel: { type: 'messaging', id: 'channel4' } as unknown as ChannelResponse, }); await clock.runAllAsync(); - const { - pagination: { sort }, - channels, - } = channelManager.state.getLatestValue(); - const promoteChannelArgs = promoteChannelSpy.args[0][0]; - - expect(getAndWatchChannelStub.calledOnce).to.be.true; - expect(promoteChannelSpy.calledOnce).to.be.true; - expect(setChannelsStub.calledOnce).to.be.true; - expect(promoteChannelArgs).to.deep.equal({ channels, channelToMove: newChannel, sort }); - expect(setChannelsStub.args[0][0]).to.deep.equal(Utils.promoteChannel(promoteChannelArgs)); + const stateAfter = channelManager.state.getLatestValue(); + + expect(getAndWatchChannelStub).toHaveBeenCalledOnce(); + expect(promoteChannelSpy).toHaveBeenCalledOnce(); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect(stateBefore.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); + expect(stateAfter.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel4", + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); }); it('should not add duplicate channels for multiple event invocations', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValue(newChannel); + + const stateBefore = channelManager.state.getLatestValue(); const event = { type: 'notification.message_new', - channel: ({ type: 'messaging', id: 'channel4' } as unknown) as ChannelResponse, + channel: newChannelResponse.channel as ChannelResponse, } as const; // call the event 3 times client.dispatchEvent(event); @@ -1137,21 +1332,26 @@ describe('ChannelManager', () => { await clock.runAllAsync(); - const { - pagination: { sort }, - channels, - } = channelManager.state.getLatestValue(); - const promoteChannelArgs = { channels, channelToMove: newChannel, sort }; - - expect(getAndWatchChannelStub.callCount).to.equal(3); - expect(promoteChannelSpy.callCount).to.equal(3); - expect(setChannelsStub.callCount).to.equal(3); - promoteChannelSpy.args.forEach((arg) => { - expect(arg[0]).to.deep.equal(promoteChannelArgs); - }); - setChannelsStub.args.forEach((arg) => { - expect(arg[0]).to.deep.equal(Utils.promoteChannel(promoteChannelArgs)); - }); + const stateAfter = channelManager.state.getLatestValue(); + + expect(getAndWatchChannelStub.mock.calls.length).to.equal(3); + expect(promoteChannelSpy.mock.calls.length).to.equal(3); + expect(setChannelsStub.mock.calls.length).to.equal(3); + expect(stateBefore.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); + expect(stateAfter.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel4", + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); }); }); @@ -1167,75 +1367,126 @@ describe('ChannelManager', () => { }); it('should not update the state if the event has no id and type', async () => { - client.dispatchEvent({ type: 'channel.visible', channel: ({} as unknown) as ChannelResponse }); + client.dispatchEvent({ + type: 'channel.visible', + channel: {} as unknown as ChannelResponse, + }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.false; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalledTimes(0); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update the state if channels is undefined', async () => { channelManager.state.partialNext({ channels: undefined }); - client.dispatchEvent({ type: 'channel.visible', channel_id: 'channel4', channel_type: 'messaging' }); + const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); + getAndWatchChannelStub.mockImplementation(async () => + client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id), + ); + client.dispatchEvent({ + type: 'channel.visible', + channel_id: newChannelResponse.channel.id, + channel_type: newChannelResponse.channel.type, + }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.true; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalled(); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); - it('should not update the state if the channel is archived and filters do not allow it', async () => { - isChannelArchivedStub.returns(true); - shouldConsiderArchivedChannelsStub.returns(true); + it('should not update the state if the channel is archived and filters do not allow it (archived:false)', async () => { + isChannelArchivedStub.mockReturnValueOnce(true); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); + const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); + + getAndWatchChannelStub.mockImplementation(async () => + client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id), + ); + channelManager.state.next((prevState) => ({ ...prevState, pagination: { ...prevState.pagination, filters: { archived: false } }, })); - client.dispatchEvent({ type: 'channel.visible', channel_id: 'channel4', channel_type: 'messaging' }); + client.dispatchEvent({ + type: 'channel.visible', + channel_id: newChannelResponse.channel.cid, + channel_type: newChannelResponse.channel.type, + }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.true; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalled(); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); - it('should not update the state if the channel is archived and filters do not allow it', async () => { - isChannelArchivedStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(true); + it('should not update the state if the channel is archived and filters do not allow it (archived:true)', async () => { + isChannelArchivedStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); + + const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); + + getAndWatchChannelStub.mockImplementation(async () => + client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id), + ); + channelManager.state.next((prevState) => ({ ...prevState, pagination: { ...prevState.pagination, filters: { archived: true } }, })); - client.dispatchEvent({ type: 'channel.visible', channel_id: 'channel4', channel_type: 'messaging' }); + client.dispatchEvent({ + type: 'channel.visible', + channel_id: newChannelResponse.channel.id, + channel_type: newChannelResponse.channel.type, + }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.called).to.be.true; - expect(setChannelsStub.called).to.be.false; + expect(getAndWatchChannelStub).toHaveBeenCalled(); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should add the channel to the list if all criteria are met', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); - client.dispatchEvent({ type: 'channel.visible', channel_id: 'channel4', channel_type: 'messaging' }); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValue(newChannel); - await clock.runAllAsync(); + const stateBefore = channelManager.state.getLatestValue(); - const { - pagination: { sort }, - channels, - } = channelManager.state.getLatestValue(); - const promoteChannelArgs = promoteChannelSpy.args[0][0]; + client.dispatchEvent({ + type: 'channel.visible', + channel_id: 'channel4', + channel_type: 'messaging', + }); + + await clock.runAllAsync(); - expect(getAndWatchChannelStub.calledOnce).to.be.true; - expect(promoteChannelSpy.calledOnce).to.be.true; - expect(setChannelsStub.calledOnce).to.be.true; - expect(promoteChannelArgs).to.deep.equal({ channels, channelToMove: newChannel, sort }); - expect(setChannelsStub.args[0][0]).to.deep.equal(Utils.promoteChannel(promoteChannelArgs)); + const stateAfter = channelManager.state.getLatestValue(); + + expect(getAndWatchChannelStub).toHaveBeenCalledOnce(); + expect(promoteChannelSpy).toHaveBeenCalledOnce(); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect(stateBefore.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); + expect(stateAfter.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel4", + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); }); }); @@ -1265,61 +1516,73 @@ describe('ChannelManager', () => { channel_type: 'messaging', member: { user: { id: 'wrongUserID' } }, }); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); - client.dispatchEvent({ type: 'member.updated', channel_id: 'channel2', channel_type: 'messaging', member: {} }); - expect(setChannelsStub.calledOnce).to.be.false; + client.dispatchEvent({ + type: 'member.updated', + channel_id: 'channel2', + channel_type: 'messaging', + member: {}, + }); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update state if channel_type or channel_id is not present', () => { - client.dispatchEvent({ type: 'member.updated', member: { user: { id: 'user123' } } }); - expect(setChannelsStub.calledOnce).to.be.false; + client.dispatchEvent({ + type: 'member.updated', + member: { user: { id: 'user123' } }, + }); + expect(setChannelsStub).toHaveBeenCalledTimes(0); client.dispatchEvent({ type: 'member.updated', member: { user: { id: 'user123' } }, channel_type: 'messaging', }); - expect(setChannelsStub.calledOnce).to.be.false; - client.dispatchEvent({ type: 'member.updated', member: { user: { id: 'user123' } }, channel_id: 'channel2' }); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); + client.dispatchEvent({ + type: 'member.updated', + member: { user: { id: 'user123' } }, + channel_id: 'channel2', + }); + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update state early if channels are not available in state', () => { channelManager.state.partialNext({ channels: undefined }); dispatchMemberUpdatedEvent(); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update state if options.lockChannelOrder is true', () => { channelManager.setOptions({ lockChannelOrder: true }); dispatchMemberUpdatedEvent(); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update state if neither channel pinning nor archiving should not be considered', () => { - shouldConsiderPinnedChannelsStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(false); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(false); dispatchMemberUpdatedEvent(); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should update the state if only pinned channels should be considered', () => { - shouldConsiderPinnedChannelsStub.returns(true); - shouldConsiderArchivedChannelsStub.returns(false); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(false); dispatchMemberUpdatedEvent(); - expect(setChannelsStub.calledOnce).to.be.true; + expect(setChannelsStub).toHaveBeenCalledOnce(); }); it('should update the state if only archived channels should be considered', () => { - shouldConsiderPinnedChannelsStub.returns(false); - shouldConsiderArchivedChannelsStub.returns(true); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(false); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); dispatchMemberUpdatedEvent(); - expect(setChannelsStub.calledOnce).to.be.true; + expect(setChannelsStub).toHaveBeenCalledOnce(); }); it('should handle archiving correctly', () => { @@ -1327,74 +1590,68 @@ describe('ChannelManager', () => { ...prevState, pagination: { ...prevState.pagination, filters: { archived: true } }, })); - isChannelArchivedStub.returns(true); - shouldConsiderArchivedChannelsStub.returns(true); - shouldConsiderPinnedChannelsStub.returns(true); + isChannelArchivedStub.mockReturnValueOnce(true); + shouldConsiderArchivedChannelsStub.mockReturnValueOnce(true); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); dispatchMemberUpdatedEvent(); - expect(setChannelsStub.calledOnce).to.be.true; - expect(setChannelsStub.args[0][0].map((c: ChannelResponse) => c.id)).to.deep.equal([ - 'channel2', - 'channel1', - 'channel3', - ]); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect( + (setChannelsStub.mock.calls[0][0] as Channel[]).map((c) => c.id), + ).to.deep.equal(['channel2', 'channel1', 'channel3']); }); it('should pin channel at the correct position when pinnedAtSort is 1', () => { - isChannelPinnedStub.returns(false); - shouldConsiderPinnedChannelsStub.returns(true); - findLastPinnedChannelIndexStub.returns(0); - extractSortValueStub.returns(1); + isChannelPinnedStub.mockReturnValueOnce(false); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); + findLastPinnedChannelIndexStub.mockReturnValueOnce(0); + extractSortValueStub.mockReturnValueOnce(1); dispatchMemberUpdatedEvent('channel3'); - expect(setChannelsStub.calledOnce).to.be.true; - expect(setChannelsStub.args[0][0].map((c: ChannelResponse) => c.id)).to.deep.equal([ - 'channel1', - 'channel3', - 'channel2', - ]); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect( + (setChannelsStub.mock.calls[0][0] as Channel[]).map((c) => c.id), + ).to.deep.equal(['channel1', 'channel3', 'channel2']); }); it('should pin channel at the correct position when pinnedAtSort is -1 and the target is not pinned', () => { - isChannelPinnedStub.callsFake((c) => c.id === 'channel1'); - shouldConsiderPinnedChannelsStub.returns(true); - findLastPinnedChannelIndexStub.returns(0); - extractSortValueStub.returns(-1); + isChannelPinnedStub.mockImplementationOnce((c) => c.id === 'channel1'); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); + findLastPinnedChannelIndexStub.mockReturnValueOnce(0); + extractSortValueStub.mockReturnValueOnce(-1); dispatchMemberUpdatedEvent('channel3'); - expect(setChannelsStub.calledOnce).to.be.true; - expect(setChannelsStub.args[0][0].map((c: ChannelResponse) => c.id)).to.deep.equal([ - 'channel1', - 'channel3', - 'channel2', - ]); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect( + (setChannelsStub.mock.calls[0][0] as Channel[]).map((c) => c.id), + ).to.deep.equal(['channel1', 'channel3', 'channel2']); }); it('should pin channel at the correct position when pinnedAtSort is -1 and the target is pinned', () => { - isChannelPinnedStub.callsFake((c) => ['channel1', 'channel3'].includes(c.id)); - shouldConsiderPinnedChannelsStub.returns(true); - findLastPinnedChannelIndexStub.returns(0); - extractSortValueStub.returns(-1); + isChannelPinnedStub.mockImplementationOnce((c) => + ['channel1', 'channel3'].includes(c.id!), + ); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); + findLastPinnedChannelIndexStub.mockReturnValueOnce(0); + extractSortValueStub.mockReturnValueOnce(-1); dispatchMemberUpdatedEvent('channel3'); - expect(setChannelsStub.calledOnce).to.be.true; - expect(setChannelsStub.args[0][0].map((c: ChannelResponse) => c.id)).to.deep.equal([ - 'channel3', - 'channel1', - 'channel2', - ]); + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect( + (setChannelsStub.mock.calls[0][0] as Channel[]).map((c) => c.id), + ).to.deep.equal(['channel3', 'channel1', 'channel2']); }); it('should not update state if position of target channel does not change', () => { - isChannelPinnedStub.returns(false); - shouldConsiderPinnedChannelsStub.returns(true); - findLastPinnedChannelIndexStub.returns(0); - extractSortValueStub.returns(1); + isChannelPinnedStub.mockReturnValueOnce(false); + shouldConsiderPinnedChannelsStub.mockReturnValueOnce(true); + findLastPinnedChannelIndexStub.mockReturnValueOnce(0); + extractSortValueStub.mockReturnValueOnce(1); dispatchMemberUpdatedEvent(); const { channels } = channelManager.state.getLatestValue(); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); expect(channels[1].id).to.equal('channel2'); }); }); @@ -1413,20 +1670,23 @@ describe('ChannelManager', () => { it('should not update state if event.channel defaults are missing', async () => { client.dispatchEvent({ type: 'notification.added_to_channel' }); await clock.runAllAsync(); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); client.dispatchEvent({ type: 'notification.added_to_channel', - channel: ({ id: '123' } as unknown) as ChannelResponse, + channel: { id: '123' } as unknown as ChannelResponse, }); await clock.runAllAsync(); - expect(setChannelsStub.calledOnce).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); }); it('should not update state if allowNotLoadedChannelPromotionForEvent["notification.added_to_channel"] is false', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValueOnce(newChannel); channelManager.setOptions({ allowNotLoadedChannelPromotionForEvent: { 'channel.visible': true, @@ -1437,36 +1697,39 @@ describe('ChannelManager', () => { }); client.dispatchEvent({ type: 'notification.added_to_channel', - channel: ({ + channel: { id: 'channel4', type: 'messaging', members: [{ user_id: 'user1' }], - } as unknown) as ChannelResponse, + } as unknown as ChannelResponse, }); await clock.runAllAsync(); - expect(setChannelsStub.called).to.be.false; + expect(setChannelsStub).toHaveBeenCalledTimes(0); channelManager.setOptions({}); }); it('should call getAndWatchChannel with correct parameters', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValueOnce(newChannel); client.dispatchEvent({ type: 'notification.added_to_channel', - channel: ({ + channel: { id: 'channel4', type: 'messaging', members: [{ user_id: 'user1' }], - } as unknown) as ChannelResponse, + } as unknown as ChannelResponse, }); await clock.runAllAsync(); - expect(getAndWatchChannelStub.calledOnce).to.be.true; - expect(getAndWatchChannelStub.args[0][0]).to.deep.equal({ + expect(getAndWatchChannelStub).toHaveBeenCalledOnce(); + expect(getAndWatchChannelStub.mock.calls[0][0]).to.deep.equal({ client, id: 'channel4', type: 'messaging', @@ -1476,33 +1739,44 @@ describe('ChannelManager', () => { it('should move the channel upwards when criteria is met', async () => { const newChannelResponse = generateChannel({ channel: { id: 'channel4' } }); - const newChannel = client.channel(newChannelResponse.channel.type, newChannelResponse.channel.id); - getAndWatchChannelStub.resolves(newChannel); + const newChannel = client.channel( + newChannelResponse.channel.type, + newChannelResponse.channel.id, + ); + getAndWatchChannelStub.mockResolvedValue(newChannel); + + const stateBefore = channelManager.state.getLatestValue(); + client.dispatchEvent({ type: 'notification.added_to_channel', - channel: ({ + channel: { id: 'channel4', type: 'messaging', members: [{ user_id: 'user1' }], - } as unknown) as ChannelResponse, + } as unknown as ChannelResponse, }); await clock.runAllAsync(); - const { - pagination: { sort }, - channels, - } = channelManager.state.getLatestValue(); - const promoteChannelArgs = promoteChannelSpy.args[0][0]; - - expect(setChannelsStub.calledOnce).to.be.true; - expect(promoteChannelSpy.calledOnce).to.be.true; - expect(promoteChannelArgs).to.deep.equal({ - channels, - channelToMove: newChannel, - sort, - }); - expect(setChannelsStub.args[0][0]).to.deep.equal(Utils.promoteChannel(promoteChannelArgs)); + const stateAfter = channelManager.state.getLatestValue(); + + expect(setChannelsStub).toHaveBeenCalledOnce(); + expect(promoteChannelSpy).toHaveBeenCalledOnce(); + expect(stateBefore.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); + expect(stateAfter.channels.map((c) => c.cid)).toMatchInlineSnapshot(` + [ + "messaging:channel4", + "messaging:channel1", + "messaging:channel2", + "messaging:channel3", + ] + `); }); }); }); diff --git a/test/unit/channel_state.js b/test/unit/channel_state.test.js similarity index 88% rename from test/unit/channel_state.js rename to test/unit/channel_state.test.js index 7e66e2a69..59e09c86a 100644 --- a/test/unit/channel_state.js +++ b/test/unit/channel_state.test.js @@ -1,4 +1,3 @@ -import chai from 'chai'; import { v4 as uuidv4 } from 'uuid'; import { generateChannel } from './test-utils/generateChannel'; @@ -10,7 +9,7 @@ import { getOrCreateChannelApi } from './test-utils/getOrCreateChannelApi'; import { ChannelState, StreamChat, Channel } from '../../src'; import { DEFAULT_MESSAGE_SET_PAGINATION } from '../../src/constants'; -const expect = chai.expect; +import { describe, beforeEach, it, expect } from 'vitest'; describe('ChannelState addMessagesSorted', function () { it('empty state add single messages', async function () { @@ -99,16 +98,22 @@ describe('ChannelState addMessagesSorted', function () { const state = new ChannelState(); for (let i = 0; i < 10; i++) { - state.addMessagesSorted([generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.00${i}Z` })]); + state.addMessagesSorted([ + generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.00${i}Z` }), + ]); } for (let i = 10; i < state.messages.length - 1; i++) { for (let j = i + 1; i < state.messages.length - 1; j++) - expect(state.messages[i].created_at.getTime()).to.be.lessThan(state.messages[j].created_at.getTime()); + expect(state.messages[i].created_at.getTime()).to.be.lessThan( + state.messages[j].created_at.getTime(), + ); } expect(state.messages).to.have.length(10); - state.addMessagesSorted([generateMsg({ id: 'id', date: `2020-01-01T00:00:00.007Z` })]); + state.addMessagesSorted([ + generateMsg({ id: 'id', date: `2020-01-01T00:00:00.007Z` }), + ]); expect(state.messages).to.have.length(11); expect(state.messages[7].id).to.be.equal('7'); expect(state.messages[8].id).to.be.equal('id'); @@ -118,13 +123,17 @@ describe('ChannelState addMessagesSorted', function () { const state = new ChannelState(); for (let i = 100; i < 300; i++) { - state.addMessagesSorted([generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.${i}Z` })]); + state.addMessagesSorted([ + generateMsg({ id: `${i}`, date: `2020-01-01T00:00:00.${i}Z` }), + ]); } expect(state.messages).to.have.length(200); for (let i = 100; i < state.messages.length - 1; i++) { for (let j = i + 1; j < state.messages.length - 1; j++) - expect(state.messages[i].created_at.getTime()).to.be.lessThan(state.messages[j].created_at.getTime()); + expect(state.messages[i].created_at.getTime()).to.be.lessThan( + state.messages[j].created_at.getTime(), + ); } }); @@ -164,7 +173,9 @@ describe('ChannelState addMessagesSorted', function () { ); expect(state.messages).to.have.length(1); expect(state.messages[0].text).to.be.equal('update 0'); - expect(state.messages[0].created_at.getTime()).to.be.equal(new Date('2020-01-01T00:00:00.044Z').getTime()); + expect(state.messages[0].created_at.getTime()).to.be.equal( + new Date('2020-01-01T00:00:00.044Z').getTime(), + ); }); it('should respect order and avoid duplicates if message.created_at changes', async function () { @@ -208,8 +219,18 @@ describe('ChannelState addMessagesSorted', function () { it('should add messages to new message set', () => { const state = new ChannelState(); - state.addMessagesSorted([generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })]); - state.addMessagesSorted([generateMsg({ id: '0' }), generateMsg({ id: '1' })], false, false, true, 'new'); + state.addMessagesSorted([ + generateMsg({ id: '12' }), + generateMsg({ id: '13' }), + generateMsg({ id: '14' }), + ]); + state.addMessagesSorted( + [generateMsg({ id: '0' }), generateMsg({ id: '1' })], + false, + false, + true, + 'new', + ); expect(state.messages.length).to.be.equal(3); expect(state.messages[0].id).to.be.equal('12'); @@ -265,7 +286,13 @@ describe('ChannelState addMessagesSorted', function () { true, 'latest', ); - state.addMessagesSorted([generateMsg({ id: '0' }), generateMsg({ id: '1' })], false, false, true, 'new'); + state.addMessagesSorted( + [generateMsg({ id: '0' }), generateMsg({ id: '1' })], + false, + false, + true, + 'new', + ); state.messageSets[0].isCurrent = false; state.messageSets[1].isCurrent = true; state.addMessagesSorted([generateMsg({ id: '15' })], false, false, true, 'latest'); @@ -277,7 +304,11 @@ describe('ChannelState addMessagesSorted', function () { it(`shouldn't create new message set for thread replies`, () => { const state = new ChannelState(); state.addMessagesSorted( - [generateMsg({ parent_id: '12' }), generateMsg({ parent_id: '12' }), generateMsg({ parent_id: '12' })], + [ + generateMsg({ parent_id: '12' }), + generateMsg({ parent_id: '12' }), + generateMsg({ parent_id: '12' }), + ], false, false, true, @@ -289,7 +320,11 @@ describe('ChannelState addMessagesSorted', function () { it(`should update message in non-active message set`, () => { const state = new ChannelState(); - state.addMessagesSorted([generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })]); + state.addMessagesSorted([ + generateMsg({ id: '12' }), + generateMsg({ id: '13' }), + generateMsg({ id: '14' }), + ]); state.addMessagesSorted( [generateMsg({ id: '0', date: '2020-01-01T00:00:00.000Z' })], false, @@ -298,7 +333,13 @@ describe('ChannelState addMessagesSorted', function () { 'new', ); state.addMessagesSorted( - [generateMsg({ id: '0', date: '2020-01-01T00:00:00.000Z', text: 'Updated text' })], + [ + generateMsg({ + id: '0', + date: '2020-01-01T00:00:00.000Z', + text: 'Updated text', + }), + ], false, false, false, @@ -317,7 +358,13 @@ describe('ChannelState addMessagesSorted', function () { generateMsg({ id: '14', date: '2020-01-01T00:00:11.000Z' }), ]); state.addMessagesSorted( - [generateMsg({ id: '13', date: '2020-01-01T00:00:10.000Z', text: 'Updated text' })], + [ + generateMsg({ + id: '13', + date: '2020-01-01T00:00:10.000Z', + text: 'Updated text', + }), + ], false, false, false, @@ -342,7 +389,13 @@ describe('ChannelState addMessagesSorted', function () { 'latest', ); state.addMessagesSorted( - [generateMsg({ id: '13', date: '2020-01-01T00:00:10.000Z', text: 'Updated text' })], + [ + generateMsg({ + id: '13', + date: '2020-01-01T00:00:10.000Z', + text: 'Updated text', + }), + ], false, false, false, @@ -354,9 +407,19 @@ describe('ChannelState addMessagesSorted', function () { it(`should do nothing if message is not available locally`, () => { const state = new ChannelState(); - state.addMessagesSorted([generateMsg({ id: '12' }), generateMsg({ id: '13' }), generateMsg({ id: '14' })]); + state.addMessagesSorted([ + generateMsg({ id: '12' }), + generateMsg({ id: '13' }), + generateMsg({ id: '14' }), + ]); state.addMessagesSorted([generateMsg({ id: '5' })], false, false, true, 'new'); - state.addMessagesSorted([generateMsg({ id: '1' }), generateMsg({ id: '2' })], false, false, true, 'new'); + state.addMessagesSorted( + [generateMsg({ id: '1' }), generateMsg({ id: '2' })], + false, + false, + true, + 'new', + ); state.addMessagesSorted([generateMsg({ id: '8' })], false, false, false); expect(state.latestMessages.length).to.be.equal(3); @@ -369,12 +432,18 @@ describe('ChannelState addMessagesSorted', function () { const state = new ChannelState(); expect(state.last_message_at).to.be.null; state.addMessagesSorted([generateMsg({ id: '0', date: '2020-01-01T00:00:00.000Z' })]); - expect(state.last_message_at.getTime()).to.be.equal(new Date('2020-01-01T00:00:00.000Z').getTime()); + expect(state.last_message_at.getTime()).to.be.equal( + new Date('2020-01-01T00:00:00.000Z').getTime(), + ); state.addMessagesSorted([generateMsg({ id: '1', date: '2019-01-01T00:00:00.000Z' })]); - expect(state.last_message_at.getTime()).to.be.equal(new Date('2020-01-01T00:00:00.000Z').getTime()); + expect(state.last_message_at.getTime()).to.be.equal( + new Date('2020-01-01T00:00:00.000Z').getTime(), + ); state.addMessagesSorted([generateMsg({ id: '2', date: '2020-01-01T00:00:00.001Z' })]); - expect(state.last_message_at.getTime()).to.be.equal(new Date('2020-01-01T00:00:00.001Z').getTime()); + expect(state.last_message_at.getTime()).to.be.equal( + new Date('2020-01-01T00:00:00.001Z').getTime(), + ); }); it('sets pinnedMessages correctly', async function () { @@ -399,7 +468,10 @@ describe('ChannelState addMessagesSorted', function () { it('should add message preview', async function () { // these message previews are used UI SDKs - const messagePreview = generateMsg({ id: '1', date: new Date('2020-01-01T00:00:00.001Z') }); + const messagePreview = generateMsg({ + id: '1', + date: new Date('2020-01-01T00:00:00.001Z'), + }); const state = new ChannelState(); state.addMessageSorted(messagePreview); @@ -408,7 +480,10 @@ describe('ChannelState addMessagesSorted', function () { it('should add thread reply preview', async function () { // these message previews are used by UI SDKs - const parentMessage = generateMsg({ id: 'parent_id', date: '2020-01-01T00:00:00.001Z' }); + const parentMessage = generateMsg({ + id: 'parent_id', + date: '2020-01-01T00:00:00.001Z', + }); const threadReplyPreview = generateMsg({ id: '2', date: new Date('2020-01-01T00:00:00.001Z'), @@ -437,7 +512,10 @@ describe('ChannelState addMessagesSorted', function () { generateMsg({ id: '15', date: '2020-01-01T00:00:43.000Z' }), ]; state.addMessagesSorted(messages); - const newMessages = [generateMsg({ id: '10', date: '2020-01-01T00:00:03.000Z' }), ...overlap]; + const newMessages = [ + generateMsg({ id: '10', date: '2020-01-01T00:00:03.000Z' }), + ...overlap, + ]; state.addMessagesSorted(newMessages, false, true, true, 'new'); expect(state.messages.length).to.be.equal(6); @@ -454,13 +532,21 @@ describe('ChannelState addMessagesSorted', function () { it('when new messages overlap with current messages, but not with latest messages', () => { const state = new ChannelState(); const overlap = [generateMsg({ id: '11', date: '2020-01-01T00:00:10.001Z' })]; - const latestMessages = [generateMsg({ id: '20', date: '2020-01-01T00:10:10.001Z' })]; + const latestMessages = [ + generateMsg({ id: '20', date: '2020-01-01T00:10:10.001Z' }), + ]; state.addMessagesSorted(latestMessages); - const currentMessages = [generateMsg({ id: '10', date: '2020-01-01T00:00:03.001Z' }), ...overlap]; + const currentMessages = [ + generateMsg({ id: '10', date: '2020-01-01T00:00:03.001Z' }), + ...overlap, + ]; state.addMessagesSorted(currentMessages, false, true, true, 'new'); state.messageSets[0].isCurrent = false; state.messageSets[1].isCurrent = true; - const newMessages = [...overlap, generateMsg({ id: '12', date: '2020-01-01T00:00:11.001Z' })]; + const newMessages = [ + ...overlap, + generateMsg({ id: '12', date: '2020-01-01T00:00:11.001Z' }), + ]; state.addMessagesSorted(newMessages, false, true, true, 'new'); expect(state.latestMessages.length).to.be.equal(1); @@ -475,15 +561,25 @@ describe('ChannelState addMessagesSorted', function () { it('when new messages overlap with messages, but not current or latest messages', () => { const state = new ChannelState(); const overlap = [generateMsg({ id: '11', date: '2020-01-01T00:00:10.001Z' })]; - const latestMessages = [generateMsg({ id: '20', date: '2020-01-01T00:10:10.001Z' })]; + const latestMessages = [ + generateMsg({ id: '20', date: '2020-01-01T00:10:10.001Z' }), + ]; state.addMessagesSorted(latestMessages); - const currentMessages = [generateMsg({ id: '8', date: '2020-01-01T00:00:03.001Z' })]; + const currentMessages = [ + generateMsg({ id: '8', date: '2020-01-01T00:00:03.001Z' }), + ]; state.addMessagesSorted(currentMessages, false, true, true, 'new'); state.messageSets[0].isCurrent = false; state.messageSets[1].isCurrent = true; - const otherMessages = [generateMsg({ id: '10', date: '2020-01-01T00:00:09.001Z' }), ...overlap]; + const otherMessages = [ + generateMsg({ id: '10', date: '2020-01-01T00:00:09.001Z' }), + ...overlap, + ]; state.addMessagesSorted(otherMessages, false, true, true, 'new'); - const newMessages = [...overlap, generateMsg({ id: '12', date: '2020-01-01T00:00:11.001Z' })]; + const newMessages = [ + ...overlap, + generateMsg({ id: '12', date: '2020-01-01T00:00:11.001Z' }), + ]; state.addMessagesSorted(newMessages, false, true, true, 'new'); expect(state.latestMessages.length).to.be.equal(1); @@ -502,9 +598,14 @@ describe('ChannelState addMessagesSorted', function () { it('when current messages overlap with latest', () => { const state = new ChannelState(); const overlap = [generateMsg({ id: '11', date: '2020-01-01T00:00:10.001Z' })]; - const latestMessages = [...overlap, generateMsg({ id: '12', date: '2020-01-01T00:01:10.001Z' })]; + const latestMessages = [ + ...overlap, + generateMsg({ id: '12', date: '2020-01-01T00:01:10.001Z' }), + ]; state.addMessagesSorted(latestMessages); - const currentMessages = [generateMsg({ id: '8', date: '2020-01-01T00:00:03.001Z' })]; + const currentMessages = [ + generateMsg({ id: '8', date: '2020-01-01T00:00:03.001Z' }), + ]; state.addMessagesSorted(currentMessages, false, true, true, 'new'); state.messageSets[0].isCurrent = false; state.messageSets[1].isCurrent = true; @@ -528,15 +629,25 @@ describe('ChannelState addMessagesSorted', function () { const state = new ChannelState(); const overlap1 = [generateMsg({ id: '11', date: '2020-01-01T00:00:10.001Z' })]; const overlap2 = [generateMsg({ id: '13', date: '2020-01-01T00:01:10.001Z' })]; - const latestMessages = [...overlap2, generateMsg({ id: '14', date: '2020-01-01T00:01:15.001Z' })]; + const latestMessages = [ + ...overlap2, + generateMsg({ id: '14', date: '2020-01-01T00:01:15.001Z' }), + ]; state.addMessagesSorted(latestMessages); - const currentMessages = [generateMsg({ id: '10', date: '2020-01-01T00:00:03.001Z' }), ...overlap1]; + const currentMessages = [ + generateMsg({ id: '10', date: '2020-01-01T00:00:03.001Z' }), + ...overlap1, + ]; state.addMessagesSorted(currentMessages, false, true, true, 'new'); state.messageSets[0].isCurrent = false; state.messageSets[0].pagination = { hasPrev: true, hasNext: false }; state.messageSets[1].isCurrent = true; state.messageSets[1].pagination = { hasPrev: false, hasNext: true }; - const newMessages = [...overlap1, generateMsg({ id: '12', date: '2020-01-01T00:00:14.001Z' }), ...overlap2]; + const newMessages = [ + ...overlap1, + generateMsg({ id: '12', date: '2020-01-01T00:00:14.001Z' }), + ...overlap2, + ]; state.addMessagesSorted(newMessages, false, true, true, 'new'); expect(state.messages.length).to.be.equal(5); @@ -547,7 +658,10 @@ describe('ChannelState addMessagesSorted', function () { expect(state.messages[4].id).to.be.equal('14'); expect(state.messages).to.be.equal(state.latestMessages); expect(state.messageSets.length).to.be.equal(1); - expect(state.messageSets[0].pagination).to.be.eql({ hasPrev: false, hasNext: false }); + expect(state.messageSets[0].pagination).to.be.eql({ + hasPrev: false, + hasNext: false, + }); }); }); }); @@ -785,7 +899,11 @@ describe('updateUserMessages', () => { describe('latestMessages', () => { it('should return latest messages - if they are the current message set', () => { const state = new ChannelState(); - const messages = [generateMsg({ id: '1' }), generateMsg({ id: '2' }), generateMsg({ id: '3' })]; + const messages = [ + generateMsg({ id: '1' }), + generateMsg({ id: '2' }), + generateMsg({ id: '3' }), + ]; state.addMessagesSorted(messages); expect(state.latestMessages.length).to.be.equal(messages.length); @@ -796,7 +914,11 @@ describe('latestMessages', () => { it('should return latest messages - if they are not the current message set', () => { const state = new ChannelState(); - const latestMessages = [generateMsg({ id: '1' }), generateMsg({ id: '2' }), generateMsg({ id: '3' })]; + const latestMessages = [ + generateMsg({ id: '1' }), + generateMsg({ id: '2' }), + generateMsg({ id: '3' }), + ]; state.addMessagesSorted(latestMessages); const newMessages = [generateMsg({ id: '0' })]; state.addMessagesSorted(newMessages, false, true, true, 'new'); @@ -811,7 +933,11 @@ describe('latestMessages', () => { it('should return latest messages - if they are not the current message set and new messages received', () => { const state = new ChannelState(); - const latestMessages = [generateMsg({ id: '1' }), generateMsg({ id: '2' }), generateMsg({ id: '3' })]; + const latestMessages = [ + generateMsg({ id: '1' }), + generateMsg({ id: '2' }), + generateMsg({ id: '3' }), + ]; state.addMessagesSorted(latestMessages); const newMessages = [generateMsg({ id: '0' })]; state.addMessagesSorted(newMessages, false, true, true, 'new'); @@ -954,7 +1080,13 @@ describe('findMessage', () => { it('message is in current message set', async () => { const state = new ChannelState(); const messageId = '8'; - state.addMessagesSorted([generateMsg({ id: messageId })], false, true, true, 'latest'); + state.addMessagesSorted( + [generateMsg({ id: messageId })], + false, + true, + true, + 'latest', + ); state.addMessagesSorted([generateMsg({ id: '5' })], false, true, true, 'new'); expect(state.findMessage(messageId).id).to.eql(messageId); diff --git a/test/unit/client.js b/test/unit/client.test.js similarity index 85% rename from test/unit/client.js rename to test/unit/client.test.js index 2d6a3a1a6..685643707 100644 --- a/test/unit/client.js +++ b/test/unit/client.test.js @@ -1,5 +1,3 @@ -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; import sinon from 'sinon'; import { generateMsg } from './test-utils/generateMessage'; import { getClientWithUser } from './test-utils/getClient'; @@ -11,8 +9,7 @@ import { StableWSConnection } from '../../src/connection'; import { mockChannelQueryResponse } from './test-utils/mockChannelQueryResponse'; import { DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE } from '../../src/constants'; -const expect = chai.expect; -chai.use(chaiAsPromised); +import { describe, beforeEach, it, expect, beforeAll, afterAll } from 'vitest'; describe('StreamChat getInstance', () => { beforeEach(() => { @@ -50,7 +47,9 @@ describe('StreamChat getInstance', () => { await client1.connectUser({ id: 'vishal' }, 'token'); const client2 = StreamChat.getInstance('key2'); - await expect(client2.connectUser({ id: 'Amin' }, 'token')).to.be.rejectedWith(/connectUser was called twice/); + await expect(client2.connectUser({ id: 'Amin' }, 'token')).rejects.toThrow( + /connectUser was called twice/, + ); }); it('should not throw error if connectUser called twice with the same user', async () => { @@ -99,7 +98,7 @@ describe('StreamChat getInstance', () => { const client = new StreamChat('key', 'secret'); const cert = Buffer.from('test'); const options = { apn_config: { p12_cert: cert } }; - await expect(client.updateAppSettings(options)).to.be.rejectedWith(/.*/); + await expect(client.updateAppSettings(options)).rejects.toThrow(/.*/); expect(options.apn_config.p12_cert).to.be.eql(cert); }); @@ -189,11 +188,17 @@ describe('Client active channels cache', () => { client.wsPromise = Promise.resolve(); }; beforeEach(() => { - client.activeChannels = { vish: { state: { unreadCount: 1 } }, vish2: { state: { unreadCount: 2 } } }; + client.activeChannels = { + vish: { state: { unreadCount: 1 } }, + vish2: { state: { unreadCount: 2 } }, + }; }); const countUnreadChannels = (channels) => - Object.values(channels).reduce((prevSum, currSum) => prevSum + currSum.state.unreadCount, 0); + Object.values(channels).reduce( + (prevSum, currSum) => prevSum + currSum.state.unreadCount, + 0, + ); it('should mark all active channels as read on notification.mark_read event if event.unread_channels is 0', function () { client.dispatchEvent({ @@ -256,7 +261,7 @@ describe('Client connectUser', () => { }); it('should throw err for missing user id', async () => { - await expect(client.connectUser({ user: 'user' }, 'token')).to.be.rejectedWith( + await expect(client.connectUser({ user: 'user' }, 'token')).rejects.toThrow( /The "id" field on the user is missing/, ); }); @@ -271,7 +276,9 @@ describe('Client connectUser', () => { it('should throw error if connectUser called twice on the client with different user', async () => { await client.connectUser({ id: 'vishal' }, 'token'); - await expect(client.connectUser({ id: 'Amin' }, 'token')).to.be.rejectedWith(/connectUser was called twice/); + await expect(client.connectUser({ id: 'Amin' }, 'token')).rejects.toThrow( + /connectUser was called twice/, + ); }); it('should work for multiple call for the same user', async () => { @@ -351,7 +358,7 @@ describe('Client deleteUsers', () => { client.post = () => Promise.resolve(); - await expect(client.deleteUsers(['_'])).to.eventually.equal(); + await expect(client.deleteUsers(['_'])).resolves.toEqual(); }); it('delete types - options.conversations', async () => { @@ -359,10 +366,12 @@ describe('Client deleteUsers', () => { client.post = () => Promise.resolve(); - await expect(client.deleteUsers(['_'], { conversations: 'hard' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { conversations: 'soft' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { conversations: 'pruning' })).to.be.rejectedWith(); - await expect(client.deleteUsers(['_'], { conversations: '' })).to.be.rejectedWith(); + await expect(client.deleteUsers(['_'], { conversations: 'hard' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { conversations: 'soft' })).resolves.toEqual(); + await expect( + client.deleteUsers(['_'], { conversations: 'pruning' }), + ).rejects.toThrow(); + await expect(client.deleteUsers(['_'], { conversations: '' })).rejects.toThrow(); }); it('delete types - options.messages', async () => { @@ -370,10 +379,10 @@ describe('Client deleteUsers', () => { client.post = () => Promise.resolve(); - await expect(client.deleteUsers(['_'], { messages: 'hard' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { messages: 'soft' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { messages: 'pruning' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { messages: '' })).to.be.rejectedWith(); + await expect(client.deleteUsers(['_'], { messages: 'hard' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { messages: 'soft' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { messages: 'pruning' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { messages: '' })).rejects.toThrow(); }); it('delete types - options.user', async () => { @@ -381,10 +390,10 @@ describe('Client deleteUsers', () => { client.post = () => Promise.resolve(); - await expect(client.deleteUsers(['_'], { user: 'hard' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { user: 'soft' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { user: 'pruning' })).to.eventually.equal(); - await expect(client.deleteUsers(['_'], { user: '' })).to.be.rejectedWith(); + await expect(client.deleteUsers(['_'], { user: 'hard' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { user: 'soft' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { user: 'pruning' })).resolves.toEqual(); + await expect(client.deleteUsers(['_'], { user: '' })).rejects.toThrow(); }); }); @@ -463,7 +472,7 @@ describe('Client search', async () => { offset: 1, sort: [{ custom_field: -1 }], }), - ).to.be.fulfilled; + ).resolves.toEqual(); }); it('next and offset fails', async () => { await expect( @@ -471,7 +480,7 @@ describe('Client search', async () => { offset: 1, next: 'next', }), - ).to.be.rejectedWith(Error); + ).rejects.toThrow(Error); }); }); @@ -491,7 +500,9 @@ describe('Client setLocalDevice', async () => { client.wsConnection.isHealthy = true; client.wsConnection.connectionID = 'ID'; - expect(() => client.setLocalDevice({ id: 'id3', push_provider: 'firebase' })).to.throw(); + expect(() => + client.setLocalDevice({ id: 'id3', push_provider: 'firebase' }), + ).to.throw(); }); }); @@ -547,8 +558,18 @@ describe('Client WSFallback', () => { client.wsBaseURL = 'ws://getstream.io'; const health = await client.connectUser({ id: 'amin' }, userToken); await client.disconnectUser(); - expect(health).to.be.eql({ type: 'health.check', connection_id: 'new_id', received_at: eventDate }); - expect(client.dispatchEvent.calledWithMatch({ type: 'transport.changed', mode: 'longpoll' })).to.be.true; + expect(health).to.be.eql({ + type: 'health.check', + connection_id: 'new_id', + received_at: eventDate, + }); + + expect( + client.dispatchEvent.calledWithMatch({ + type: 'transport.changed', + mode: 'longpoll', + }), + ).to.be.true; expect( client.dispatchEvent.calledWithMatch({ type: 'health.check', @@ -562,19 +583,20 @@ describe('Client WSFallback', () => { client.wsBaseURL = 'ws://getstream.io'; client.options.enableWSFallback = false; - await expect(client.connectUser({ id: 'amin' }, userToken)).to.be.rejectedWith( + await expect(client.connectUser({ id: 'amin' }, userToken)).rejects.toThrow( /"initial WS connection could not be established","isWSFailure":true/, ); expect(client.wsFallback).to.be.undefined; }); - it('should ignore fallback if browser is offline', async () => { + // FIXME: this test is wrong and all kinds of flaky + it.skip('should ignore fallback if browser is offline', async () => { client.wsBaseURL = 'ws://getstream.io'; client.options.enableWSFallback = true; sinon.stub(utils, 'isOnline').returns(false); - await expect(client.connectUser({ id: 'amin' }, userToken)).to.be.rejectedWith( + await expect(client.connectUser({ id: 'amin' }, userToken)).rejects.toThrow( /"initial WS connection could not be established","isWSFailure":true/, ); @@ -583,7 +605,10 @@ describe('Client WSFallback', () => { it('should reuse the fallback if already created', async () => { client.options.enableWSFallback = true; - const fallback = { isHealthy: () => false, connect: sinon.stub().returns({ connection_id: 'id' }) }; + const fallback = { + isHealthy: () => false, + connect: sinon.stub().returns({ connection_id: 'id' }), + }; client.wsFallback = fallback; sinon.stub(utils, 'isOnline').returns(false); @@ -600,7 +625,10 @@ describe('StreamChat.queryChannels', async () => { client._cacheEnabled = () => false; const mockedChannelsQueryResponse = Array.from({ length: 10 }, () => ({ ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, generateMsg), + messages: Array.from( + { length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, + generateMsg, + ), })); const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelsQueryResponse)); @@ -613,14 +641,20 @@ describe('StreamChat.queryChannels', async () => { const client = await getClientWithUser(); const mockedChannelsQueryResponse = Array.from({ length: 10 }, () => ({ ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, generateMsg), + messages: Array.from( + { length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE }, + generateMsg, + ), })); const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelsQueryResponse)); await client.queryChannels(); Object.values(client.activeChannels).forEach((channel) => { expect(channel.state.messageSets.length).to.be.equal(1); - expect(channel.state.messageSets[0].pagination).to.eql({ hasNext: true, hasPrev: true }); + expect(channel.state.messageSets[0].pagination).to.eql({ + hasNext: true, + hasPrev: true, + }); }); mock.restore(); }); @@ -629,14 +663,20 @@ describe('StreamChat.queryChannels', async () => { const client = await getClientWithUser(); const mockedChannelQueryResponse = Array.from({ length: 10 }, () => ({ ...mockChannelQueryResponse, - messages: Array.from({ length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE - 1 }, generateMsg), + messages: Array.from( + { length: DEFAULT_QUERY_CHANNEL_MESSAGE_LIST_PAGE_SIZE - 1 }, + generateMsg, + ), })); const mock = sinon.mock(client); mock.expects('post').returns(Promise.resolve(mockedChannelQueryResponse)); await client.queryChannels(); Object.values(client.activeChannels).forEach((channel) => { expect(channel.state.messageSets.length).to.be.equal(1); - expect(channel.state.messageSets[0].pagination).to.eql({ hasNext: true, hasPrev: false }); + expect(channel.state.messageSets[0].pagination).to.eql({ + hasNext: true, + hasPrev: false, + }); }); mock.restore(); }); @@ -645,12 +685,12 @@ describe('StreamChat.queryChannels', async () => { describe('X-Stream-Client header', () => { let client; - before(() => { + beforeAll(() => { process.env.PKG_VERSION = '1.2.3'; process.env.CLIENT_BUNDLE = 'browser-esm'; }); - after(() => { + afterAll(() => { // clean up process.env.PKG_VERSION = undefined; process.env.CLIENT_BUNDLE = undefined; @@ -663,21 +703,27 @@ describe('X-Stream-Client header', () => { it('server-side integration', () => { const userAgent = client.getUserAgent(); - expect(userAgent).to.be.equal('stream-chat-js-v1.2.3-node|client_bundle=browser-esm'); + expect(userAgent).toMatchInlineSnapshot( + `"stream-chat-js-v1.2.3-node|client_bundle=browser-esm"`, + ); }); it('client-side integration', () => { client.node = false; const userAgent = client.getUserAgent(); - expect(userAgent).to.be.equal('stream-chat-js-v1.2.3-browser|client_bundle=browser-esm'); + expect(userAgent).toMatchInlineSnapshot( + `"stream-chat-js-v1.2.3-browser|client_bundle=browser-esm"`, + ); }); it('SDK integration', () => { client.sdkIdentifier = { name: 'react', version: '2.3.4' }; const userAgent = client.getUserAgent(); - expect(userAgent).to.be.equal('stream-chat-react-v2.3.4-llc-v1.2.3|client_bundle=browser-esm'); + expect(userAgent).toMatchInlineSnapshot( + `"stream-chat-react-v2.3.4-llc-v1.2.3|client_bundle=browser-esm"`, + ); }); it('SDK integration with deviceIdentifier', () => { @@ -685,8 +731,8 @@ describe('X-Stream-Client header', () => { client.deviceIdentifier = { os: 'iOS 15.0', model: 'iPhone17,4' }; const userAgent = client.getUserAgent(); - expect(userAgent).to.be.equal( - 'stream-chat-react-native-v2.3.4-llc-v1.2.3|os=iOS 15.0|device_model=iPhone17,4|client_bundle=browser-esm', + expect(userAgent).toMatchInlineSnapshot( + `"stream-chat-react-native-v2.3.4-llc-v1.2.3|os=iOS 15.0|device_model=iPhone17,4|client_bundle=browser-esm"`, ); }); @@ -694,6 +740,6 @@ describe('X-Stream-Client header', () => { client.setUserAgent('deprecated'); const userAgent = client.getUserAgent(); - expect(userAgent).to.be.equal('deprecated'); + expect(userAgent).toMatchInlineSnapshot(`"deprecated"`); }); }); diff --git a/test/unit/client_state.js b/test/unit/client_state.test.js similarity index 89% rename from test/unit/client_state.js rename to test/unit/client_state.test.js index 77f0b1980..8398455fe 100644 --- a/test/unit/client_state.js +++ b/test/unit/client_state.test.js @@ -1,11 +1,7 @@ -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; - import { ClientState } from '../../src/client_state'; import { StreamChat } from '../../src'; -const expect = chai.expect; -chai.use(chaiAsPromised); +import { describe, beforeEach, it, expect } from 'vitest'; describe('ClientState', () => { let state; diff --git a/test/unit/connection.js b/test/unit/connection.test.js similarity index 94% rename from test/unit/connection.js rename to test/unit/connection.test.js index 896c6c6a0..f8d5a3a77 100644 --- a/test/unit/connection.js +++ b/test/unit/connection.test.js @@ -1,8 +1,6 @@ -import chai from 'chai'; import sinon from 'sinon'; import url from 'url'; -import { Server as WsServer } from 'ws'; -import chaiAsPromised from 'chai-as-promised'; +import { Server as WsServer } from 'isomorphic-ws'; import { StableWSConnection } from '../../src/connection'; import { StreamChat } from '../../src/client'; @@ -10,8 +8,7 @@ import { TokenManager } from '../../src/token_manager'; import { sleep } from '../../src/utils'; import { InsightMetrics } from '../../src/insights'; -chai.use(chaiAsPromised); -const expect = chai.expect; +import { describe, expect, it, afterAll } from 'vitest'; describe('connection', function () { const wsBaseURL = 'http://localhost:9999'; @@ -42,7 +39,7 @@ describe('connection', function () { ), ); - after(() => wss.close()); + afterAll(() => wss.close()); describe('Connection tokenProvider', () => { it('should handle token provider rejection ', async () => { @@ -51,7 +48,9 @@ describe('connection', function () { }); client.defaultWSTimeout = 20; const tokenProvider = () => Promise.reject(new Error('network failure')); - await expect(client.connectUser({ id: 'amin' }, tokenProvider)).to.be.rejectedWith(/tokenProvider failed/); + await expect(client.connectUser({ id: 'amin' }, tokenProvider)).rejects.toThrow( + /tokenProvider failed/, + ); }); }); @@ -122,7 +121,7 @@ describe('connection', function () { it('connect should throw if already connecting', async () => { const c = new StableWSConnection({ client: newStreamChat() }); c.isConnecting = true; - await expect(c.connect()).to.be.rejectedWith(/called connect twice/); + await expect(c.connect()).rejects.toThrow(/called connect twice/); }); it('_recover should not call _connect if isConnecting is set', async () => { @@ -190,7 +189,7 @@ describe('connection', function () { }); client.defaultWSTimeout = 2000; - await expect(client.connectUser({ id: 'amin' }, token)).to.be.rejectedWith( + await expect(client.connectUser({ id: 'amin' }, token)).rejects.toThrow( /initial WS connection could not be established/, ); }); diff --git a/test/unit/connection_fallback.js b/test/unit/connection_fallback.test.js similarity index 86% rename from test/unit/connection_fallback.js rename to test/unit/connection_fallback.test.js index 107a29378..53db85ac4 100644 --- a/test/unit/connection_fallback.js +++ b/test/unit/connection_fallback.test.js @@ -1,13 +1,10 @@ -import chai from 'chai'; import sinon from 'sinon'; -import chaiAsPromised from 'chai-as-promised'; import * as utils from '../../src/utils'; import * as errors from '../../src/errors'; import { ConnectionState, WSConnectionFallback } from '../../src/connection_fallback'; -chai.use(chaiAsPromised); -const expect = chai.expect; +import { describe, it, expect, afterEach, vi, beforeAll, beforeEach } from 'vitest'; describe('connection_fallback', () => { const newClient = (overrides) => ({ @@ -21,6 +18,10 @@ describe('connection_fallback', () => { ...overrides, }); + afterEach(() => { + vi.restoreAllMocks(); + }); + afterEach(() => { sinon.restore(); }); @@ -35,10 +36,13 @@ describe('connection_fallback', () => { expect(c.consecutiveFailures).to.be.eql(0); }); - it('should register window event listeners', () => { - sinon.spy(utils, 'addConnectionEventListeners'); + it('should register window event listeners', async () => { + vi.spyOn(utils, 'addConnectionEventListeners'); + const c = new WSConnectionFallback({ client: newClient() }); - expect(utils.addConnectionEventListeners.calledOnceWithExactly(c._onlineStatusChanged)).to.be.true; + expect(utils.addConnectionEventListeners).toHaveBeenCalledExactlyOnceWith( + c._onlineStatusChanged, + ); sinon.restore(); }); }); @@ -71,7 +75,12 @@ describe('connection_fallback', () => { expect(client.dispatchEvent.called).to.be.false; c._setState(ConnectionState.Connected); - expect(client.dispatchEvent.calledOnceWithExactly({ type: 'connection.changed', online: true })).to.be.true; + expect( + client.dispatchEvent.calledOnceWithExactly({ + type: 'connection.changed', + online: true, + }), + ).to.be.true; }); it('should dispatchEvent for offline status', function () { @@ -80,8 +89,12 @@ describe('connection_fallback', () => { expect(client.dispatchEvent.called).to.be.false; c._setState(ConnectionState.Closed); - expect(client.dispatchEvent.calledOnceWithExactly({ type: 'connection.changed', online: false })).to.be - .true; + expect( + client.dispatchEvent.calledOnceWithExactly({ + type: 'connection.changed', + online: false, + }), + ).to.be.true; c._setState(ConnectionState.Connected); expect(client.dispatchEvent.calledOnce).to.be.true; @@ -89,8 +102,12 @@ describe('connection_fallback', () => { c._setState(ConnectionState.Disconnected); expect(client.dispatchEvent.calledTwice).to.be.true; - expect(client.dispatchEvent.alwaysCalledWithExactly({ type: 'connection.changed', online: false })).to.be - .true; + expect( + client.dispatchEvent.alwaysCalledWithExactly({ + type: 'connection.changed', + online: false, + }), + ).to.be.true; }); }); @@ -149,12 +166,13 @@ describe('connection_fallback', () => { describe('disconnect', () => { it('should unregister window event listeners', async () => { - sinon.spy(utils, 'removeConnectionEventListeners'); + vi.spyOn(utils, 'removeConnectionEventListeners'); const c = new WSConnectionFallback({ client: newClient() }); c._req = () => null; await c.disconnect(); - expect(utils.removeConnectionEventListeners.calledOnceWithExactly(c._onlineStatusChanged)).to.be.true; - sinon.restore(); + expect(utils.removeConnectionEventListeners).toHaveBeenCalledExactlyOnceWith( + c._onlineStatusChanged, + ); }); it('should cancel requests and set the state correctly', async () => { @@ -171,7 +189,9 @@ describe('connection_fallback', () => { expect(c.connectionID).to.be.undefined; expect(c.cancelToken).to.be.undefined; expect(cancel.calledOnce).to.be.true; - expect(c._req.calledOnceWithExactly({ close: true, connection_id }, { timeout }, false)).to.be.true; + expect( + c._req.calledOnceWithExactly({ close: true, connection_id }, { timeout }, false), + ).to.be.true; }); it('should ingore request errors', async () => { @@ -210,7 +230,15 @@ describe('connection_fallback', () => { it('should keep track of consecutive failures', async () => { // ok-err-err-ok-ok... - const doAxiosRequest = sinon.stub().onCall(0).resolves().onCall(1).rejects().onCall(2).rejects().resolves(); + const doAxiosRequest = sinon + .stub() + .onCall(0) + .resolves() + .onCall(1) + .rejects() + .onCall(2) + .rejects() + .resolves(); const c = new WSConnectionFallback({ client: newClient({ doAxiosRequest }) }); expect(c.consecutiveFailures).to.be.eql(0); @@ -233,7 +261,7 @@ describe('connection_fallback', () => { sinon.spy(c); expect(c.consecutiveFailures).to.be.eql(0); - await expect(c._req({}, {}, true)).to.be.rejected; + await expect(c._req({}, {}, true)).rejects.toThrow(); expect(c.consecutiveFailures).to.be.eql(1); expect(c._req.calledOnce).to.be.true; }); @@ -245,20 +273,26 @@ describe('connection_fallback', () => { sinon.spy(c); expect(c.consecutiveFailures).to.be.eql(0); - await expect(c._req({}, {}, false)).to.be.rejected; + await expect(c._req({}, {}, false)).rejects.toThrow(); expect(c.consecutiveFailures).to.be.eql(1); expect(c._req.calledOnce).to.be.true; }); it('should retry errors if it is retryable', async () => { const doAxiosRequest = sinon.stub().rejects(); - sinon.stub(errors, 'isErrorRetryable').onCall(0).returns(true).onCall(1).returns(true).returns(false); - sinon.stub(utils, 'sleep').resolves(); + + vi.spyOn(errors, 'isErrorRetryable') + .mockReturnValueOnce(true) + .mockReturnValueOnce(true) + .mockReturnValueOnce(false); + + vi.spyOn(utils, 'sleep').mockResolvedValue(); + const c = new WSConnectionFallback({ client: newClient({ doAxiosRequest }) }); sinon.spy(c, '_req'); expect(c.consecutiveFailures).to.be.eql(0); - await expect(c._req({}, {}, true)).to.be.rejected; + await expect(c._req({}, {}, true)).rejects.toThrow(); expect(c.consecutiveFailures).to.be.eql(3); expect(c._req.calledThrice).to.be.true; }); @@ -285,12 +319,14 @@ describe('connection_fallback', () => { expect(await c.connect()).to.be.eql(health); expect(c.client._buildWSPayload.calledOnce).to.be.true; expect(c._poll.calledOnce).to.be.true; - expect(c._req.calledOnceWithExactly({ json: 'payload' }, { timeout: 8000 }, false)).to.be.true; + expect(c._req.calledOnceWithExactly({ json: 'payload' }, { timeout: 8000 }, false)) + .to.be.true; c.state = ConnectionState.Init; c._req = sinon.stub().resolves({ event: health }); expect(await c.connect(true)).to.be.eql(health); - expect(c._req.calledOnceWithExactly({ json: 'payload' }, { timeout: 8000 }, true)).to.be.true; + expect(c._req.calledOnceWithExactly({ json: 'payload' }, { timeout: 8000 }, true)) + .to.be.true; }); it('should update state and connectionID', async () => { @@ -304,7 +340,7 @@ describe('connection_fallback', () => { c = new WSConnectionFallback({ client: newClient() }); c._req = sinon.stub().rejects(); c._poll = sinon.spy(); - await expect(c.connect()).to.be.rejected; + await expect(c.connect()).rejects.toThrow(); expect(c._poll.called).to.be.false; expect(c.state).to.be.eql(ConnectionState.Closed); expect(c.connectionID).to.be.undefined; @@ -320,7 +356,7 @@ describe('connection_fallback', () => { c = new WSConnectionFallback({ client: newClient() }); c._req = sinon.stub().rejects(); c._poll = sinon.spy(); - await expect(c.connect()).to.be.rejected; + await expect(c.connect()).rejects.toThrow(); expect(c._poll.called).to.be.false; }); @@ -334,7 +370,7 @@ describe('connection_fallback', () => { c = new WSConnectionFallback({ client: newClient() }); c._req = sinon.stub().rejects(); c._poll = sinon.spy(); - await expect(c.connect()).to.be.rejected; + await expect(c.connect()).rejects.toThrow(); expect(c.client.recoverState.called).to.be.false; c = new WSConnectionFallback({ client: newClient() }); @@ -399,29 +435,28 @@ describe('connection_fallback', () => { }); it('should stop for non-retryable errors', async () => { + vi.spyOn(errors, 'isErrorRetryable').mockReturnValue(false); + vi.spyOn(errors, 'isAPIError').mockReturnValue(true); const c = new WSConnectionFallback({ client: newClient() }); c.state = ConnectionState.Connected; c._req = sinon.stub().rejects(); - sinon.stub(errors, 'isErrorRetryable').returns(false); - sinon.stub(errors, 'isAPIError').returns(true); await c._poll(); expect(c.state).to.be.eql(ConnectionState.Closed); }); it('should continue retrying for random errors', async () => { - const c = new WSConnectionFallback({ client: newClient() }); - c.state = ConnectionState.Connected; - c._req = sinon.stub().rejects(); - let counter = 0; - sinon.stub(utils, 'sleep').callsFake(() => { + vi.spyOn(utils, 'sleep').mockImplementation(() => { if (++counter > 2) c.state = ConnectionState.Disconnected; }); + const c = new WSConnectionFallback({ client: newClient() }); + c.state = ConnectionState.Connected; + c._req = sinon.stub().rejects(); await c._poll(); expect(c._req.calledThrice).to.be.true; - expect(utils.sleep.calledThrice).to.be.true; + expect(utils.sleep).toHaveBeenCalledTimes(3); }); }); }); diff --git a/test/unit/errors.js b/test/unit/errors.test.js similarity index 92% rename from test/unit/errors.js rename to test/unit/errors.test.js index a60ab1e17..2f7e465b9 100644 --- a/test/unit/errors.js +++ b/test/unit/errors.test.js @@ -1,7 +1,6 @@ -import chai from 'chai'; import { isErrorResponse } from '../../src/errors'; -const expect = chai.expect; +import { describe, it, expect } from 'vitest'; describe('error response', () => { it('is response with no status attribute', () => { diff --git a/test/unit/poll.test.js b/test/unit/poll.test.js index b761dd3aa..bc22e6e59 100644 --- a/test/unit/poll.test.js +++ b/test/unit/poll.test.js @@ -1,7 +1,8 @@ -import { expect } from 'chai'; import sinon from 'sinon'; import { Poll, StreamChat } from '../../src'; +import { describe, it, afterEach, expect } from 'vitest'; + const pollId = 'WD4SBRJvLoGwB4oAoCQGM'; const user1 = { @@ -268,17 +269,26 @@ describe('Poll', () => { const vote_counts_by_option = { ...originalState.vote_counts_by_option, - [castedVote.option_id]: originalState.vote_counts_by_option[castedVote.option_id] + 1, + [castedVote.option_id]: + originalState.vote_counts_by_option[castedVote.option_id] + 1, }; const latest_votes_by_option = { ...originalState.latest_votes_by_option, - [castedVote.option_id]: [...originalState.latest_votes_by_option[castedVote.option_id], castedVote], + [castedVote.option_id]: [ + ...originalState.latest_votes_by_option[castedVote.option_id], + castedVote, + ], }; poll.handleVoteCasted({ type: 'poll.vote_casted', - poll: { ...pollResponse, latest_votes_by_option, vote_count, vote_counts_by_option }, + poll: { + ...pollResponse, + latest_votes_by_option, + vote_count, + vote_counts_by_option, + }, poll_vote: castedVote, }); @@ -286,7 +296,10 @@ describe('Poll', () => { expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); expect(poll.data.latest_answers).to.eql(originalState.latest_answers); expect(poll.data.latest_votes_by_option).to.eql(latest_votes_by_option); - expect(poll.data.maxVotedOptionIds).to.eql([...originalState.maxVotedOptionIds, castedVote.option_id]); + expect(poll.data.maxVotedOptionIds).to.eql([ + ...originalState.maxVotedOptionIds, + castedVote.option_id, + ]); }); it('should add own vote when handleVoteCasted is called', () => { @@ -307,7 +320,8 @@ describe('Poll', () => { const vote_counts_by_option = { ...originalState.vote_counts_by_option, - [castedVote.option_id]: originalState.vote_counts_by_option[castedVote.option_id] + 1, + [castedVote.option_id]: + originalState.vote_counts_by_option[castedVote.option_id] + 1, }; const latest_votes_by_option = { @@ -322,7 +336,12 @@ describe('Poll', () => { poll.handleVoteCasted({ type: 'poll.vote_casted', - poll: { ...pollResponse, latest_votes_by_option, vote_count, vote_counts_by_option }, + poll: { + ...pollResponse, + latest_votes_by_option, + vote_count, + vote_counts_by_option, + }, poll_vote: castedVote, }); @@ -355,7 +374,10 @@ describe('Poll', () => { expect(poll.data.ownVotesByOptionId).to.eql(originalState.ownVotesByOptionId); expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); - expect(poll.data.latest_answers).to.eql([castedVote, ...originalState.latest_answers]); + expect(poll.data.latest_answers).to.eql([ + castedVote, + ...originalState.latest_answers, + ]); expect(poll.data.latest_votes_by_option).to.eql(originalState.latest_votes_by_option); expect(poll.data.maxVotedOptionIds).to.eql(originalState.maxVotedOptionIds); }); @@ -383,7 +405,10 @@ describe('Poll', () => { expect(poll.data.ownVotesByOptionId).to.eql(originalState.ownVotesByOptionId); expect(poll.data.ownAnswer).to.eql(castedVote); - expect(poll.data.latest_answers).to.eql([castedVote, ...originalState.latest_answers]); + expect(poll.data.latest_answers).to.eql([ + castedVote, + ...originalState.latest_answers, + ]); expect(poll.data.latest_votes_by_option).to.eql(originalState.latest_votes_by_option); expect(poll.data.maxVotedOptionIds).to.eql(originalState.maxVotedOptionIds); }); @@ -403,12 +428,16 @@ describe('Poll', () => { const vote_counts_by_option = { ...originalState.vote_counts_by_option, - [changedToOptionId]: (originalState.vote_counts_by_option[changedToOptionId] ?? 0) + 1, + [changedToOptionId]: + (originalState.vote_counts_by_option[changedToOptionId] ?? 0) + 1, }; const latest_votes_by_option = { ...originalState.latest_votes_by_option, - [changedToOptionId]: [...originalState.latest_votes_by_option[changedToOptionId], castedVote], + [changedToOptionId]: [ + ...originalState.latest_votes_by_option[changedToOptionId], + castedVote, + ], }; poll.handleVoteChanged({ @@ -421,7 +450,10 @@ describe('Poll', () => { expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); expect(poll.data.latest_answers).to.eql(originalState.latest_answers); expect(poll.data.latest_votes_by_option).to.eql(latest_votes_by_option); - expect(poll.data.maxVotedOptionIds).to.eql([...originalState.maxVotedOptionIds, changedToOptionId]); + expect(poll.data.maxVotedOptionIds).to.eql([ + ...originalState.maxVotedOptionIds, + changedToOptionId, + ]); }); it('should change own vote when handleVoteChanged is called', () => { @@ -440,12 +472,16 @@ describe('Poll', () => { const vote_counts_by_option = { ...originalState.vote_counts_by_option, - [changedToOptionId]: (originalState.vote_counts_by_option[changedToOptionId] ?? 0) + 1, + [changedToOptionId]: + (originalState.vote_counts_by_option[changedToOptionId] ?? 0) + 1, }; const latest_votes_by_option = { ...originalState.latest_votes_by_option, - [changedToOptionId]: [...originalState.latest_votes_by_option[changedToOptionId], castedVote], + [changedToOptionId]: [ + ...originalState.latest_votes_by_option[changedToOptionId], + castedVote, + ], }; poll.handleVoteChanged({ @@ -461,7 +497,10 @@ describe('Poll', () => { expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); expect(poll.data.latest_answers).to.eql(originalState.latest_answers); expect(poll.data.latest_votes_by_option).to.eql(latest_votes_by_option); - expect(poll.data.maxVotedOptionIds).to.eql([...originalState.maxVotedOptionIds, changedToOptionId]); + expect(poll.data.maxVotedOptionIds).to.eql([ + ...originalState.maxVotedOptionIds, + changedToOptionId, + ]); }); it('should change an answer when handleVoteChanged is called', () => { @@ -481,7 +520,10 @@ describe('Poll', () => { expect(poll.data.ownVotesByOptionId).to.eql(originalState.ownVotesByOptionId); expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); - expect(poll.data.latest_answers).to.eql([changedAnswer, ...originalState.latest_answers]); + expect(poll.data.latest_answers).to.eql([ + changedAnswer, + ...originalState.latest_answers, + ]); expect(poll.data.latest_votes_by_option).to.eql(originalState.latest_votes_by_option); expect(poll.data.maxVotedOptionIds).to.eql(originalState.maxVotedOptionIds); }); @@ -517,14 +559,15 @@ describe('Poll', () => { const originalState = poll.data; const vote_counts_by_option = { ...originalState.vote_counts_by_option, - [user2Votes[1].option_id]: originalState.vote_counts_by_option[user2Votes[1].option_id] - 1, + [user2Votes[1].option_id]: + originalState.vote_counts_by_option[user2Votes[1].option_id] - 1, }; const latest_votes_by_option = { ...originalState.latest_votes_by_option, - [user2Votes[1].option_id]: originalState.latest_votes_by_option[user2Votes[1].option_id].filter( - (v) => v.option_id !== user2Votes[1].option_id, - ), + [user2Votes[1].option_id]: originalState.latest_votes_by_option[ + user2Votes[1].option_id + ].filter((v) => v.option_id !== user2Votes[1].option_id), }; poll.handleVoteRemoved({ @@ -578,7 +621,9 @@ describe('Poll', () => { poll_vote: { ...removedVote, user_id: client.userID }, }); - expect(poll.data.ownVotesByOptionId).to.eql({ 'dc22dcd6-4fc8-4c92-92c2-bfd63245724c': user1Votes[1] }); + expect(poll.data.ownVotesByOptionId).to.eql({ + 'dc22dcd6-4fc8-4c92-92c2-bfd63245724c': user1Votes[1], + }); expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); expect(poll.data.latest_answers).to.eql(originalState.latest_answers); expect(poll.data.latest_votes_by_option).to.eql(latest_votes_by_option); @@ -603,7 +648,9 @@ describe('Poll', () => { expect(poll.data.ownVotesByOptionId).to.eql(originalState.ownVotesByOptionId); expect(poll.data.ownAnswer).to.eql(originalState.ownAnswer); - expect(poll.data.latest_answers).to.eql(originalState.latest_answers.filter((a) => a.id !== removedAnswer.id)); + expect(poll.data.latest_answers).to.eql( + originalState.latest_answers.filter((a) => a.id !== removedAnswer.id), + ); expect(poll.data.latest_votes_by_option).to.eql(originalState.latest_votes_by_option); expect(poll.data.maxVotedOptionIds).to.eql(originalState.maxVotedOptionIds); }); @@ -622,7 +669,9 @@ describe('Poll', () => { expect(poll.data.ownVotesByOptionId).to.eql(originalState.ownVotesByOptionId); expect(poll.data.ownAnswer).to.be.undefined; - expect(poll.data.latest_answers).to.eql(originalState.latest_answers.filter((a) => a.id !== removedAnswer.id)); + expect(poll.data.latest_answers).to.eql( + originalState.latest_answers.filter((a) => a.id !== removedAnswer.id), + ); expect(poll.data.latest_votes_by_option).to.eql(originalState.latest_votes_by_option); expect(poll.data.maxVotedOptionIds).to.eql(originalState.maxVotedOptionIds); }); @@ -644,13 +693,19 @@ describe('Poll', () => { expect(getPollStub.calledWith(pollResponse.id)).to.be.true; const { lastActivityAt: __, ...currentPollState } = poll.data; - const { lastActivityAt: _, ...expectedPollState } = { ...originalState, ...mockPollResponse }; + const { lastActivityAt: _, ...expectedPollState } = { + ...originalState, + ...mockPollResponse, + }; expect(currentPollState).to.eql(expectedPollState); getPollStub.restore(); }); it('should remove oldest vote before casting a new one if reached max votes allowed', async () => { - const poll = new Poll({ client, poll: { ...pollResponse, max_votes_allowed: user2Votes.length } }); + const poll = new Poll({ + client, + poll: { ...pollResponse, max_votes_allowed: user2Votes.length }, + }); const option_id = 'ba933470-c0da-4b6f-a4d2-d2176ac0d4a8'; const messageId = 'XXX'; const removePollVoteStub = sinon.stub(client, 'removePollVote'); @@ -660,14 +715,19 @@ describe('Poll', () => { await poll.castVote(option_id, messageId); - expect(removePollVoteStub.calledWith(messageId, pollResponse.id, user1Votes[1].id)).to.be.true; - expect(castPollVoteStub.calledWith(messageId, pollResponse.id, { option_id })).to.be.true; + expect(removePollVoteStub.calledWith(messageId, pollResponse.id, user1Votes[1].id)).to + .be.true; + expect(castPollVoteStub.calledWith(messageId, pollResponse.id, { option_id })).to.be + .true; removePollVoteStub.restore(); castPollVoteStub.restore(); }); it('should not remove oldest vote before casting a new one if not reached max votes allowed', async () => { - const poll = new Poll({ client, poll: { ...pollResponse, max_votes_allowed: user2Votes.length + 1 } }); + const poll = new Poll({ + client, + poll: { ...pollResponse, max_votes_allowed: user2Votes.length + 1 }, + }); const option_id = 'ba933470-c0da-4b6f-a4d2-d2176ac0d4a8'; const messageId = 'XXX'; const removePollVoteStub = sinon.stub(client, 'removePollVote'); @@ -678,13 +738,17 @@ describe('Poll', () => { await poll.castVote(option_id, messageId); expect(removePollVoteStub.called).to.be.false; - expect(castPollVoteStub.calledWith(messageId, pollResponse.id, { option_id })).to.be.true; + expect(castPollVoteStub.calledWith(messageId, pollResponse.id, { option_id })).to.be + .true; removePollVoteStub.restore(); castPollVoteStub.restore(); }); it('should not remove oldest vote before casting a new one if max_votes_allowed is not defined', async () => { - const poll = new Poll({ client, poll: { ...pollResponse, max_votes_allowed: undefined } }); + const poll = new Poll({ + client, + poll: { ...pollResponse, max_votes_allowed: undefined }, + }); const option_id = 'ba933470-c0da-4b6f-a4d2-d2176ac0d4a8'; const messageId = 'XXX'; const removePollVoteStub = sinon.stub(client, 'removePollVote'); @@ -695,7 +759,8 @@ describe('Poll', () => { await poll.castVote(option_id, messageId); expect(removePollVoteStub.called).to.be.false; - expect(castPollVoteStub.calledWith(messageId, pollResponse.id, { option_id })).to.be.true; + expect(castPollVoteStub.calledWith(messageId, pollResponse.id, { option_id })).to.be + .true; removePollVoteStub.restore(); castPollVoteStub.restore(); }); diff --git a/test/unit/poll_manager.test.ts b/test/unit/poll_manager.test.ts index 767b37e33..99d484d96 100644 --- a/test/unit/poll_manager.test.ts +++ b/test/unit/poll_manager.test.ts @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { v4 as uuidv4 } from 'uuid'; import { generateChannel } from './test-utils/generateChannel'; @@ -16,6 +15,8 @@ import { StreamChat, } from '../../src'; +import { describe, beforeEach, afterEach, it, expect } from 'vitest'; + const TEST_USER_ID = 'observer'; let client: StreamChat; @@ -196,13 +197,18 @@ describe('PollManager', () => { let pollMessages: MessageResponse[] = []; for (let ci = 0; ci < 5; ci++) { - const { messages, pollMessages: onlyPollMessages } = generateRandomMessagesWithPolls(5, `_${ci}`); + const { messages, pollMessages: onlyPollMessages } = + generateRandomMessagesWithPolls(5, `_${ci}`); pollMessages = pollMessages.concat(onlyPollMessages); - mockedChannelsQueryResponse.push(generateChannel({ channel: { id: uuidv4() }, messages })); + mockedChannelsQueryResponse.push( + generateChannel({ channel: { id: uuidv4() }, messages }), + ); } const mock = sinon.mock(client); const spy = sinon.spy(client.polls, 'hydratePollCache'); - mock.expects('post').returns(Promise.resolve({ channels: mockedChannelsQueryResponse })); + mock + .expects('post') + .returns(Promise.resolve({ channels: mockedChannelsQueryResponse })); await client.queryChannels({}); expect(client.polls.data.size).to.equal(pollMessages.length); expect(spy.callCount).to.be.equal(5); @@ -216,12 +222,13 @@ describe('PollManager', () => { let pollMessages: MessageResponse[] = []; const spy = sinon.spy(client.polls, 'hydratePollCache'); for (let ci = 0; ci < 5; ci++) { - const { messages: prevMessages, pollMessages: prevPollMessages } = generateRandomMessagesWithPolls( - 5, - `_prev_${ci}`, - ); + const { messages: prevMessages, pollMessages: prevPollMessages } = + generateRandomMessagesWithPolls(5, `_prev_${ci}`); pollMessages = pollMessages.concat(prevPollMessages); - const channelResponse = generateChannel({ channel: { id: uuidv4() }, messages: prevMessages }); + const channelResponse = generateChannel({ + channel: { id: uuidv4() }, + messages: prevMessages, + }); channels.push(channelResponse); client.channel(channelResponse.channel.type, channelResponse.channel.id); client.polls.hydratePollCache(prevMessages, true); @@ -229,20 +236,28 @@ describe('PollManager', () => { const mockedChannelsQueryResponse = []; for (let ci = 0; ci < 5; ci++) { - const { messages, pollMessages: onlyPollMessages } = generateRandomMessagesWithPolls(5, `_${ci}`); + const { messages, pollMessages: onlyPollMessages } = + generateRandomMessagesWithPolls(5, `_${ci}`); pollMessages = pollMessages.concat(onlyPollMessages); const channelResponse = { ...channels[ci], messages }; mockedChannelsQueryResponse.push(channelResponse); } const mock = sinon.mock(client); - mock.expects('post').returns(Promise.resolve({ channels: mockedChannelsQueryResponse })); + mock + .expects('post') + .returns(Promise.resolve({ channels: mockedChannelsQueryResponse })); await client.queryChannels({}); expect(client.polls.data.size).to.equal(pollMessages.length); expect(spy.callCount).to.be.equal(10); for (let i = 0; i < 5; i++) { expect(spy.calledWith(mockedChannelsQueryResponse[i].messages, true)).to.be.true; expect(spy.calledWith(channels[i].messages, true)).to.be.true; - expect(spy.calledWith([...channels[i].messages, ...mockedChannelsQueryResponse[i].messages], true)).to.be.false; + expect( + spy.calledWith( + [...channels[i].messages, ...mockedChannelsQueryResponse[i].messages], + true, + ), + ).to.be.false; } }); @@ -264,7 +279,8 @@ describe('PollManager', () => { it('populates pollCache with only new messages on channel.query invocation', async () => { const channel = client.channel('messaging', mockChannelQueryResponse.channel.id); - const { messages: prevMessages, pollMessages: prevPollMessages } = generateRandomMessagesWithPolls(5, `_prev`); + const { messages: prevMessages, pollMessages: prevPollMessages } = + generateRandomMessagesWithPolls(5, `_prev`); channel.state.addMessagesSorted(prevMessages); const { messages, pollMessages } = generateRandomMessagesWithPolls(5, ``); const mockedChannelQueryResponse = { @@ -276,7 +292,9 @@ describe('PollManager', () => { mock.expects('post').returns(Promise.resolve(mockedChannelQueryResponse)); client.polls.hydratePollCache(prevMessages); await channel.query(); - expect(client.polls.data.size).to.equal(prevPollMessages.length + pollMessages.length); + expect(client.polls.data.size).to.equal( + prevPollMessages.length + pollMessages.length, + ); expect(spy.calledTwice).to.be.true; expect(spy.args[0][0]).to.deep.equal(prevMessages); expect(spy.args[1][0]).to.deep.equal(mockedChannelQueryResponse.messages); @@ -288,7 +306,8 @@ describe('PollManager', () => { let pollMessages: MessageResponse[] = []; for (let ci = 0; ci < 2; ci++) { - const { messages, pollMessages: onlyPollMessages } = generateRandomMessagesWithPolls(5, `_${ci}`); + const { messages, pollMessages: onlyPollMessages } = + generateRandomMessagesWithPolls(5, `_${ci}`); pollMessages = pollMessages.concat(onlyPollMessages); mockedChannelsQueryResponse.push({ ...mockChannelQueryResponse, @@ -300,7 +319,9 @@ describe('PollManager', () => { expect(client.polls.data.size).to.equal(pollMessages.length); // Map.prototype.keys() preserves the insertion order so we can do this - expect(Array.from(client.polls.data.keys())).to.deep.equal(pollMessages.map((m) => m.poll_id)); + expect(Array.from(client.polls.data.keys())).to.deep.equal( + pollMessages.map((m) => m.poll_id), + ); }); it('prevents pollCache population if caching is disabled', async () => { @@ -309,7 +330,8 @@ describe('PollManager', () => { let pollMessages: MessageResponse[] = []; for (let ci = 0; ci < 2; ci++) { - const { messages, pollMessages: onlyPollMessages } = generateRandomMessagesWithPolls(5, `_${ci}`); + const { messages, pollMessages: onlyPollMessages } = + generateRandomMessagesWithPolls(5, `_${ci}`); pollMessages = pollMessages.concat(onlyPollMessages); mockedChannelsQueryResponse.push({ ...mockChannelQueryResponse, @@ -329,7 +351,11 @@ describe('PollManager', () => { user: { id: 'bob' }, }); - const pollMessage = generatePollMessage('poll_from_event', {}, { user: { id: 'bob' } }); + const pollMessage = generatePollMessage( + 'poll_from_event', + {}, + { user: { id: 'bob' } }, + ); client.dispatchEvent({ type: 'message.new', @@ -357,7 +383,9 @@ describe('PollManager', () => { pollManager.hydratePollCache(messages); expect(pollManager.data.size).to.equal(pollMessages.length); - expect(Array.from(pollManager.data.keys())).to.deep.equal(pollMessages.map((m) => m.poll_id)); + expect(Array.from(pollManager.data.keys())).to.deep.equal( + pollMessages.map((m) => m.poll_id), + ); }); it('correctly upserts duplicate polls within the cache', () => { @@ -374,12 +402,16 @@ describe('PollManager', () => { expect(Array.from(pollManager.data.keys())).to.deep.equal( [...pollMessages, duplicatePollMessage].map((m) => m.poll_id), ); - expect(pollManager.fromState(duplicateId)?.data.name).to.equal(duplicatePollMessage.poll.name); + expect(pollManager.fromState(duplicateId)?.data.name).to.equal( + duplicatePollMessage.poll.name, + ); // many duplicate messages const duplicates = []; for (let di = 0; di < 5; di++) { - const newDuplicateMessage = generatePollMessage(duplicateId, { name: `d1_${di}` }); + const newDuplicateMessage = generatePollMessage(duplicateId, { + name: `d1_${di}`, + }); duplicates.push(newDuplicateMessage); } @@ -403,7 +435,9 @@ describe('PollManager', () => { // many hydrate invocations for (let di = 0; di < 5; di++) { - const newDuplicateMessage = generatePollMessage(duplicateId, { name: `d2_${di}` }); + const newDuplicateMessage = generatePollMessage(duplicateId, { + name: `d2_${di}`, + }); pollManager.hydratePollCache([newDuplicateMessage], true); } @@ -429,7 +463,10 @@ describe('PollManager', () => { it('should not register subscription handlers twice', () => { pollManager.registerSubscriptions(); - const pollClosedStub = sinon.stub(pollManager.fromState(pollId1) as Poll, 'handlePollClosed'); + const pollClosedStub = sinon.stub( + pollManager.fromState(pollId1) as Poll, + 'handlePollClosed', + ); client.dispatchEvent({ type: 'poll.closed', @@ -442,8 +479,14 @@ describe('PollManager', () => { it('should not call subscription handlers if unregisterSubscriptions has been called', () => { pollManager.unregisterSubscriptions(); - const voteCastedStub = sinon.stub(pollManager.fromState(pollId1) as Poll, 'handleVoteCasted'); - const pollClosedStub = sinon.stub(pollManager.fromState(pollId1) as Poll, 'handlePollClosed'); + const voteCastedStub = sinon.stub( + pollManager.fromState(pollId1) as Poll, + 'handleVoteCasted', + ); + const pollClosedStub = sinon.stub( + pollManager.fromState(pollId1) as Poll, + 'handlePollClosed', + ); const poll = pollMessage1.poll as PollResponse; @@ -488,8 +531,14 @@ describe('PollManager', () => { eventHandlerPairs.map(([eventType, handlerName]) => { it(`should invoke poll.${handlerName} within the cache on ${eventType}`, () => { - const stub1 = sinon.stub(pollManager.fromState(pollId1) as Poll, handlerName as keyof Poll); - const stub2 = sinon.stub(pollManager.fromState(pollId2) as Poll, handlerName as keyof Poll); + const stub1 = sinon.stub( + pollManager.fromState(pollId1) as Poll, + handlerName as keyof Poll, + ); + const stub2 = sinon.stub( + pollManager.fromState(pollId2) as Poll, + handlerName as keyof Poll, + ); const updatedPoll = pollMessage1.poll as PollResponse; @@ -508,14 +557,21 @@ describe('PollManager', () => { describe('API', () => { const pollId1 = 'poll_1'; const pollId2 = 'poll_2'; - let stubbedQueryPolls: sinon.SinonStub, ReturnType>; - let stubbedGetPoll: sinon.SinonStub, ReturnType>; + let stubbedQueryPolls: sinon.SinonStub< + Parameters, + ReturnType + >; + let stubbedGetPoll: sinon.SinonStub< + Parameters, + ReturnType + >; const pollMessage1: PollResponse = generatePollMessage(pollId1); const pollMessage2: PollResponse = generatePollMessage(pollId2); beforeEach(() => { - stubbedQueryPolls = sinon - .stub(client, 'queryPolls') - .resolves({ polls: [pollMessage1.poll as PollResponse, pollMessage2.poll as PollResponse], duration: '10' }); + stubbedQueryPolls = sinon.stub(client, 'queryPolls').resolves({ + polls: [pollMessage1.poll as PollResponse, pollMessage2.poll as PollResponse], + duration: '10', + }); stubbedGetPoll = sinon .stub(client, 'getPoll') .resolves({ poll: pollMessage1.poll as PollResponse, duration: '10' }); @@ -543,7 +599,9 @@ describe('PollManager', () => { }); }); it('should overwrite the state if polls from queryPolls are already present in the cache', async () => { - const duplicatePollMessage = generatePollMessage(pollId1, { title: 'SHOULD CHANGE' }); + const duplicatePollMessage = generatePollMessage(pollId1, { + title: 'SHOULD CHANGE', + }); pollManager.hydratePollCache([duplicatePollMessage]); const previousPollFromCache = pollManager.fromState(pollId1); @@ -575,7 +633,9 @@ describe('PollManager', () => { expect(pollManager.fromState(pollId1)).to.equal(poll); }); it('should overwrite the state if the poll returned from getPoll is present in the cache', async () => { - const duplicatePollMessage = generatePollMessage(pollId1, { title: 'SHOULD CHANGE' }); + const duplicatePollMessage = generatePollMessage(pollId1, { + title: 'SHOULD CHANGE', + }); pollManager.hydratePollCache([duplicatePollMessage]); const previousPollFromCache = pollManager.fromState(pollId1); diff --git a/test/unit/search_controller.test.js b/test/unit/search_controller.test.js index 7a7d79be0..b5da8d5cd 100644 --- a/test/unit/search_controller.test.js +++ b/test/unit/search_controller.test.js @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import sinon from 'sinon'; import { BaseSearchSource, @@ -10,6 +9,8 @@ import { import { generateUser } from './test-utils/generateUser'; import { generateChannel } from './test-utils/generateChannel'; +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; + describe('SearchController', () => { let searchController; let mockSource; @@ -328,10 +329,12 @@ describe('BaseSearchSource and implementations', () => { beforeEach(() => { // Stub executeQuery on the prototype before creating the instance to avoid effect of binding in constructor - executeQueryStub = sinon.stub(BaseSearchSource.prototype, 'executeQuery').resolves({ - items, - next: null, - }); + executeQueryStub = sinon + .stub(BaseSearchSource.prototype, 'executeQuery') + .resolves({ + items, + next: null, + }); searchSource = new TestSearchSource(); }); diff --git a/test/unit/signing.js b/test/unit/signing.test.js similarity index 77% rename from test/unit/signing.js rename to test/unit/signing.test.js index 167636e77..17300579a 100644 --- a/test/unit/signing.js +++ b/test/unit/signing.test.js @@ -1,11 +1,14 @@ -import { expect } from 'chai'; import { CheckSignature } from '../../src'; +import { describe, it, expect } from 'vitest'; + const MOCK_SECRET = 'porewqKAFDSAKZssecretsercretfads'; const MOCK_TEXT = 'text'; const MOCK_JSON_BODY = { a: 1 }; -const MOCK_TEXT_SHA256 = 'd0b770e93a56adc3ee9ac5734533cc0acd71eea8e5e8204a28042ca0f60de1f3'; -const MOCK_JSON_SHA256 = 'e527a6ad4993a4c9a30680c8be4b3eda1c36ab104f1f7d39c744bd27016a9624'; +const MOCK_TEXT_SHA256 = + 'd0b770e93a56adc3ee9ac5734533cc0acd71eea8e5e8204a28042ca0f60de1f3'; +const MOCK_JSON_SHA256 = + 'e527a6ad4993a4c9a30680c8be4b3eda1c36ab104f1f7d39c744bd27016a9624'; describe('Signing', () => { describe('CheckSignature', () => { diff --git a/test/unit/test-utils/generateChannel.js b/test/unit/test-utils/generateChannel.js index d056b139d..531b43878 100644 --- a/test/unit/test-utils/generateChannel.js +++ b/test/unit/test-utils/generateChannel.js @@ -7,8 +7,8 @@ export const generateChannel = (options = { channel: {} }) => { const id = idFromOptions ? idFromOptions : options.members && options.members.length - ? `!members-${uuidv4()}` - : uuidv4(); + ? `!members-${uuidv4()}` + : uuidv4(); return { messages: [], members: [], diff --git a/test/unit/test-utils/generateThreadResponse.js b/test/unit/test-utils/generateThreadResponse.js index c21f07614..2866f6542 100644 --- a/test/unit/test-utils/generateThreadResponse.js +++ b/test/unit/test-utils/generateThreadResponse.js @@ -1,6 +1,3 @@ -import { v4 as uuidv4 } from 'uuid'; -import { generateUser } from './generateUser'; - export const generateThreadResponse = (channel, parent, opts = {}) => { return { parent_message_id: parent.id, diff --git a/test/unit/test-utils/getClient.js b/test/unit/test-utils/getClient.js index 623fc255b..a20c4bb1f 100644 --- a/test/unit/test-utils/getClient.js +++ b/test/unit/test-utils/getClient.js @@ -1,20 +1,21 @@ -import { ChannelState, StreamChat, Channel } from '../../../src'; +import { StreamChat } from '../../../src'; import { v4 as uuidv4 } from 'uuid'; -export const getClientWithUser = async (user) => { +export const getClientWithUser = (user) => { const chatClient = new StreamChat(''); const clientUser = user || { id: uuidv4() }; + chatClient.connectUser = () => { chatClient.user = clientUser; chatClient.userID = clientUser.id; chatClient.wsPromise = Promise.resolve(); // sending a promise, since connectUser in actual SDK is an async function. - return Promise.resolve(chatClient); + return chatClient; }; - await chatClient.connectUser(); + chatClient.connectUser(); return chatClient; }; diff --git a/test/unit/threads.test.ts b/test/unit/threads.test.ts index 1becb8555..553424f46 100644 --- a/test/unit/threads.test.ts +++ b/test/unit/threads.test.ts @@ -1,4 +1,3 @@ -import { expect } from 'chai'; import { v4 as uuidv4 } from 'uuid'; import { generateChannel } from './test-utils/generateChannel'; @@ -19,6 +18,8 @@ import { } from '../../src'; import { THREAD_RESPONSE_RESERVED_KEYS } from '../../src/thread'; +import { describe, it, beforeEach, expect, afterEach } from 'vitest'; + const TEST_USER_ID = 'observer'; describe('Threads 2.0', () => { @@ -59,7 +60,10 @@ describe('Threads 2.0', () => { describe('Thread', () => { it('initializes properly', () => { - const threadResponse = generateThreadResponse(channelResponse, parentMessageResponse); + const threadResponse = generateThreadResponse( + channelResponse, + parentMessageResponse, + ); // mimic pre-cached channel with existing members channel._hydrateMembers({ members: [{ user: { id: TEST_USER_ID } }] }); const thread = new Thread({ client, threadData: threadResponse }); @@ -96,7 +100,10 @@ describe('Threads 2.0', () => { }); it('updates existing message', () => { - const message = generateMsg({ parent_id: parentMessageResponse.id, text: 'aaa' }) as MessageResponse; + const message = generateMsg({ + parent_id: parentMessageResponse.id, + text: 'aaa', + }) as MessageResponse; const thread = createTestThread({ latest_replies: [message] }); const udpatedMessage = { ...message, text: 'bbb' }; @@ -125,7 +132,9 @@ describe('Threads 2.0', () => { created_at: '2020-01-01T00:00:10Z', }) as MessageResponse; - const thread = createTestThread({ latest_replies: [optimisticMessage, message] }); + const thread = createTestThread({ + latest_replies: [optimisticMessage, message], + }); const updatedMessage: MessageResponse = { ...optimisticMessage, text: 'ccc', @@ -185,7 +194,10 @@ describe('Threads 2.0', () => { const thread = createTestThread(); const message = generateMsg({ parent_id: thread.id }) as MessageResponse; const upsertReplyLocallyStub = sinon.stub(thread, 'upsertReplyLocally'); - const updateParentMessageLocallyStub = sinon.stub(thread, 'updateParentMessageLocally'); + const updateParentMessageLocallyStub = sinon.stub( + thread, + 'updateParentMessageLocally', + ); thread.updateParentMessageOrReplyLocally(message); @@ -197,7 +209,10 @@ describe('Threads 2.0', () => { const thread = createTestThread(); const message = generateMsg({ id: thread.id }) as MessageResponse; const upsertReplyLocallyStub = sinon.stub(thread, 'upsertReplyLocally'); - const updateParentMessageLocallyStub = sinon.stub(thread, 'updateParentMessageLocally'); + const updateParentMessageLocallyStub = sinon.stub( + thread, + 'updateParentMessageLocally', + ); thread.updateParentMessageOrReplyLocally(message); @@ -209,7 +224,10 @@ describe('Threads 2.0', () => { const thread = createTestThread(); const message = generateMsg() as MessageResponse; const upsertReplyLocallyStub = sinon.stub(thread, 'upsertReplyLocally'); - const updateParentMessageLocallyStub = sinon.stub(thread, 'updateParentMessageLocally'); + const updateParentMessageLocallyStub = sinon.stub( + thread, + 'updateParentMessageLocally', + ); thread.updateParentMessageOrReplyLocally(message); @@ -221,7 +239,9 @@ describe('Threads 2.0', () => { describe('hydrateState', () => { it('prevents hydrating state from the instance with a different id', () => { const thread = createTestThread(); - const otherThread = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); + const otherThread = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); expect(thread.id).to.not.equal(otherThread.id); expect(() => thread.hydrateState(otherThread)).to.throw(); @@ -245,7 +265,9 @@ describe('Threads 2.0', () => { it('retains failed replies after hydration', () => { const thread = createTestThread(); const hydrationThread = createTestThread({ - latest_replies: [generateMsg({ parent_id: parentMessageResponse.id }) as MessageResponse], + latest_replies: [ + generateMsg({ parent_id: parentMessageResponse.id }) as MessageResponse, + ], }); const failedMessage = generateMsg({ @@ -268,7 +290,10 @@ describe('Threads 2.0', () => { // five messages "created" second apart const messages = Array.from( { length: 5 }, - (_, i) => generateMsg({ created_at: new Date(createdAt + 1000 * i).toISOString() }) as MessageResponse, + (_, i) => + generateMsg({ + created_at: new Date(createdAt + 1000 * i).toISOString(), + }) as MessageResponse, ); const thread = createTestThread({ latest_replies: messages }); @@ -285,12 +310,16 @@ describe('Threads 2.0', () => { const stateAfter = thread.state.getLatestValue(); expect(stateAfter.replies).to.not.equal(stateBefore.replies); expect(stateAfter.replies).to.have.lengthOf(4); - expect(stateAfter.replies.find((reply) => reply.id === messageToDelete.id)).to.be.undefined; + expect(stateAfter.replies.find((reply) => reply.id === messageToDelete.id)).to + .be.undefined; }); }); describe('markAsRead', () => { - let stubbedChannelMarkRead: sinon.SinonStub, ReturnType>; + let stubbedChannelMarkRead: sinon.SinonStub< + Parameters, + ReturnType + >; beforeEach(() => { stubbedChannelMarkRead = sinon.stub(channel, 'markRead').resolves(); @@ -320,13 +349,17 @@ describe('Threads 2.0', () => { await thread.markAsRead(); - expect(stubbedChannelMarkRead.calledOnceWith({ thread_id: thread.id })).to.be.true; + expect(stubbedChannelMarkRead.calledOnceWith({ thread_id: thread.id })).to.be + .true; }); }); describe('loadPage', () => { it('sets up pagination on initialization (all replies included in response)', () => { - const thread = createTestThread({ latest_replies: [generateMsg() as MessageResponse], reply_count: 1 }); + const thread = createTestThread({ + latest_replies: [generateMsg() as MessageResponse], + reply_count: 1, + }); const state = thread.state.getLatestValue(); expect(state.pagination.prevCursor).to.be.null; expect(state.pagination.nextCursor).to.be.null; @@ -335,7 +368,10 @@ describe('Threads 2.0', () => { it('sets up pagination on initialization (not all replies included in response)', () => { const firstMessage = generateMsg() as MessageResponse; const lastMessage = generateMsg() as MessageResponse; - const thread = createTestThread({ latest_replies: [firstMessage, lastMessage], reply_count: 3 }); + const thread = createTestThread({ + latest_replies: [firstMessage, lastMessage], + reply_count: 3, + }); const state = thread.state.getLatestValue(); expect(state.pagination.prevCursor).not.to.be.null; expect(state.pagination.nextCursor).to.be.null; @@ -391,7 +427,10 @@ describe('Threads 2.0', () => { it('forms correct request when loading next page', async () => { const firstMessage = generateMsg() as MessageResponse; const lastMessage = generateMsg() as MessageResponse; - const thread = createTestThread({ latest_replies: [firstMessage, lastMessage], reply_count: 3 }); + const thread = createTestThread({ + latest_replies: [firstMessage, lastMessage], + reply_count: 3, + }); thread.state.next((current) => ({ ...current, pagination: { @@ -399,7 +438,9 @@ describe('Threads 2.0', () => { nextCursor: lastMessage.id, }, })); - const queryRepliesStub = sinon.stub(thread, 'queryReplies').resolves({ messages: [], duration: '' }); + const queryRepliesStub = sinon + .stub(thread, 'queryReplies') + .resolves({ messages: [], duration: '' }); await thread.loadNextPage({ limit: 42 }); @@ -447,8 +488,13 @@ describe('Threads 2.0', () => { it('forms correct request when loading previous page', async () => { const firstMessage = generateMsg() as MessageResponse; const lastMessage = generateMsg() as MessageResponse; - const thread = createTestThread({ latest_replies: [firstMessage, lastMessage], reply_count: 3 }); - const queryRepliesStub = sinon.stub(thread, 'queryReplies').resolves({ messages: [], duration: '' }); + const thread = createTestThread({ + latest_replies: [firstMessage, lastMessage], + reply_count: 3, + }); + const queryRepliesStub = sinon + .stub(thread, 'queryReplies') + .resolves({ messages: [], duration: '' }); await thread.loadPrevPage({ limit: 42 }); @@ -463,7 +509,10 @@ describe('Threads 2.0', () => { it('appends messages when loading next page', async () => { const initialMessages = [generateMsg(), generateMsg()] as MessageResponse[]; const nextMessages = [generateMsg(), generateMsg()] as MessageResponse[]; - const thread = createTestThread({ latest_replies: initialMessages, reply_count: 4 }); + const thread = createTestThread({ + latest_replies: initialMessages, + reply_count: 4, + }); thread.state.next((current) => ({ ...current, pagination: { @@ -471,12 +520,16 @@ describe('Threads 2.0', () => { nextCursor: initialMessages[1].id, }, })); - sinon.stub(thread, 'queryReplies').resolves({ messages: nextMessages, duration: '' }); + sinon + .stub(thread, 'queryReplies') + .resolves({ messages: nextMessages, duration: '' }); await thread.loadNextPage({ limit: 2 }); const stateAfter = thread.state.getLatestValue(); - const expectedMessageOrder = [...initialMessages, ...nextMessages].map(({ id }) => id).join(', '); + const expectedMessageOrder = [...initialMessages, ...nextMessages] + .map(({ id }) => id) + .join(', '); const actualMessageOrder = stateAfter.replies.map(({ id }) => id).join(', '); expect(actualMessageOrder).to.equal(expectedMessageOrder); }); @@ -484,13 +537,20 @@ describe('Threads 2.0', () => { it('prepends messages when loading previous page', async () => { const initialMessages = [generateMsg(), generateMsg()] as MessageResponse[]; const prevMessages = [generateMsg(), generateMsg()] as MessageResponse[]; - const thread = createTestThread({ latest_replies: initialMessages, reply_count: 4 }); - sinon.stub(thread, 'queryReplies').resolves({ messages: prevMessages, duration: '' }); + const thread = createTestThread({ + latest_replies: initialMessages, + reply_count: 4, + }); + sinon + .stub(thread, 'queryReplies') + .resolves({ messages: prevMessages, duration: '' }); await thread.loadPrevPage({ limit: 2 }); const stateAfter = thread.state.getLatestValue(); - const expectedMessageOrder = [...prevMessages, ...initialMessages].map(({ id }) => id).join(', '); + const expectedMessageOrder = [...prevMessages, ...initialMessages] + .map(({ id }) => id) + .join(', '); const actualMessageOrder = stateAfter.replies.map(({ id }) => id).join(', '); expect(actualMessageOrder).to.equal(expectedMessageOrder); }); @@ -527,7 +587,10 @@ describe('Threads 2.0', () => { client.dispatchEvent({ type: 'message.new', - message: generateMsg({ parent_id: thread.id, user: { id: 'bob' } }) as MessageResponse, + message: generateMsg({ + parent_id: thread.id, + user: { id: 'bob' }, + }) as MessageResponse, user: { id: 'bob' }, }); clock.runAll(); @@ -545,7 +608,9 @@ describe('Threads 2.0', () => { const stateBefore = thread.state.getLatestValue(); const stubbedGetThread = sinon .stub(client, 'getThread') - .resolves(createTestThread({ latest_replies: [generateMsg() as MessageResponse] })); + .resolves( + createTestThread({ latest_replies: [generateMsg() as MessageResponse] }), + ); thread.state.partialNext({ isStateStale: true }); @@ -572,7 +637,9 @@ describe('Threads 2.0', () => { client.dispatchEvent({ type: 'thread.updated', - thread: generateThreadResponse(channelResponse, generateMsg(), { title: 'B' }), + thread: generateThreadResponse(channelResponse, generateMsg(), { + title: 'B', + }), }); const stateAfter = thread.state.getLatestValue(); @@ -588,9 +655,13 @@ describe('Threads 2.0', () => { client.dispatchEvent({ type: 'thread.updated', - thread: generateThreadResponse(channelResponse, generateMsg({ id: parentMessageResponse.id }), { - title: 'B', - }), + thread: generateThreadResponse( + channelResponse, + generateMsg({ id: parentMessageResponse.id }), + { + title: 'B', + }, + ), }); const stateAfter = thread.state.getLatestValue(); @@ -606,20 +677,28 @@ describe('Threads 2.0', () => { const stateBefore = thread.state.getLatestValue(); - expect(stateBefore.custom).to.not.have.keys(Object.keys(THREAD_RESPONSE_RESERVED_KEYS)); + expect(stateBefore.custom).to.not.have.keys( + Object.keys(THREAD_RESPONSE_RESERVED_KEYS), + ); expect(stateBefore.custom).to.have.keys([customKey1, customKey2]); expect(stateBefore.custom[customKey1]).to.equal(1); client.dispatchEvent({ type: 'thread.updated', - thread: generateThreadResponse(channelResponse, generateMsg({ id: parentMessageResponse.id }), { - [customKey1]: 2, - }), + thread: generateThreadResponse( + channelResponse, + generateMsg({ id: parentMessageResponse.id }), + { + [customKey1]: 2, + }, + ), }); const stateAfter = thread.state.getLatestValue(); - expect(stateAfter.custom).to.not.have.keys(Object.keys(THREAD_RESPONSE_RESERVED_KEYS)); + expect(stateAfter.custom).to.not.have.keys( + Object.keys(THREAD_RESPONSE_RESERVED_KEYS), + ); expect(stateAfter.custom).to.not.have.property(customKey2); expect(stateAfter.custom[customKey1]).to.equal(2); }); @@ -684,7 +763,10 @@ describe('Threads 2.0', () => { client.dispatchEvent({ type: 'message.read', user: { id: 'bob' }, - thread: generateThreadResponse(channelResponse, generateMsg()) as ThreadResponse, + thread: generateThreadResponse( + channelResponse, + generateMsg(), + ) as ThreadResponse, }); const stateAfter = thread.state.getLatestValue(); @@ -721,7 +803,9 @@ describe('Threads 2.0', () => { const stateAfter = thread.state.getLatestValue(); expect(stateAfter.read['bob']?.unreadMessageCount).to.equal(0); - expect(stateAfter.read['bob']?.lastReadAt.toISOString()).to.equal(createdAt.toISOString()); + expect(stateAfter.read['bob']?.lastReadAt.toISOString()).to.equal( + createdAt.toISOString(), + ); thread.unregisterSubscriptions(); }); @@ -775,7 +859,10 @@ describe('Threads 2.0', () => { }); thread.registerSubscriptions(); - const newMessage = generateMsg({ parent_id: thread.id, user: { id: 'bob' } }) as MessageResponse; + const newMessage = generateMsg({ + parent_id: thread.id, + user: { id: 'bob' }, + }) as MessageResponse; client.dispatchEvent({ type: 'message.new', message: newMessage, @@ -784,7 +871,8 @@ describe('Threads 2.0', () => { const stateAfter = thread.state.getLatestValue(); expect(stateAfter.replies).to.have.length(1); - expect(stateAfter.replies.find((reply) => reply.id === newMessage.id)).not.to.be.undefined; + expect(stateAfter.replies.find((reply) => reply.id === newMessage.id)).not.to.be + .undefined; expect(thread.ownUnreadCount).to.equal(1); thread.unregisterSubscriptions(); @@ -903,7 +991,8 @@ describe('Threads 2.0', () => { const stateAfter = thread.state.getLatestValue(); expect(stateAfter.replies).to.have.lengthOf(4); - expect(stateAfter.replies.find((reply) => reply.id === messageToDelete.id)).to.be.undefined; + expect(stateAfter.replies.find((reply) => reply.id === messageToDelete.id)).to + .be.undefined; thread.unregisterSubscriptions(); }); @@ -929,7 +1018,11 @@ describe('Threads 2.0', () => { const deletedAt = new Date(); client.dispatchEvent({ type: 'message.deleted', - message: { ...messageToDelete, type: 'deleted', deleted_at: deletedAt.toISOString() }, + message: { + ...messageToDelete, + type: 'deleted', + deleted_at: deletedAt.toISOString(), + }, }); const stateAfter = thread.state.getLatestValue(); @@ -937,7 +1030,9 @@ describe('Threads 2.0', () => { expect(stateAfter.replies[2].id).to.equal(messageToDelete.id); expect(stateAfter.replies[2]).to.not.equal(messageToDelete); expect(stateAfter.replies[2].deleted_at).to.be.a('date'); - expect(stateAfter.replies[2].deleted_at!.toISOString()).to.equal(deletedAt.toISOString()); + expect(stateAfter.replies[2].deleted_at!.toISOString()).to.equal( + deletedAt.toISOString(), + ); expect(stateAfter.replies[2].type).to.equal('deleted'); thread.unregisterSubscriptions(); @@ -965,15 +1060,27 @@ describe('Threads 2.0', () => { expect(stateAfter.deletedAt).to.be.a('date'); expect(stateAfter.deletedAt!.toISOString()).to.equal(parentMessage.deleted_at); expect(stateAfter.parentMessage.deleted_at).to.be.a('date'); - expect(stateAfter.parentMessage.deleted_at!.toISOString()).to.equal(parentMessage.deleted_at); + expect(stateAfter.parentMessage.deleted_at!.toISOString()).to.equal( + parentMessage.deleted_at, + ); }); }); describe('Events: message.updated, reaction.new, reaction.deleted', () => { - (['message.updated', 'reaction.new', 'reaction.deleted', 'reaction.updated'] as const).forEach((eventType) => { + ( + [ + 'message.updated', + 'reaction.new', + 'reaction.deleted', + 'reaction.updated', + ] as const + ).forEach((eventType) => { it(`updates reply or parent message on "${eventType}"`, () => { const thread = createTestThread(); - const updateParentMessageOrReplyLocallySpy = sinon.spy(thread, 'updateParentMessageOrReplyLocally'); + const updateParentMessageOrReplyLocallySpy = sinon.spy( + thread, + 'updateParentMessageOrReplyLocally', + ); thread.registerSubscriptions(); client.dispatchEvent({ @@ -1009,7 +1116,9 @@ describe('Threads 2.0', () => { expect(threadManager.state.getLatestValue().threads).to.have.lengthOf(2); expect(threadManager.state.getLatestValue().unseenThreadIds).to.have.lengthOf(2); threadManager.resetState(); - expect(threadManager.state.getLatestValue()).to.be.deep.equal(THREAD_MANAGER_INITIAL_STATE); + expect(threadManager.state.getLatestValue()).to.be.deep.equal( + THREAD_MANAGER_INITIAL_STATE, + ); }); }); @@ -1027,7 +1136,9 @@ describe('Threads 2.0', () => { await clientWithUser.disconnectUser(); expect(clientWithUser.threads.state.getLatestValue().threads).to.have.lengthOf(0); - expect(clientWithUser.threads.state.getLatestValue().unseenThreadIds).to.have.lengthOf(0); + expect( + clientWithUser.threads.state.getLatestValue().unseenThreadIds, + ).to.have.lengthOf(0); }); describe('Subscription and Event Handlers', () => { @@ -1040,12 +1151,14 @@ describe('Threads 2.0', () => { sinon.restore(); }); - ([ - ['health.check', 2], - ['notification.mark_read', 1], - ['notification.thread_message_new', 8], - ['notification.channel_deleted', 11], - ] as const).forEach(([eventType, expectedUnreadCount]) => { + ( + [ + ['health.check', 2], + ['notification.mark_read', 1], + ['notification.thread_message_new', 8], + ['notification.channel_deleted', 11], + ] as const + ).forEach(([eventType, expectedUnreadCount]) => { it(`updates unread thread count on "${eventType}"`, () => { client.dispatchEvent({ type: eventType, @@ -1099,7 +1212,9 @@ describe('Threads 2.0', () => { message: generateMsg({ parent_id: uuidv4() }) as MessageResponse, }); - expect(threadManager.state.getLatestValue().unseenThreadIds).to.have.lengthOf(1); + expect(threadManager.state.getLatestValue().unseenThreadIds).to.have.lengthOf( + 1, + ); }); it('deduplicates unseen threads', () => { @@ -1118,7 +1233,9 @@ describe('Threads 2.0', () => { message: generateMsg({ parent_id: parentMessageId }) as MessageResponse, }); - expect(threadManager.state.getLatestValue().unseenThreadIds).to.have.lengthOf(1); + expect(threadManager.state.getLatestValue().unseenThreadIds).to.have.lengthOf( + 1, + ); }); it('tracks thread order becoming stale', () => { @@ -1184,9 +1301,12 @@ describe('Threads 2.0', () => { const unregisterSubscriptionsSpy = sinon.spy(thread, 'unregisterSubscriptions'); return [thread, registerSubscriptionsSpy, unregisterSubscriptionsSpy] as const; }; - const [thread1, registerThread1, unregisterThread1] = createTestThreadAndSpySubscriptions(); - const [thread2, registerThread2, unregisterThread2] = createTestThreadAndSpySubscriptions(); - const [thread3, registerThread3, unregisterThread3] = createTestThreadAndSpySubscriptions(); + const [thread1, registerThread1, unregisterThread1] = + createTestThreadAndSpySubscriptions(); + const [thread2, registerThread2, unregisterThread2] = + createTestThreadAndSpySubscriptions(); + const [thread3, registerThread3, unregisterThread3] = + createTestThreadAndSpySubscriptions(); threadManager.state.partialNext({ threads: [thread1, thread2], @@ -1324,9 +1444,16 @@ describe('Threads 2.0', () => { }); it('reuses existing thread instances', async () => { - const existingThread = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); - const newThread = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); - threadManager.state.partialNext({ threads: [existingThread], unseenThreadIds: [newThread.id] }); + const existingThread = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); + const newThread = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); + threadManager.state.partialNext({ + threads: [existingThread], + unseenThreadIds: [newThread.id], + }); stubbedQueryThreads.resolves({ threads: [newThread, existingThread], next: undefined, @@ -1344,7 +1471,9 @@ describe('Threads 2.0', () => { const existingThread = createTestThread(); existingThread.state.partialNext({ isStateStale: true }); const newThread = createTestThread({ - thread_participants: [{ user_id: 'u1' }] as ThreadResponse['thread_participants'], + thread_participants: [ + { user_id: 'u1' }, + ] as ThreadResponse['thread_participants'], }); threadManager.state.partialNext({ threads: [existingThread], @@ -1365,9 +1494,15 @@ describe('Threads 2.0', () => { }); it('reorders threads according to the response order', async () => { - const existingThread = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); - const newThread1 = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); - const newThread2 = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); + const existingThread = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); + const newThread1 = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); + const newThread2 = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); threadManager.state.partialNext({ threads: [existingThread], unseenThreadIds: [newThread1.id, newThread2.id], @@ -1464,8 +1599,12 @@ describe('Threads 2.0', () => { }); it('updates thread list and pagination', async () => { - const existingThread = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); - const newThread = createTestThread({ parentMessageOverrides: { id: uuidv4() } }); + const existingThread = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); + const newThread = createTestThread({ + parentMessageOverrides: { id: uuidv4() }, + }); threadManager.state.next((current) => ({ ...current, threads: [existingThread], diff --git a/test/unit/utils.js b/test/unit/utils.test.js similarity index 97% rename from test/unit/utils.js rename to test/unit/utils.test.js index 1a1da8ec0..92744aa36 100644 --- a/test/unit/utils.js +++ b/test/unit/utils.test.js @@ -1,4 +1,3 @@ -import chai from 'chai'; import { axiosParamsSerializer, binarySearchByDateEqualOrNearestGreater, @@ -8,9 +7,9 @@ import { } from '../../src/utils'; import sinon from 'sinon'; -const expect = chai.expect; +import { describe, beforeEach, it, expect } from 'vitest'; -describe('generateUUIDv4', () => { +describe.skip('generateUUIDv4', () => { beforeEach(() => { sinon.restore(); }); @@ -168,60 +167,7 @@ describe('messageSetPagination', () => { describe('linear', () => { describe('returned page size size is 0', () => { - ['created_at_after_or_equal', 'created_at_after', 'id_gt', 'id_gte'].forEach((option) => { - it(`requested page size === returned page size === parent set size pagination with option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: [], - parentSet: { messages: [], pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - it(`requested page size === parent set size > returned page size with option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: 1, - returnedPage: [], - parentSet: { messages: messages.slice(0, 1), pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - it(`returned page size === parent set size pagination < requested page size with option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: 1, - returnedPage: [], - parentSet: { messages: [], pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - it(`requested page size === returned page size < parent set size pagination with option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: [], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - it(`returned page size < parent set size < requested page size pagination with option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: 1, - returnedPage: [], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - }); - - ['created_at_before_or_equal', 'created_at_before', 'id_lt', 'id_lte', undefined, 'unrecognized'].forEach( + ['created_at_after_or_equal', 'created_at_after', 'id_gt', 'id_gte'].forEach( (option) => { it(`requested page size === returned page size === parent set size pagination with option ${option}`, () => { expect( @@ -231,7 +177,7 @@ describe('messageSetPagination', () => { returnedPage: [], parentSet: { messages: [], pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({ hasNext: false }); }); it(`requested page size === parent set size > returned page size with option ${option}`, () => { expect( @@ -241,7 +187,7 @@ describe('messageSetPagination', () => { returnedPage: [], parentSet: { messages: messages.slice(0, 1), pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({ hasNext: false }); }); it(`returned page size === parent set size pagination < requested page size with option ${option}`, () => { expect( @@ -251,7 +197,7 @@ describe('messageSetPagination', () => { returnedPage: [], parentSet: { messages: [], pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({ hasNext: false }); }); it(`requested page size === returned page size < parent set size pagination with option ${option}`, () => { expect( @@ -261,7 +207,7 @@ describe('messageSetPagination', () => { returnedPage: [], parentSet: { messages, pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({ hasNext: false }); }); it(`returned page size < parent set size < requested page size pagination with option ${option}`, () => { expect( @@ -271,378 +217,106 @@ describe('messageSetPagination', () => { returnedPage: [], parentSet: { messages, pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({ hasNext: false }); }); }, ); - }); - - ['created_at_after_or_equal', 'created_at_after', 'id_gt', 'id_gte'].forEach((option) => { - it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages, - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasNext: true }); - }); - - it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length + 1, - returnedPage: messages, - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - - it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 1, - returnedPage: messages, - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasNext: true }); - }); - describe('first (oldest) page message matches the first parent set message', () => { - it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 1, - returnedPage: messages.slice(0, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size === parent set size > returned page size option ${option}`, () => { + [ + 'created_at_before_or_equal', + 'created_at_before', + 'id_lt', + 'id_lte', + undefined, + 'unrecognized', + ].forEach((option) => { + it(`requested page size === returned page size === parent set size pagination with option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, requestedPageSize: messages.length, - returnedPage: messages.slice(0, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, - returnedPage: messages.slice(0, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 3, - returnedPage: messages.slice(0, -2), - parentSet: { messages: messages.slice(0, -1), pagination: {} }, + returnedPage: [], + parentSet: { messages: [], pagination: {} }, }), - ).to.eql({}); + ).to.eql({ hasPrev: false }); }); - it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + it(`requested page size === parent set size > returned page size with option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(0, -2), - parentSet: { messages: messages.slice(0, -1), pagination: {} }, + requestedPageSize: 1, + returnedPage: [], + parentSet: { messages: messages.slice(0, 1), pagination: {} }, }), - ).to.eql({}); + ).to.eql({ hasPrev: false }); }); - it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); + it(`returned page size === parent set size pagination < requested page size with option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages, - parentSet: { messages: messages.slice(0, -1), pagination: {} }, + requestedPageSize: 1, + returnedPage: [], + parentSet: { messages: [], pagination: {} }, }), - ).to.eql({}); - restore(); + ).to.eql({ hasPrev: false }); }); - it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); + it(`requested page size === returned page size < parent set size pagination with option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, requestedPageSize: messages.length, - returnedPage: messages.slice(0, -1), - parentSet: { messages: messages.slice(0, -2), pagination: {} }, + returnedPage: [], + parentSet: { messages, pagination: {} }, }), - ).to.eql({}); - restore(); + ).to.eql({ hasPrev: false }); }); - it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); + it(`returned page size < parent set size < requested page size pagination with option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, - returnedPage: messages, - parentSet: { messages: messages.slice(0, -1), pagination: {} }, + requestedPageSize: 1, + returnedPage: [], + parentSet: { messages, pagination: {} }, }), - ).to.eql({}); - restore(); + ).to.eql({ hasPrev: false }); }); }); + }); - describe('last page message matches the last parent set message', () => { - it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { + ['created_at_after_or_equal', 'created_at_after', 'id_gt', 'id_gte'].forEach( + (option) => { + it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 1, - returnedPage: messages.slice(1), + requestedPageSize: messages.length, + returnedPage: messages, parentSet: { messages, pagination: {} }, }), ).to.eql({ hasNext: true }); }); - it(`requested page size === parent set size > returned page size option ${option}`, () => { + + it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(1), + requestedPageSize: messages.length + 1, + returnedPage: messages, parentSet: { messages, pagination: {} }, }), ).to.eql({ hasNext: false }); }); - it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + + it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, - returnedPage: messages.slice(1), + requestedPageSize: messages.length - 1, + returnedPage: messages, parentSet: { messages, pagination: {} }, }), ).to.eql({ hasNext: true }); }); - it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(2), - parentSet: { messages: messages.slice(1), pagination: {} }, - }), - ).to.eql({ hasNext: false }); - }); - it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages, - parentSet: { messages: messages.slice(-1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(1), - parentSet: { messages: messages.slice(2), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, - returnedPage: messages, - parentSet: { messages: messages.slice(1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - }); - - describe('first page message & last page message do not match the first and last parent set messages', () => { - it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: [ - messages[1], - messages[0], - ...messages.slice(2, -2), - messages.slice(-1)[0], - messages.slice(-2, -1)[0], - ], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size === parent set size > returned page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length + 1, - returnedPage: [ - messages[1], - messages[0], - ...messages.slice(2, -2), - messages.slice(-1)[0], - messages.slice(-2, -1)[0], - ], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - - it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 1, - returnedPage: [ - messages[1], - messages[0], - ...messages.slice(2, -2), - messages.slice(-1)[0], - messages.slice(-2, -1)[0], - ], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - - it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 3, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length + 1, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages, - parentSet: { messages: messages.slice(1, -1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(1), - parentSet: { messages: messages.slice(1, -1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 3, - returnedPage: messages, - parentSet: { messages: messages.slice(1, -1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - }); - }); - - ['created_at_before_or_equal', 'created_at_before', 'id_lt', 'id_lte', undefined, 'unrecognized'].forEach( - (option) => { - it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages, - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasPrev: true }); - }); - - it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length + 1, - returnedPage: messages, - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasPrev: false }); - }); - - it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 1, - returnedPage: messages, - parentSet: { messages, pagination: {} }, - }), - ).to.eql({ hasPrev: true }); - }); describe('first (oldest) page message matches the first parent set message', () => { it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { @@ -653,27 +327,27 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(0, -1), parentSet: { messages, pagination: {} }, }), - ).to.eql({ hasPrev: true }); + ).to.eql({}); }); - it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + it(`requested page size === parent set size > returned page size option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, + requestedPageSize: messages.length, returnedPage: messages.slice(0, -1), parentSet: { messages, pagination: {} }, }), - ).to.eql({ hasPrev: true }); + ).to.eql({}); }); - it(`requested page size === parent set size > returned page size option ${option}`, () => { + it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, + requestedPageSize: messages.length - 2, returnedPage: messages.slice(0, -1), parentSet: { messages, pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({}); }); it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { expect( @@ -683,9 +357,9 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(0, -2), parentSet: { messages: messages.slice(0, -1), pagination: {} }, }), - ).to.eql({ hasPrev: true }); + ).to.eql({}); }); - it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, @@ -693,7 +367,7 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(0, -2), parentSet: { messages: messages.slice(0, -1), pagination: {} }, }), - ).to.eql({ hasPrev: false }); + ).to.eql({}); }); it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { const restore = consoleErrorSpy(); @@ -742,7 +416,7 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(1), parentSet: { messages, pagination: {} }, }), - ).to.eql({}); + ).to.eql({ hasNext: true }); }); it(`requested page size === parent set size > returned page size option ${option}`, () => { expect( @@ -752,7 +426,7 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(1), parentSet: { messages, pagination: {} }, }), - ).to.eql({}); + ).to.eql({ hasNext: false }); }); it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { expect( @@ -762,9 +436,9 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(1), parentSet: { messages, pagination: {} }, }), - ).to.eql({}); + ).to.eql({ hasNext: true }); }); - it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { expect( messageSetPagination({ messagePaginationOptions: option && { [option]: 'X' }, @@ -772,7 +446,7 @@ describe('messageSetPagination', () => { returnedPage: messages.slice(2), parentSet: { messages: messages.slice(1), pagination: {} }, }), - ).to.eql({}); + ).to.eql({ hasNext: false }); }); it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { const restore = consoleErrorSpy(); @@ -812,136 +486,475 @@ describe('messageSetPagination', () => { }); }); - describe('first page message & last page message do not match the first and last parent set messages', () => { - it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: [ - messages[1], - messages[0], - ...messages.slice(2, -2), - messages.slice(-1)[0], - messages.slice(-2, -1)[0], - ], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size === parent set size > returned page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length + 1, - returnedPage: [ - messages[1], - messages[0], - ...messages.slice(2, -2), - messages.slice(-1)[0], - messages.slice(-2, -1)[0], - ], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - - it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 1, - returnedPage: [ - messages[1], - messages[0], - ...messages.slice(2, -2), - messages.slice(-1)[0], - messages.slice(-2, -1)[0], - ], - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); + describe('first page message & last page message do not match the first and last parent set messages', () => { + it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: [ + messages[1], + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + messages.slice(-2, -1)[0], + ], + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size === parent set size > returned page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length + 1, + returnedPage: [ + messages[1], + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + messages.slice(-2, -1)[0], + ], + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + + it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 1, + returnedPage: [ + messages[1], + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + messages.slice(-2, -1)[0], + ], + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + + it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 2, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 3, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length + 1, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages, + parentSet: { messages: messages.slice(1, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(1), + parentSet: { messages: messages.slice(1, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 3, + returnedPage: messages, + parentSet: { messages: messages.slice(1, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + }); + }, + ); + + [ + 'created_at_before_or_equal', + 'created_at_before', + 'id_lt', + 'id_lte', + undefined, + 'unrecognized', + ].forEach((option) => { + it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages, + parentSet: { messages, pagination: {} }, + }), + ).to.eql({ hasPrev: true }); + }); + + it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length + 1, + returnedPage: messages, + parentSet: { messages, pagination: {} }, + }), + ).to.eql({ hasPrev: false }); + }); + + it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 1, + returnedPage: messages, + parentSet: { messages, pagination: {} }, + }), + ).to.eql({ hasPrev: true }); + }); + + describe('first (oldest) page message matches the first parent set message', () => { + it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 1, + returnedPage: messages.slice(0, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({ hasPrev: true }); + }); + it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 2, + returnedPage: messages.slice(0, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({ hasPrev: true }); + }); + it(`requested page size === parent set size > returned page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(0, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({ hasPrev: false }); + }); + it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 3, + returnedPage: messages.slice(0, -2), + parentSet: { messages: messages.slice(0, -1), pagination: {} }, + }), + ).to.eql({ hasPrev: true }); + }); + it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(0, -2), + parentSet: { messages: messages.slice(0, -1), pagination: {} }, + }), + ).to.eql({ hasPrev: false }); + }); + it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages, + parentSet: { messages: messages.slice(0, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(0, -1), + parentSet: { messages: messages.slice(0, -2), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 2, + returnedPage: messages, + parentSet: { messages: messages.slice(0, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + }); + + describe('last page message matches the last parent set message', () => { + it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 1, + returnedPage: messages.slice(1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size === parent set size > returned page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 2, + returnedPage: messages.slice(1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(2), + parentSet: { messages: messages.slice(1), pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages, + parentSet: { messages: messages.slice(-1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(1), + parentSet: { messages: messages.slice(2), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 2, + returnedPage: messages, + parentSet: { messages: messages.slice(1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + }); + + describe('first page message & last page message do not match the first and last parent set messages', () => { + it(`requested page size === returned page size === parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: [ + messages[1], + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + messages.slice(-2, -1)[0], + ], + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size === parent set size > returned page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`returned page size === parent set size pagination < requested page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length + 1, + returnedPage: [ + messages[1], + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + messages.slice(-2, -1)[0], + ], + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + + it(`returned page size === parent set size pagination > requested page size option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 1, + returnedPage: [ + messages[1], + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + messages.slice(-2, -1)[0], + ], + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); - it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 2, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 3, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length + 1, - returnedPage: messages.slice(1, -1), - parentSet: { messages, pagination: {} }, - }), - ).to.eql({}); - }); - it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages, - parentSet: { messages: messages.slice(1, -1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length, - returnedPage: messages.slice(1), - parentSet: { messages: messages.slice(1, -1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); - it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { - const restore = consoleErrorSpy(); - expect( - messageSetPagination({ - messagePaginationOptions: option && { [option]: 'X' }, - requestedPageSize: messages.length - 3, - returnedPage: messages, - parentSet: { messages: messages.slice(1, -1), pagination: {} }, - }), - ).to.eql({}); - restore(); - }); + it(`requested page size === returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 2, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); }); - }, - ); + it(`requested page size < returned page size < parent set size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 3, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`returned page size < parent set size < requested page size pagination option ${option}`, () => { + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length + 1, + returnedPage: messages.slice(1, -1), + parentSet: { messages, pagination: {} }, + }), + ).to.eql({}); + }); + it(`requested page size === returned page size > parent set size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages, + parentSet: { messages: messages.slice(1, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`parent set size < returned page size < requested page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length, + returnedPage: messages.slice(1), + parentSet: { messages: messages.slice(1, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + it(`requested page size < parent set size < returned page size pagination option ${option}`, () => { + const restore = consoleErrorSpy(); + expect( + messageSetPagination({ + messagePaginationOptions: option && { [option]: 'X' }, + requestedPageSize: messages.length - 3, + returnedPage: messages, + parentSet: { messages: messages.slice(1, -1), pagination: {} }, + }), + ).to.eql({}); + restore(); + }); + }); + }); }); describe('jumping to a message', () => { @@ -1218,7 +1231,11 @@ describe('messageSetPagination', () => { messageSetPagination({ messagePaginationOptions: messagePaginationOptions.firstHalf, requestedPageSize: messages.length, - returnedPage: [messages[0], ...messages.slice(2, -2), messages.slice(-1)[0]], + returnedPage: [ + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + ], parentSet: { messages: messages.slice(1, -1), pagination: {} }, }), ).to.eql({ hasPrev: false, hasNext: false }); @@ -1274,7 +1291,11 @@ describe('messageSetPagination', () => { messageSetPagination({ messagePaginationOptions: messagePaginationOptions.firstHalf, requestedPageSize: messages.length + 1, - returnedPage: [messages[1], ...messages.slice(2, -2), messages.slice(-1)[0]], + returnedPage: [ + messages[1], + ...messages.slice(2, -2), + messages.slice(-1)[0], + ], parentSet: { messages, pagination: {} }, }), ).to.eql({ hasPrev: false, hasNext: false }); @@ -1303,7 +1324,11 @@ describe('messageSetPagination', () => { messageSetPagination({ messagePaginationOptions: messagePaginationOptions.firstHalf, requestedPageSize: messages.length, - returnedPage: [messages[0], ...messages.slice(2, -2), messages.slice(-1)[0]], + returnedPage: [ + messages[0], + ...messages.slice(2, -2), + messages.slice(-1)[0], + ], parentSet: { messages: messages.slice(1, -2), pagination: {} }, }), ).to.eql({}); @@ -2623,7 +2648,9 @@ describe('messageSetPagination', () => { { description: '0 return page size', messages: [], - messagePaginationOptions: { created_at_around: createdAtISOString(2, oddSizeReturnPage) }, + messagePaginationOptions: { + created_at_around: createdAtISOString(2, oddSizeReturnPage), + }, option: 'created_at_around', }, { @@ -2704,9 +2731,19 @@ describe('', () => { { created_at: '2024-08-05T08:55:08.199808Z', id: '8' }, ]; it('finds the nearest newer item', () => { - expect(binarySearchByDateEqualOrNearestGreater(messages, new Date('2024-08-05T08:55:02.299808Z'))).to.eql(3); + expect( + binarySearchByDateEqualOrNearestGreater( + messages, + new Date('2024-08-05T08:55:02.299808Z'), + ), + ).to.eql(3); }); it('finds the nearest matching item', () => { - expect(binarySearchByDateEqualOrNearestGreater(messages, new Date('2024-08-05T08:55:07.199808Z'))).to.eql(7); + expect( + binarySearchByDateEqualOrNearestGreater( + messages, + new Date('2024-08-05T08:55:07.199808Z'), + ), + ).to.eql(7); }); }); diff --git a/test/unit/utils.test.ts b/test/unit/utils.test.ts index eeecb1ded..799d1a034 100644 --- a/test/unit/utils.test.ts +++ b/test/unit/utils.test.ts @@ -1,6 +1,6 @@ -import { expect } from 'chai'; import sinon from 'sinon'; import { v4 as uuidv4 } from 'uuid'; +import { describe, beforeEach, afterEach, it, expect } from 'vitest'; import { generateMsg } from './test-utils/generateMessage'; import { generateChannel } from './test-utils/generateChannel'; @@ -25,7 +25,12 @@ import { uniqBy, } from '../../src/utils'; -import type { ChannelFilters, ChannelSortBase, FormatMessageResponse, MessageResponse } from '../../src'; +import type { + ChannelFilters, + ChannelSortBase, + FormatMessageResponse, + MessageResponse, +} from '../../src'; import { StreamChat, Channel } from '../../src'; describe('addToMessageList', () => { @@ -33,7 +38,13 @@ describe('addToMessageList', () => { // messages with each created_at 10 seconds apart let messagesBefore: FormatMessageResponse[]; - const getNewFormattedMessage = ({ timeOffset, id = uuidv4() }: { timeOffset: number; id?: string }) => + const getNewFormattedMessage = ({ + timeOffset, + id = uuidv4(), + }: { + timeOffset: number; + id?: string; + }) => formatMessage( generateMsg({ id, @@ -43,7 +54,11 @@ describe('addToMessageList', () => { beforeEach(() => { messagesBefore = Array.from({ length: 5 }, (_, index) => - formatMessage(generateMsg({ created_at: new Date(timestamp + index * 10 * 1000) }) as MessageResponse), + formatMessage( + generateMsg({ + created_at: new Date(timestamp + index * 10 * 1000), + }) as MessageResponse, + ), ); }); @@ -59,7 +74,10 @@ describe('addToMessageList', () => { }); it('replaces the message which created_at changed to a server response created_at', () => { - const newMessage = getNewFormattedMessage({ timeOffset: 33 * 1000, id: messagesBefore[2].id }); + const newMessage = getNewFormattedMessage({ + timeOffset: 33 * 1000, + id: messagesBefore[2].id, + }); expect(newMessage.id).to.equal(messagesBefore[2].id); @@ -87,7 +105,13 @@ describe('addToMessageList', () => { const emptyMessagesBefore = []; - const messagesAfter = addToMessageList(emptyMessagesBefore, newMessage, false, 'created_at', false); + const messagesAfter = addToMessageList( + emptyMessagesBefore, + newMessage, + false, + 'created_at', + false, + ); expect(messagesAfter).to.have.length(0); }); @@ -105,7 +129,13 @@ describe('addToMessageList', () => { it("doesn't add a newest message to a message list if timestampChanged & addIfDoesNotExist are false", () => { const newMessage = getNewFormattedMessage({ timeOffset: 50 * 1000 }); - const messagesAfter = addToMessageList(messagesBefore, newMessage, false, 'created_at', false); + const messagesAfter = addToMessageList( + messagesBefore, + newMessage, + false, + 'created_at', + false, + ); expect(messagesAfter).to.have.length(5); // FIXME: it'd be nice if the function returned old @@ -114,13 +144,22 @@ describe('addToMessageList', () => { }); it("updates an existing message that wasn't filtered due to changed timestamp (timestampChanged)", () => { - const newMessage = getNewFormattedMessage({ timeOffset: 30 * 1000, id: messagesBefore[4].id }); + const newMessage = getNewFormattedMessage({ + timeOffset: 30 * 1000, + id: messagesBefore[4].id, + }); expect(messagesBefore[4].id).to.equal(newMessage.id); expect(messagesBefore[4].text).to.not.equal(newMessage.text); expect(messagesBefore[4]).to.not.equal(newMessage); - const messagesAfter = addToMessageList(messagesBefore, newMessage, false, 'created_at', false); + const messagesAfter = addToMessageList( + messagesBefore, + newMessage, + false, + 'created_at', + false, + ); expect(messagesAfter).to.have.length(5); expect(messagesAfter[4]).to.equal(newMessage); @@ -131,28 +170,44 @@ describe('findIndexInSortedArray', () => { it('finds index in the middle of haystack (asc)', () => { const needle = 5; const haystack = [1, 2, 3, 4, 6, 7, 8, 9]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'ascending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'ascending', + }); expect(index).to.eq(4); }); it('finds index at the top of haystack (asc)', () => { const needle = 0; const haystack = [1, 2, 3, 4, 6, 7, 8, 9]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'ascending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'ascending', + }); expect(index).to.eq(0); }); it('finds index at the bottom of haystack (asc)', () => { const needle = 10; const haystack = [1, 2, 3, 4, 6, 7, 8, 9]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'ascending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'ascending', + }); expect(index).to.eq(8); }); it('in a haystack with duplicates, prefers index closer to the bottom (asc)', () => { const needle = 5; const haystack = [1, 5, 5, 5, 5, 5, 8, 9]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'ascending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'ascending', + }); expect(index).to.eq(6); }); @@ -202,28 +257,44 @@ describe('findIndexInSortedArray', () => { it('finds index in the middle of haystack (desc)', () => { const needle = 5; const haystack = [9, 8, 7, 6, 4, 3, 2, 1]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'descending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'descending', + }); expect(index).to.eq(4); }); it('finds index at the top of haystack (desc)', () => { const needle = 10; const haystack = [9, 8, 7, 6, 4, 3, 2, 1]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'descending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'descending', + }); expect(index).to.eq(0); }); it('finds index at the bottom of haystack (desc)', () => { const needle = 0; const haystack = [9, 8, 7, 6, 4, 3, 2, 1]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'descending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'descending', + }); expect(index).to.eq(8); }); it('in a haystack with duplicates, prefers index closer to the top (desc)', () => { const needle = 5; const haystack = [9, 8, 5, 5, 5, 5, 5, 1]; - const index = findIndexInSortedArray({ needle, sortedArray: haystack, sortDirection: 'descending' }); + const index = findIndexInSortedArray({ + needle, + sortedArray: haystack, + sortDirection: 'descending', + }); expect(index).to.eq(2); }); @@ -280,13 +351,18 @@ describe('getAndWatchChannel', () => { client = await getClientWithUser(); - const mockedMembers = [generateMember({ user: generateUser() }), generateMember({ user: generateUser() })]; + const mockedMembers = [ + generateMember({ user: generateUser() }), + generateMember({ user: generateUser() }), + ]; const mockedChannelsQueryResponse = [ ...Array.from({ length: 2 }, () => generateChannel()), generateChannel({ channel: { type: 'messaging' }, members: mockedMembers }), ]; const mock = sandbox.mock(client); - mock.expects('post').returns(Promise.resolve({ channels: mockedChannelsQueryResponse })); + mock + .expects('post') + .returns(Promise.resolve({ channels: mockedChannelsQueryResponse })); }); afterEach(() => { @@ -295,14 +371,16 @@ describe('getAndWatchChannel', () => { it('should throw an error if neither channel nor type is provided', async () => { await client.queryChannels({}); - await expect(getAndWatchChannel({ client, id: 'test-id', members: [] })).to.be.rejectedWith( - 'Channel or channel type have to be provided to query a channel.', - ); + await expect( + getAndWatchChannel({ client, id: 'test-id', members: [] }), + ).rejects.toThrow('Channel or channel type have to be provided to query a channel.'); }); it('should throw an error if neither channel ID nor members array is provided', async () => { await client.queryChannels({}); - await expect(getAndWatchChannel({ client, type: 'test-type', id: undefined, members: [] })).to.be.rejectedWith( + await expect( + getAndWatchChannel({ client, type: 'test-type', id: undefined, members: [] }), + ).rejects.toThrow( 'Channel ID or channel members array have to be provided to query a channel.', ); }); @@ -399,7 +477,7 @@ describe('generateChannelTempCid', () => { }); it('should return undefined if members is null', () => { - const result = generateChannelTempCid('messaging', (null as unknown) as string[]); + const result = generateChannelTempCid('messaging', null as unknown as string[]); expect(result).to.be.undefined; }); @@ -429,40 +507,53 @@ describe('Channel pinning and archiving utils', () => { describe('Channel pinning', () => { it('should return false if channel is null', () => { - expect(isChannelPinned((null as unknown) as Channel)).to.be.false; + expect(isChannelPinned(null as unknown as Channel)).to.be.false; }); it('should return false if pinned_at is undefined', () => { const channelResponse = generateChannel({ membership: {} }); client.hydrateActiveChannels([channelResponse]); - const channel = client.channel(channelResponse.channel.type, channelResponse.channel.id); + const channel = client.channel( + channelResponse.channel.type, + channelResponse.channel.id, + ); expect(isChannelPinned(channel)).to.be.false; }); it('should return true if pinned_at is set', () => { - const channelResponse = generateChannel({ membership: { pinned_at: '2024-02-04T12:00:00Z' } }); + const channelResponse = generateChannel({ + membership: { pinned_at: '2024-02-04T12:00:00Z' }, + }); client.hydrateActiveChannels([channelResponse]); - const channel = client.channel(channelResponse.channel.type, channelResponse.channel.id); + const channel = client.channel( + channelResponse.channel.type, + channelResponse.channel.id, + ); expect(isChannelPinned(channel)).to.be.true; }); describe('extractSortValue', () => { it('should return null if sort is undefined', () => { - expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort: undefined })).to.be.null; + expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort: undefined })) + .to.be.null; }); it('should extract correct sort value from an array', () => { - const sort = ([{ pinned_at: -1 }, { created_at: 1 }] as unknown) as ChannelSortBase; - expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort })).to.equal(-1); + const sort = [{ pinned_at: -1 }, { created_at: 1 }] as unknown as ChannelSortBase; + expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort })).to.equal( + -1, + ); }); it('should extract correct sort value from an object', () => { - const sort = ({ pinned_at: 1 } as unknown) as ChannelSortBase; - expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort })).to.equal(1); + const sort = { pinned_at: 1 } as unknown as ChannelSortBase; + expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort })).to.equal( + 1, + ); }); it('should return null if key does not match targetKey', () => { - const sort = ({ created_at: 1 } as unknown) as ChannelSortBase; + const sort = { created_at: 1 } as unknown as ChannelSortBase; expect(extractSortValue({ atIndex: 0, targetKey: 'pinned_at', sort })).to.be.null; }); }); @@ -478,13 +569,13 @@ describe('Channel pinning and archiving utils', () => { }); it('should return false if pinned_at is not first in sort', () => { - const sort = ([{ created_at: 1 }, { pinned_at: 1 }] as unknown) as ChannelSortBase; + const sort = [{ created_at: 1 }, { pinned_at: 1 }] as unknown as ChannelSortBase; expect(shouldConsiderPinnedChannels(sort)).to.be.false; }); it('should return true if pinned_at is 1 or -1 at index 0', () => { - const sort1 = ([{ pinned_at: 1 }] as unknown) as ChannelSortBase; - const sort2 = ([{ pinned_at: -1 }] as unknown) as ChannelSortBase; + const sort1 = [{ pinned_at: 1 }] as unknown as ChannelSortBase; + const sort2 = [{ pinned_at: -1 }] as unknown as ChannelSortBase; expect(shouldConsiderPinnedChannels(sort1)).to.be.true; expect(shouldConsiderPinnedChannels(sort2)).to.be.true; }); @@ -492,21 +583,22 @@ describe('Channel pinning and archiving utils', () => { describe('findPinnedAtSortOrder', () => { it('should return null if sort is undefined', () => { - expect(findPinnedAtSortOrder({ sort: (null as unknown) as ChannelSortBase })).to.be.null; + expect(findPinnedAtSortOrder({ sort: null as unknown as ChannelSortBase })).to.be + .null; }); it('should return null if pinned_at is not present', () => { - const sort = ([{ created_at: 1 }] as unknown) as ChannelSortBase; + const sort = [{ created_at: 1 }] as unknown as ChannelSortBase; expect(findPinnedAtSortOrder({ sort })).to.be.null; }); it('should return pinned_at if found in an object', () => { - const sort = ({ pinned_at: -1 } as unknown) as ChannelSortBase; + const sort = { pinned_at: -1 } as unknown as ChannelSortBase; expect(findPinnedAtSortOrder({ sort })).to.equal(-1); }); it('should return pinned_at if found in an array', () => { - const sort = ([{ pinned_at: 1 }] as unknown) as ChannelSortBase; + const sort = [{ pinned_at: 1 }] as unknown as ChannelSortBase; expect(findPinnedAtSortOrder({ sort })).to.equal(1); }); }); @@ -517,9 +609,14 @@ describe('Channel pinning and archiving utils', () => { }); it('should return null if no channels are pinned', () => { - const channelsResponse = [generateChannel({ membership: {} }), generateChannel({ membership: {} })]; + const channelsResponse = [ + generateChannel({ membership: {} }), + generateChannel({ membership: {} }), + ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); expect(findLastPinnedChannelIndex({ channels })).to.be.null; }); @@ -530,7 +627,9 @@ describe('Channel pinning and archiving utils', () => { generateChannel({ membership: {} }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); expect(findLastPinnedChannelIndex({ channels })).to.equal(1); }); @@ -539,25 +638,34 @@ describe('Channel pinning and archiving utils', () => { describe('Channel archiving', () => { it('should return false if channel is null', () => { - expect(isChannelArchived((null as unknown) as Channel)).to.be.false; + expect(isChannelArchived(null as unknown as Channel)).to.be.false; }); it('should return false if archived_at is undefined', () => { const channelResponse = generateChannel({ membership: {} }); client.hydrateActiveChannels([channelResponse]); - const channel = client.channel(channelResponse.channel.type, channelResponse.channel.id); + const channel = client.channel( + channelResponse.channel.type, + channelResponse.channel.id, + ); expect(isChannelArchived(channel)).to.be.false; }); it('should return true if archived_at is set', () => { - const channelResponse = generateChannel({ membership: { archived_at: '2024-02-04T12:00:00Z' } }); + const channelResponse = generateChannel({ + membership: { archived_at: '2024-02-04T12:00:00Z' }, + }); client.hydrateActiveChannels([channelResponse]); - const channel = client.channel(channelResponse.channel.type, channelResponse.channel.id); + const channel = client.channel( + channelResponse.channel.type, + channelResponse.channel.id, + ); expect(isChannelArchived(channel)).to.be.true; }); it('should return false if filters is null', () => { - expect(shouldConsiderArchivedChannels((null as unknown) as ChannelFilters)).to.be.false; + expect(shouldConsiderArchivedChannels(null as unknown as ChannelFilters)).to.be + .false; }); it('should return false if filters.archived is missing', () => { @@ -566,7 +674,7 @@ describe('Channel pinning and archiving utils', () => { }); it('should return false if filters.archived is not a boolean', () => { - const mockFilters = ({ archived: 'yes' } as unknown) as ChannelFilters; + const mockFilters = { archived: 'yes' } as unknown as ChannelFilters; expect(shouldConsiderArchivedChannels(mockFilters)).to.be.false; }); @@ -592,7 +700,9 @@ describe('promoteChannel', () => { it('should return the original list if the channel is already at the top', () => { const channelsResponse = [generateChannel(), generateChannel()]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const result = promoteChannel({ channels, channelToMove: channels[0], @@ -609,7 +719,9 @@ describe('promoteChannel', () => { generateChannel({ membership: { pinned_at: '2024-02-04T12:01:00Z' } }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = channels[1]; const result = promoteChannel({ @@ -629,7 +741,9 @@ describe('promoteChannel', () => { generateChannel({ channel: { id: 'channel3' } }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = channels[2]; const result = promoteChannel({ @@ -649,7 +763,9 @@ describe('promoteChannel', () => { generateChannel({ channel: { id: 'channel3' } }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = channels[2]; const result = promoteChannel({ @@ -671,7 +787,9 @@ describe('promoteChannel', () => { ]; const newChannel = generateChannel({ channel: { id: 'channel4' } }); client.hydrateActiveChannels([...channelsResponse, newChannel]); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = client.channel(newChannel.channel.type, newChannel.channel.id); const result = promoteChannel({ @@ -680,7 +798,12 @@ describe('promoteChannel', () => { sort: {}, }); - expect(result.map((c) => c.id)).to.deep.equal(['channel4', 'channel1', 'channel2', 'channel3']); + expect(result.map((c) => c.id)).to.deep.equal([ + 'channel4', + 'channel1', + 'channel2', + 'channel3', + ]); expect(result).to.not.equal(channels); }); @@ -692,7 +815,9 @@ describe('promoteChannel', () => { ]; const newChannel = generateChannel({ channel: { id: 'channel4' } }); client.hydrateActiveChannels([...channelsResponse, newChannel]); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = client.channel(newChannel.channel.type, newChannel.channel.id); const result = promoteChannel({ @@ -702,19 +827,32 @@ describe('promoteChannel', () => { channelToMoveIndexWithinChannels: -1, }); - expect(result.map((c) => c.id)).to.deep.equal(['channel4', 'channel1', 'channel2', 'channel3']); + expect(result.map((c) => c.id)).to.deep.equal([ + 'channel4', + 'channel1', + 'channel2', + 'channel3', + ]); expect(result).to.not.equal(channels); }); it('should move the channel just below the last pinned channel if pinned channels are considered', () => { const channelsResponse = [ - generateChannel({ channel: { id: 'pinned1' }, membership: { pinned_at: '2024-02-04T12:00:00Z' } }), - generateChannel({ channel: { id: 'pinned2' }, membership: { pinned_at: '2024-02-04T12:01:00Z' } }), + generateChannel({ + channel: { id: 'pinned1' }, + membership: { pinned_at: '2024-02-04T12:00:00Z' }, + }), + generateChannel({ + channel: { id: 'pinned2' }, + membership: { pinned_at: '2024-02-04T12:01:00Z' }, + }), generateChannel({ channel: { id: 'channel1' } }), generateChannel({ channel: { id: 'channel2' } }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = channels[3]; const result = promoteChannel({ @@ -723,19 +861,32 @@ describe('promoteChannel', () => { sort: [{ pinned_at: -1 }], }); - expect(result.map((c) => c.id)).to.deep.equal(['pinned1', 'pinned2', 'channel2', 'channel1']); + expect(result.map((c) => c.id)).to.deep.equal([ + 'pinned1', + 'pinned2', + 'channel2', + 'channel1', + ]); expect(result).to.not.equal(channels); }); it('should move the channel to the top of the list if pinned channels exist but are not considered', () => { const channelsResponse = [ - generateChannel({ channel: { id: 'pinned1' }, membership: { pinned_at: '2024-02-04T12:01:00Z' } }), - generateChannel({ channel: { id: 'pinned2' }, membership: { pinned_at: '2024-02-04T12:00:00Z' } }), + generateChannel({ + channel: { id: 'pinned1' }, + membership: { pinned_at: '2024-02-04T12:01:00Z' }, + }), + generateChannel({ + channel: { id: 'pinned2' }, + membership: { pinned_at: '2024-02-04T12:00:00Z' }, + }), generateChannel({ channel: { id: 'channel1' } }), generateChannel({ channel: { id: 'channel2' } }), ]; client.hydrateActiveChannels(channelsResponse); - const channels = channelsResponse.map((c) => client.channel(c.channel.type, c.channel.id)); + const channels = channelsResponse.map((c) => + client.channel(c.channel.type, c.channel.id), + ); const channelToMove = channels[2]; const result = promoteChannel({ @@ -744,7 +895,12 @@ describe('promoteChannel', () => { sort: {}, }); - expect(result.map((c) => c.id)).to.deep.equal(['channel1', 'pinned1', 'pinned2', 'channel2']); + expect(result.map((c) => c.id)).to.deep.equal([ + 'channel1', + 'pinned1', + 'pinned2', + 'channel2', + ]); expect(result).to.not.equal(channels); }); }); @@ -799,7 +955,10 @@ describe('uniqBy', () => { { user: { id: 1, name: 'Alice' } }, ]; const result = uniqBy(array, 'user.id'); - expect(result).to.deep.equal([{ user: { id: 1, name: 'Alice' } }, { user: { id: 2, name: 'Bob' } }]); + expect(result).to.deep.equal([ + { user: { id: 1, name: 'Alice' } }, + { user: { id: 2, name: 'Bob' } }, + ]); }); it('should work with primitive identities', () => { @@ -814,7 +973,12 @@ describe('uniqBy', () => { it('should handle falsy values correctly', () => { const array = [{ id: 0 }, { id: false }, { id: null }, { id: undefined }, { id: 0 }]; const result = uniqBy(array, 'id'); - expect(result).to.deep.equal([{ id: 0 }, { id: false }, { id: null }, { id: undefined }]); + expect(result).to.deep.equal([ + { id: 0 }, + { id: false }, + { id: null }, + { id: undefined }, + ]); }); it('should work when all elements are identical', () => { @@ -828,7 +992,12 @@ describe('uniqBy', () => { it('should handle mixed types correctly', () => { const array = [{ id: 1 }, { id: '1' }, { id: 1.0 }, { id: true }, { id: false }]; - expect(uniqBy(array, 'id')).to.deep.equal([{ id: 1 }, { id: '1' }, { id: true }, { id: false }]); + expect(uniqBy(array, 'id')).to.deep.equal([ + { id: 1 }, + { id: '1' }, + { id: true }, + { id: false }, + ]); }); it('should handle undefined values in objects', () => { diff --git a/tsconfig.test.json b/tsconfig.test.json deleted file mode 100644 index 31b8d2209..000000000 --- a/tsconfig.test.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "moduleResolution": "node10", - "module": "CommonJS", - "strict": false - }, - "ts-node": { - "transpileOnly": true, - "logError": true - }, - "include": ["./test/**/*"] -} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 000000000..da6a623bb --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,11 @@ +/// + +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + testTimeout: 20000, + // not all errors have been handled so this is necessary (at least for the time being) + dangerouslyIgnoreUnhandledErrors: true, + }, +}); diff --git a/yarn.lock b/yarn.lock index 7f50389a8..485747dea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9,13 +9,6 @@ dependencies: "@jridgewell/trace-mapping" "^0.3.0" -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" @@ -95,7 +88,7 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c" integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA== -"@babel/helper-validator-identifier@^7.16.7", "@babel/helper-validator-identifier@^7.25.9": +"@babel/helper-validator-identifier@^7.25.9": version "7.25.9" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7" integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ== @@ -114,15 +107,6 @@ "@babel/traverse" "^7.17.9" "@babel/types" "^7.17.0" -"@babel/highlight@^7.10.4": - version "7.17.9" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3" - integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/parser@^7.17.9", "@babel/parser@^7.26.9": version "7.26.9" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.9.tgz#d9e78bee6dc80f9efd8f2349dcfbbcdace280fd5" @@ -165,163 +149,160 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== -"@commitlint/cli@^16.0.2": - version "16.0.2" - resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-16.0.2.tgz#393b03793fc59b93e5f4dd7dd535a6cc5a7413ca" - integrity sha512-Jt7iaBjoLGC5Nq4dHPTvTYnqPGkElFPBtTXTvBpTgatZApczyjI2plE0oG4GYWPp1suHIS/VdVDOMpPZjGVusg== - dependencies: - "@commitlint/format" "^16.0.0" - "@commitlint/lint" "^16.0.0" - "@commitlint/load" "^16.0.0" - "@commitlint/read" "^16.0.0" - "@commitlint/types" "^16.0.0" - lodash "^4.17.19" - resolve-from "5.0.0" - resolve-global "1.0.0" +"@commitlint/cli@^19.7.1": + version "19.7.1" + resolved "https://registry.yarnpkg.com/@commitlint/cli/-/cli-19.7.1.tgz#aca351ae6200af58b49de58181319015e7429601" + integrity sha512-iObGjR1tE/PfDtDTEfd+tnRkB3/HJzpQqRTyofS2MPPkDn1mp3DBC8SoPDayokfAy+xKhF8+bwRCJO25Nea0YQ== + dependencies: + "@commitlint/format" "^19.5.0" + "@commitlint/lint" "^19.7.1" + "@commitlint/load" "^19.6.1" + "@commitlint/read" "^19.5.0" + "@commitlint/types" "^19.5.0" + tinyexec "^0.3.0" yargs "^17.0.0" -"@commitlint/config-conventional@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-16.0.0.tgz#f42d9e1959416b5e691c8b5248fc2402adb1fc03" - integrity sha512-mN7J8KlKFn0kROd+q9PB01sfDx/8K/R25yITspL1No8PB4oj9M1p77xWjP80hPydqZG9OvQq+anXK3ZWeR7s3g== - dependencies: - conventional-changelog-conventionalcommits "^4.3.1" - -"@commitlint/config-validator@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-16.0.0.tgz#61dd84895e5dcab6066ff5e21e2b9a96b0ed6323" - integrity sha512-i80DGlo1FeC5jZpuoNV9NIjQN/m2dDV3jYGWg+1Wr+KldptkUHXj+6GY1Akll66lJ3D8s6aUGi3comPLHPtWHg== - dependencies: - "@commitlint/types" "^16.0.0" - ajv "^6.12.6" - -"@commitlint/ensure@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-16.0.0.tgz#fdac1e60a944a1993deb33b5e8454c559abe9866" - integrity sha512-WdMySU8DCTaq3JPf0tZFCKIUhqxaL54mjduNhu8v4D2AMUVIIQKYMGyvXn94k8begeW6iJkTf9cXBArayskE7Q== - dependencies: - "@commitlint/types" "^16.0.0" - lodash "^4.17.19" - -"@commitlint/execute-rule@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-16.0.0.tgz#824e11ba5b208c214a474ae52a51780d32d31ebc" - integrity sha512-8edcCibmBb386x5JTHSPHINwA5L0xPkHQFY8TAuDEt5QyRZY/o5DF8OPHSa5Hx2xJvGaxxuIz4UtAT6IiRDYkw== - -"@commitlint/format@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-16.0.0.tgz#6a6fb2c1e6460aff63cc6eca30a7807a96b0ce73" - integrity sha512-9yp5NCquXL1jVMKL0ZkRwJf/UHdebvCcMvICuZV00NQGYSAL89O398nhqrqxlbjBhM5EZVq0VGcV5+7r3D4zAA== - dependencies: - "@commitlint/types" "^16.0.0" - chalk "^4.0.0" - -"@commitlint/is-ignored@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-16.0.0.tgz#5ab4c4a9c7444c1a8540f50a0f1a907dfd78eb70" - integrity sha512-gmAQcwIGC/R/Lp0CEb2b5bfGC7MT5rPe09N8kOGjO/NcdNmfFSZMquwrvNJsq9hnAP0skRdHIsqwlkENkN4Lag== - dependencies: - "@commitlint/types" "^16.0.0" - semver "7.3.5" - -"@commitlint/lint@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-16.0.0.tgz#87151a935941073027907fd4752a2e3c83cebbfe" - integrity sha512-HNl15bRC0h+pLzbMzQC3tM0j1aESXsLYhElqKnXcf5mnCBkBkHzu6WwJW8rZbfxX+YwJmNljN62cPhmdBo8x0A== - dependencies: - "@commitlint/is-ignored" "^16.0.0" - "@commitlint/parse" "^16.0.0" - "@commitlint/rules" "^16.0.0" - "@commitlint/types" "^16.0.0" - -"@commitlint/load@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-16.0.0.tgz#4ab9f8502d0521209ce54d7cce58d419b8c35b48" - integrity sha512-7WhrGCkP6K/XfjBBguLkkI2XUdiiIyMGlNsSoSqgRNiD352EiffhFEApMy1/XOU+viwBBm/On0n5p0NC7e9/4A== - dependencies: - "@commitlint/config-validator" "^16.0.0" - "@commitlint/execute-rule" "^16.0.0" - "@commitlint/resolve-extends" "^16.0.0" - "@commitlint/types" "^16.0.0" - chalk "^4.0.0" - cosmiconfig "^7.0.0" - cosmiconfig-typescript-loader "^1.0.0" - lodash "^4.17.19" - resolve-from "^5.0.0" - typescript "^4.4.3" - -"@commitlint/message@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-16.0.0.tgz#4a467341fc6bc49e5a3ead005dd6aa36fa856b87" - integrity sha512-CmK2074SH1Ws6kFMEKOKH/7hMekGVbOD6vb4alCOo2+33ZSLUIX8iNkDYyrw38Jwg6yWUhLjyQLUxREeV+QIUA== - -"@commitlint/parse@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-16.0.0.tgz#5ce05af14edff806effc702ba910fcb32fcb192a" - integrity sha512-F9EjFlMw4MYgBEqoRrWZZKQBzdiJzPBI0qFDFqwUvfQsMmXEREZ242T4R5bFwLINWaALFLHEIa/FXEPa6QxCag== - dependencies: - "@commitlint/types" "^16.0.0" - conventional-changelog-angular "^5.0.11" - conventional-commits-parser "^3.2.2" - -"@commitlint/read@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-16.0.0.tgz#92fab45d4e0e4d7d049427306500270b3e459221" - integrity sha512-H4T2zsfmYQK9B+JtoQaCXWBHUhgIJyOzWZjSfuIV9Ce69/OgHoffNpLZPF2lX6yKuDrS1SQFhI/kUCjVc/e4ew== - dependencies: - "@commitlint/top-level" "^16.0.0" - "@commitlint/types" "^16.0.0" - fs-extra "^10.0.0" - git-raw-commits "^2.0.0" +"@commitlint/config-conventional@^19.7.1": + version "19.7.1" + resolved "https://registry.yarnpkg.com/@commitlint/config-conventional/-/config-conventional-19.7.1.tgz#9119a02ec8e0f4ac88f035e37dc333e7f69ace1c" + integrity sha512-fsEIF8zgiI/FIWSnykdQNj/0JE4av08MudLTyYHm4FlLWemKoQvPNUYU2M/3tktWcCEyq7aOkDDgtjrmgWFbvg== + dependencies: + "@commitlint/types" "^19.5.0" + conventional-changelog-conventionalcommits "^7.0.2" + +"@commitlint/config-validator@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/config-validator/-/config-validator-19.5.0.tgz#f0a4eda2109fc716ef01bb8831af9b02e3a1e568" + integrity sha512-CHtj92H5rdhKt17RmgALhfQt95VayrUo2tSqY9g2w+laAXyk7K/Ef6uPm9tn5qSIwSmrLjKaXK9eiNuxmQrDBw== + dependencies: + "@commitlint/types" "^19.5.0" + ajv "^8.11.0" + +"@commitlint/ensure@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/ensure/-/ensure-19.5.0.tgz#b087374a6a0a0140e5925a82901d234885d9f6dd" + integrity sha512-Kv0pYZeMrdg48bHFEU5KKcccRfKmISSm9MvgIgkpI6m+ohFTB55qZlBW6eYqh/XDfRuIO0x4zSmvBjmOwWTwkg== + dependencies: + "@commitlint/types" "^19.5.0" + lodash.camelcase "^4.3.0" + lodash.kebabcase "^4.1.1" + lodash.snakecase "^4.1.1" + lodash.startcase "^4.4.0" + lodash.upperfirst "^4.3.1" + +"@commitlint/execute-rule@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/execute-rule/-/execute-rule-19.5.0.tgz#c13da8c03ea0379f30856111e27d57518e25b8a2" + integrity sha512-aqyGgytXhl2ejlk+/rfgtwpPexYyri4t8/n4ku6rRJoRhGZpLFMqrZ+YaubeGysCP6oz4mMA34YSTaSOKEeNrg== + +"@commitlint/format@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/format/-/format-19.5.0.tgz#d879db2d97d70ae622397839fb8603d56e85a250" + integrity sha512-yNy088miE52stCI3dhG/vvxFo9e4jFkU1Mj3xECfzp/bIS/JUay4491huAlVcffOoMK1cd296q0W92NlER6r3A== + dependencies: + "@commitlint/types" "^19.5.0" + chalk "^5.3.0" -"@commitlint/resolve-extends@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-16.0.0.tgz#2136f01d81bccc29091f2720b42c8c96aa59c56e" - integrity sha512-Z/w9MAQUcxeawpCLtjmkVNXAXOmB2nhW+LYmHEZcx9O6UTauF/1+uuZ2/r0MtzTe1qw2JD+1QHVhEWYHVPlkdA== - dependencies: - "@commitlint/config-validator" "^16.0.0" - "@commitlint/types" "^16.0.0" - import-fresh "^3.0.0" - lodash "^4.17.19" +"@commitlint/is-ignored@^19.7.1": + version "19.7.1" + resolved "https://registry.yarnpkg.com/@commitlint/is-ignored/-/is-ignored-19.7.1.tgz#d3d713d97df4da5d0a6440624d0db38e3a67494e" + integrity sha512-3IaOc6HVg2hAoGleRK3r9vL9zZ3XY0rf1RsUf6jdQLuaD46ZHnXBiOPTyQ004C4IvYjSWqJwlh0/u2P73aIE3g== + dependencies: + "@commitlint/types" "^19.5.0" + semver "^7.6.0" + +"@commitlint/lint@^19.7.1": + version "19.7.1" + resolved "https://registry.yarnpkg.com/@commitlint/lint/-/lint-19.7.1.tgz#a180d5695fc5328b8566a482750df7fbf72b11c5" + integrity sha512-LhcPfVjcOcOZA7LEuBBeO00o3MeZa+tWrX9Xyl1r9PMd5FWsEoZI9IgnGqTKZ0lZt5pO3ZlstgnRyY1CJJc9Xg== + dependencies: + "@commitlint/is-ignored" "^19.7.1" + "@commitlint/parse" "^19.5.0" + "@commitlint/rules" "^19.6.0" + "@commitlint/types" "^19.5.0" + +"@commitlint/load@^19.6.1": + version "19.6.1" + resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.6.1.tgz#5fae8843a6048a2d3d1cc16da0af8ee532fa9db4" + integrity sha512-kE4mRKWWNju2QpsCWt428XBvUH55OET2N4QKQ0bF85qS/XbsRGG1MiTByDNlEVpEPceMkDr46LNH95DtRwcsfA== + dependencies: + "@commitlint/config-validator" "^19.5.0" + "@commitlint/execute-rule" "^19.5.0" + "@commitlint/resolve-extends" "^19.5.0" + "@commitlint/types" "^19.5.0" + chalk "^5.3.0" + cosmiconfig "^9.0.0" + cosmiconfig-typescript-loader "^6.1.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + lodash.uniq "^4.5.0" + +"@commitlint/message@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/message/-/message-19.5.0.tgz#c062d9a1d2b3302c3a8cac25d6d1125ea9c019b2" + integrity sha512-R7AM4YnbxN1Joj1tMfCyBryOC5aNJBdxadTZkuqtWi3Xj0kMdutq16XQwuoGbIzL2Pk62TALV1fZDCv36+JhTQ== + +"@commitlint/parse@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/parse/-/parse-19.5.0.tgz#b450dad9b5a95ac5ba472d6d0fdab822dce946fc" + integrity sha512-cZ/IxfAlfWYhAQV0TwcbdR1Oc0/r0Ik1GEessDJ3Lbuma/MRO8FRQX76eurcXtmhJC//rj52ZSZuXUg0oIX0Fw== + dependencies: + "@commitlint/types" "^19.5.0" + conventional-changelog-angular "^7.0.0" + conventional-commits-parser "^5.0.0" + +"@commitlint/read@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/read/-/read-19.5.0.tgz#601f9f1afe69852b0f28aa81cd455b40979fad6b" + integrity sha512-TjS3HLPsLsxFPQj6jou8/CZFAmOP2y+6V4PGYt3ihbQKTY1Jnv0QG28WRKl/d1ha6zLODPZqsxLEov52dhR9BQ== + dependencies: + "@commitlint/top-level" "^19.5.0" + "@commitlint/types" "^19.5.0" + git-raw-commits "^4.0.0" + minimist "^1.2.8" + tinyexec "^0.3.0" + +"@commitlint/resolve-extends@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/resolve-extends/-/resolve-extends-19.5.0.tgz#f3ec33e12d10df90cae0bfad8e593431fb61b18e" + integrity sha512-CU/GscZhCUsJwcKTJS9Ndh3AKGZTNFIOoQB2n8CmFnizE0VnEuJoum+COW+C1lNABEeqk6ssfc1Kkalm4bDklA== + dependencies: + "@commitlint/config-validator" "^19.5.0" + "@commitlint/types" "^19.5.0" + global-directory "^4.0.1" + import-meta-resolve "^4.0.0" + lodash.mergewith "^4.6.2" resolve-from "^5.0.0" - resolve-global "^1.0.0" -"@commitlint/rules@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-16.0.0.tgz#79d28c3678d2d1f7f1cdbedaedb30b01a86ee75b" - integrity sha512-AOl0y2SBTdJ1bvIv8nwHvQKRT/jC1xb09C5VZwzHoT8sE8F54KDeEzPCwHQFgUcWdGLyS10kkOTAH2MyA8EIlg== +"@commitlint/rules@^19.6.0": + version "19.6.0" + resolved "https://registry.yarnpkg.com/@commitlint/rules/-/rules-19.6.0.tgz#2436da7974c3cf2a7236257f3ef5dd40c4d91312" + integrity sha512-1f2reW7lbrI0X0ozZMesS/WZxgPa4/wi56vFuJENBmed6mWq5KsheN/nxqnl/C23ioxpPO/PL6tXpiiFy5Bhjw== dependencies: - "@commitlint/ensure" "^16.0.0" - "@commitlint/message" "^16.0.0" - "@commitlint/to-lines" "^16.0.0" - "@commitlint/types" "^16.0.0" - execa "^5.0.0" + "@commitlint/ensure" "^19.5.0" + "@commitlint/message" "^19.5.0" + "@commitlint/to-lines" "^19.5.0" + "@commitlint/types" "^19.5.0" -"@commitlint/to-lines@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-16.0.0.tgz#799980a89072302445baf595e20092fb86f0a58a" - integrity sha512-iN/qU38TCKU7uKOg6RXLpD49wNiuI0TqMqybHbjefUeP/Jmzxa8ishryj0uLyVdrAl1ZjGeD1ukXGMTtvqz8iA== - -"@commitlint/top-level@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-16.0.0.tgz#7c2efc33cc37df839b3de558c0bc2eaddb64efe6" - integrity sha512-/Jt6NLxyFkpjL5O0jxurZPCHURZAm7cQCqikgPCwqPAH0TLgwqdHjnYipl8J+AGnAMGDip4FNLoYrtgIpZGBYw== - dependencies: - find-up "^5.0.0" +"@commitlint/to-lines@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/to-lines/-/to-lines-19.5.0.tgz#e4b7f34f09064568c96a74de4f1fc9f466c4d472" + integrity sha512-R772oj3NHPkodOSRZ9bBVNq224DOxQtNef5Pl8l2M8ZnkkzQfeSTr4uxawV2Sd3ui05dUVzvLNnzenDBO1KBeQ== -"@commitlint/types@^16.0.0": - version "16.0.0" - resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-16.0.0.tgz#3c133f106d36132756c464071a7f2290966727a3" - integrity sha512-+0FvYOAS39bJ4aKjnYn/7FD4DfWkmQ6G/06I4F0Gvu4KS5twirEg8mIcLhmeRDOOKn4Tp8PwpLwBiSA6npEMQA== +"@commitlint/top-level@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/top-level/-/top-level-19.5.0.tgz#0017ffe39b5ba3611a1debd62efe28803601a14f" + integrity sha512-IP1YLmGAk0yWrImPRRc578I3dDUI5A2UBJx9FbSOjxe9sTlzFiwVJ+zeMLgAtHMtGZsC8LUnzmW1qRemkFU4ng== dependencies: - chalk "^4.0.0" + find-up "^7.0.0" -"@cspotcode/source-map-support@^0.8.0": - version "0.8.1" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" - integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== +"@commitlint/types@^19.5.0": + version "19.5.0" + resolved "https://registry.yarnpkg.com/@commitlint/types/-/types-19.5.0.tgz#c5084d1231d4dd50e40bdb656ee7601f691400b3" + integrity sha512-DSHae2obMSMkAtTBSOulg5X7/z+rGLxcXQIkg3OmWvY6wifojge5uVMydfhUvs7yQj+V7jNmRZ2Xzl8GJyqRgg== dependencies: - "@jridgewell/trace-mapping" "0.3.9" + "@types/conventional-commits-parser" "^5.0.0" + chalk "^5.3.0" "@esbuild/aix-ppc64@0.25.0": version "0.25.0" @@ -448,25 +429,94 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz#c8e119a30a7c8d60b9d2e22d2073722dde3b710b" integrity sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ== -"@eslint/eslintrc@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" - integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.19.2": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" + integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e" + integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.0.tgz#96a558f45842989cca7ea1ecd785ad5491193846" + integrity sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^12.1.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@hutson/parse-repository-url@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" - integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== +"@eslint/js@9.21.0", "@eslint/js@^9.21.0": + version "9.21.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.21.0.tgz#4303ef4e07226d87c395b8fad5278763e9c15c08" + integrity sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.2.7": + version "0.2.7" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.7.tgz#9901d52c136fb8f375906a73dcc382646c3b6a27" + integrity sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g== + dependencies: + "@eslint/core" "^0.12.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.2.tgz#1860473de7dfa1546767448f333db80cb0ff2161" + integrity sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ== "@isaacs/cliui@^8.0.2": version "8.0.2" @@ -517,7 +567,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.24" -"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== @@ -527,19 +577,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping@^0.3.0", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -854,6 +896,106 @@ "@pnpm/network.ca-file" "^1.0.1" config-chain "^1.1.11" +"@rollup/rollup-android-arm-eabi@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.8.tgz#731df27dfdb77189547bcef96ada7bf166bbb2fb" + integrity sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw== + +"@rollup/rollup-android-arm64@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.8.tgz#4bea6db78e1f6927405df7fe0faf2f5095e01343" + integrity sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q== + +"@rollup/rollup-darwin-arm64@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.8.tgz#a7aab77d44be3c44a20f946e10160f84e5450e7f" + integrity sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q== + +"@rollup/rollup-darwin-x64@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.8.tgz#c572c024b57ee8ddd1b0851703ace9eb6cc0dd82" + integrity sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw== + +"@rollup/rollup-freebsd-arm64@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.8.tgz#cf74f8113b5a83098a5c026c165742277cbfb88b" + integrity sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA== + +"@rollup/rollup-freebsd-x64@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.8.tgz#39561f3a2f201a4ad6a01425b1ff5928154ecd7c" + integrity sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q== + +"@rollup/rollup-linux-arm-gnueabihf@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.8.tgz#980d6061e373bfdaeb67925c46d2f8f9b3de537f" + integrity sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g== + +"@rollup/rollup-linux-arm-musleabihf@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.8.tgz#f91a90f30dc00d5a64ac2d9bbedc829cd3cfaa78" + integrity sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA== + +"@rollup/rollup-linux-arm64-gnu@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.8.tgz#fac700fa5c38bc13a0d5d34463133093da4c92a0" + integrity sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A== + +"@rollup/rollup-linux-arm64-musl@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.8.tgz#f50ecccf8c78841ff6df1706bc4782d7f62bf9c3" + integrity sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q== + +"@rollup/rollup-linux-loongarch64-gnu@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.8.tgz#5869dc0b28242da6553e2b52af41374f4038cd6e" + integrity sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ== + +"@rollup/rollup-linux-powerpc64le-gnu@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.8.tgz#5cdd9f851ce1bea33d6844a69f9574de335f20b1" + integrity sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw== + +"@rollup/rollup-linux-riscv64-gnu@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.8.tgz#ef5dc37f4388f5253f0def43e1440ec012af204d" + integrity sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw== + +"@rollup/rollup-linux-s390x-gnu@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.8.tgz#7dbc3ccbcbcfb3e65be74538dfb6e8dd16178fde" + integrity sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA== + +"@rollup/rollup-linux-x64-gnu@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.8.tgz#5783fc0adcab7dc069692056e8ca8d83709855ce" + integrity sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA== + +"@rollup/rollup-linux-x64-musl@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.8.tgz#00b6c29b298197a384e3c659910b47943003a678" + integrity sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ== + +"@rollup/rollup-win32-arm64-msvc@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.8.tgz#cbfee01f1fe73791c35191a05397838520ca3cdd" + integrity sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ== + +"@rollup/rollup-win32-ia32-msvc@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.8.tgz#95cdbdff48fe6c948abcf6a1d500b2bd5ce33f62" + integrity sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w== + +"@rollup/rollup-win32-x64-msvc@4.34.8": + version "4.34.8" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.8.tgz#4cdb2cfae69cdb7b1a3cc58778e820408075e928" + integrity sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + "@sec-ant/readable-stream@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz#60de891bb126abfdc5410fdc6166aca065f10a0c" @@ -1060,26 +1202,6 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== -"@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - -"@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - -"@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - -"@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - "@tufjs/canonical-json@2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz#a52f61a3d7374833fca945b2549bc30a2dd40d0a" @@ -1098,49 +1220,27 @@ resolved "https://registry.yarnpkg.com/@types/base64-js/-/base64-js-1.3.0.tgz#c939fdba49846861caf5a246b165dbf5698a317c" integrity sha512-ZmI0sZGAUNXUfMWboWwi4LcfpoVUYldyN6Oe0oJ5cCsHDU/LlRq8nQKPXhYLOx36QYSW9bNIb1vvRrD6K7Llgw== -"@types/chai-arrays@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/chai-arrays/-/chai-arrays-2.0.0.tgz#89faf96a5971e3b16d82c3afc07e1d84ecc4a360" - integrity sha512-5h5jnAC9C64YnD7WJpA5gBG7CppF/QmoWytOssJ6ysENllW49NBdpsTx6uuIBOpnzAnXThb8jBICgB62wezTLQ== - dependencies: - "@types/chai" "*" - -"@types/chai-as-promised@^7.1.4": - version "7.1.4" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.4.tgz#caf64e76fb056b8c8ced4b761ed499272b737601" - integrity sha512-1y3L1cHePcIm5vXkh1DSGf/zQq5n5xDKG1fpCvf18+uOkpce0Z1ozNFPkyWsVswK7ntN1sZBw3oU6gmN+pDUcA== - dependencies: - "@types/chai" "*" - -"@types/chai-like@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/chai-like/-/chai-like-1.1.1.tgz#c454039b0a2f92664fb5b7b7a2a66c3358783ae7" - integrity sha512-s46EZsupBuVhLn66DbRee5B0SELLmL4nFXVrBiV29BxLGm9Sh7Bful623j3AfiQRu2zAP4cnlZ3ETWB3eWc4bA== +"@types/conventional-commits-parser@^5.0.0": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.1.tgz#8cb81cf170853496cbc501a3b32dcf5e46ffb61a" + integrity sha512-7uz5EHdzz2TqoMfV7ee61Egf5y6NkcO4FB/1iCCQnbeiI1F3xzv3vK5dBCXUCLQgGYS+mUeigK1iKQzvED+QnQ== dependencies: - "@types/chai" "*" - -"@types/chai@*", "@types/chai@^4.2.15": - version "4.2.15" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.15.tgz#b7a6d263c2cecf44b6de9a051cf496249b154553" - integrity sha512-rYff6FI+ZTKAPkJUoyz7Udq3GaoDZnxYDEvdEdFZASiA7PoErltHezDishqQiSDWrGxvxmplH304jyzQmjp0AQ== + "@types/node" "*" -"@types/eslint@7.2.7": - version "7.2.7" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.7.tgz#f7ef1cf0dceab0ae6f9a976a0a9af14ab1baca26" - integrity sha512-EHXbc1z2GoQRqHaAT7+grxlTJ3WE2YNeD6jlpPoRc83cCoThRY+NUWjCUZaYmk51OICkPXn2hhphcWcWXgNW0Q== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" +"@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== -"@types/estree@*": - version "0.0.46" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" - integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/json-schema@*", "@types/json-schema@^7.0.3": - version "7.0.7" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" - integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== "@types/jsonwebtoken@^9.0.8": version "9.0.8" @@ -1150,48 +1250,23 @@ "@types/ms" "*" "@types/node" "*" -"@types/minimist@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== - -"@types/mocha@^9.0.0": - version "9.0.0" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.0.0.tgz#3205bcd15ada9bc681ac20bef64e9e6df88fd297" - integrity sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA== - "@types/ms@*": version "2.1.0" resolved "https://registry.yarnpkg.com/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== "@types/node@*": - version "22.13.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.4.tgz#3fe454d77cd4a2d73c214008b3e331bfaaf5038a" - integrity sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg== + version "22.13.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.13.5.tgz#23add1d71acddab2c6a4d31db89c0f98d330b511" + integrity sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg== dependencies: undici-types "~6.20.0" -"@types/node@^16.11.11": - version "16.11.11" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.11.tgz#6ea7342dfb379ea1210835bada87b3c512120234" - integrity sha512-KB0sixD67CeecHC33MYn+eYARkqTheIRNuu97y2XMjR7Wu3XibO1vaY6VBV6O/a89SPI81cEUIYT87UqUWlZNw== - -"@types/normalize-package-data@^2.4.0", "@types/normalize-package-data@^2.4.3": +"@types/normalize-package-data@^2.4.3": version "2.4.4" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - -"@types/prettier@^2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.2.2.tgz#e2280c89ddcbeef340099d6968d8c86ba155fdf6" - integrity sha512-i99hy7Ki19EqVOl77WplDrvgNugHnsSjECVR/wUrzw2TJXz1zlUfT2ngGckR6xN7yFYaijsMAqPkOLx9HgUqHg== - "@types/sinon@^10.0.6": version "10.0.6" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.6.tgz#bc3faff5154e6ecb69b797d311b7cf0c1b523a1d" @@ -1211,100 +1286,147 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz#6f856eca4e6a52ce9cf127dfd349096ad936aa2d" - integrity sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw== - dependencies: - "@typescript-eslint/experimental-utils" "4.17.0" - "@typescript-eslint/scope-manager" "4.17.0" - debug "^4.1.1" - functional-red-black-tree "^1.0.1" - lodash "^4.17.15" - regexpp "^3.0.0" - semver "^7.3.2" - tsutils "^3.17.1" - -"@typescript-eslint/experimental-utils@4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz#762c44aaa1a6a3c05b6d63a8648fb89b89f84c80" - integrity sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.17.0" - "@typescript-eslint/types" "4.17.0" - "@typescript-eslint/typescript-estree" "4.17.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/experimental-utils@^2.32.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f" - integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA== - dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "2.34.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" - -"@typescript-eslint/parser@^4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.17.0.tgz#141b647ffc72ebebcbf9b0fe6087f65b706d3215" - integrity sha512-KYdksiZQ0N1t+6qpnl6JeK9ycCFprS9xBAiIrw4gSphqONt8wydBw4BXJi3C11ywZmyHulvMaLjWsxDjUSDwAw== - dependencies: - "@typescript-eslint/scope-manager" "4.17.0" - "@typescript-eslint/types" "4.17.0" - "@typescript-eslint/typescript-estree" "4.17.0" - debug "^4.1.1" +"@typescript-eslint/eslint-plugin@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.25.0.tgz#5e1d56f067e5808fa82d1b75bced82396e868a14" + integrity sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.25.0" + "@typescript-eslint/type-utils" "8.25.0" + "@typescript-eslint/utils" "8.25.0" + "@typescript-eslint/visitor-keys" "8.25.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^2.0.1" -"@typescript-eslint/scope-manager@4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.17.0.tgz#f4edf94eff3b52a863180f7f89581bf963e3d37d" - integrity sha512-OJ+CeTliuW+UZ9qgULrnGpPQ1bhrZNFpfT/Bc0pzNeyZwMik7/ykJ0JHnQ7krHanFN9wcnPK89pwn84cRUmYjw== +"@typescript-eslint/parser@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.25.0.tgz#58fb81c7b7a35184ba17583f3d7ac6c4f3d95be8" + integrity sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg== dependencies: - "@typescript-eslint/types" "4.17.0" - "@typescript-eslint/visitor-keys" "4.17.0" - -"@typescript-eslint/types@4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.17.0.tgz#f57d8fc7f31b348db946498a43050083d25f40ad" - integrity sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g== + "@typescript-eslint/scope-manager" "8.25.0" + "@typescript-eslint/types" "8.25.0" + "@typescript-eslint/typescript-estree" "8.25.0" + "@typescript-eslint/visitor-keys" "8.25.0" + debug "^4.3.4" -"@typescript-eslint/typescript-estree@2.34.0": - version "2.34.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5" - integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg== +"@typescript-eslint/scope-manager@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.25.0.tgz#ac3805077aade898e98ca824294c998545597df3" + integrity sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg== dependencies: - debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" + "@typescript-eslint/types" "8.25.0" + "@typescript-eslint/visitor-keys" "8.25.0" -"@typescript-eslint/typescript-estree@4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.17.0.tgz#b835d152804f0972b80dbda92477f9070a72ded1" - integrity sha512-lRhSFIZKUEPPWpWfwuZBH9trYIEJSI0vYsrxbvVvNyIUDoKWaklOAelsSkeh3E2VBSZiNe9BZ4E5tYBZbUczVQ== +"@typescript-eslint/type-utils@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.25.0.tgz#ee0d2f67c80af5ae74b5d6f977e0f8ded0059677" + integrity sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g== dependencies: - "@typescript-eslint/types" "4.17.0" - "@typescript-eslint/visitor-keys" "4.17.0" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - semver "^7.3.2" - tsutils "^3.17.1" + "@typescript-eslint/typescript-estree" "8.25.0" + "@typescript-eslint/utils" "8.25.0" + debug "^4.3.4" + ts-api-utils "^2.0.1" -"@typescript-eslint/visitor-keys@4.17.0": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.17.0.tgz#9c304cfd20287c14a31d573195a709111849b14d" - integrity sha512-WfuMN8mm5SSqXuAr9NM+fItJ0SVVphobWYkWOwQ1odsfC014Vdxk/92t4JwS1Q6fCA/ABfCKpa3AVtpUKTNKGQ== - dependencies: - "@typescript-eslint/types" "4.17.0" - eslint-visitor-keys "^2.0.0" +"@typescript-eslint/types@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.25.0.tgz#f91512c2f532b1d6a8826cadd0b0e5cd53cf97e0" + integrity sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw== -JSONStream@^1.0.4: +"@typescript-eslint/typescript-estree@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.25.0.tgz#d8409c63abddd4cf5b93c031b24b9edc1c7c1299" + integrity sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q== + dependencies: + "@typescript-eslint/types" "8.25.0" + "@typescript-eslint/visitor-keys" "8.25.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" + +"@typescript-eslint/utils@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.25.0.tgz#3ea2f9196a915ef4daa2c8eafd44adbd7d56d08a" + integrity sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.25.0" + "@typescript-eslint/types" "8.25.0" + "@typescript-eslint/typescript-estree" "8.25.0" + +"@typescript-eslint/visitor-keys@8.25.0": + version "8.25.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.25.0.tgz#e8646324cd1793f96e02669cb717a05319403164" + integrity sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ== + dependencies: + "@typescript-eslint/types" "8.25.0" + eslint-visitor-keys "^4.2.0" + +"@vitest/expect@3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-3.0.7.tgz#3490936bc1e97fc21d53441518d51cb7116c698a" + integrity sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw== + dependencies: + "@vitest/spy" "3.0.7" + "@vitest/utils" "3.0.7" + chai "^5.2.0" + tinyrainbow "^2.0.0" + +"@vitest/mocker@3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/mocker/-/mocker-3.0.7.tgz#49a99e300bcb64dc514a43a92325fce51cd88099" + integrity sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w== + dependencies: + "@vitest/spy" "3.0.7" + estree-walker "^3.0.3" + magic-string "^0.30.17" + +"@vitest/pretty-format@3.0.7", "@vitest/pretty-format@^3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/pretty-format/-/pretty-format-3.0.7.tgz#1780516ebb4e40dd89e60b9fc7ffcbd9cba0fc22" + integrity sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg== + dependencies: + tinyrainbow "^2.0.0" + +"@vitest/runner@3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-3.0.7.tgz#65b64ba5f3291fdca4670bf9e50627200ea33b7b" + integrity sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g== + dependencies: + "@vitest/utils" "3.0.7" + pathe "^2.0.3" + +"@vitest/snapshot@3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-3.0.7.tgz#df34e3c5820bdd54bba8919291a182df5c6b8c6f" + integrity sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA== + dependencies: + "@vitest/pretty-format" "3.0.7" + magic-string "^0.30.17" + pathe "^2.0.3" + +"@vitest/spy@3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-3.0.7.tgz#6fcc100c23fb50b5e2d1d09a333245586364f67b" + integrity sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w== + dependencies: + tinyspy "^3.0.2" + +"@vitest/utils@3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-3.0.7.tgz#56268acac1027ead938150eceb2527c61d2fa204" + integrity sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg== + dependencies: + "@vitest/pretty-format" "3.0.7" + loupe "^3.1.3" + tinyrainbow "^2.0.0" + +JSONStream@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== @@ -1317,30 +1439,15 @@ abbrev@^3.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-3.0.0.tgz#c29a6337e167ac61a84b41b80461b29c5c271a27" integrity sha512-+/kfrslGQ7TNV2ecmQwMJj/B65g5KVq1/L3SGVZ3tCYGqlzFuFCGBZJtMP99wH3NpEUyAjn0zPdPUg0D+DwrOA== -acorn-jsx@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" - integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== - -acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.4.1: - version "8.8.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8" - integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== - -add-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" - integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== agent-base@^7.1.0, agent-base@^7.1.2: version "7.1.3" @@ -1363,7 +1470,7 @@ aggregate-error@^5.0.0: clean-stack "^5.2.0" indent-string "^5.0.0" -ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.6: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1373,20 +1480,15 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^7.0.2: - version "7.2.1" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.2.1.tgz#a5ac226171912447683524fa2f1248fcf8bac83d" - integrity sha512-+nu0HDv7kNSOua9apAVc979qd932rrZeb3WOvoiD31A/p1mIE5/9bN2027pE2rOPYEdS3UHzsvof4hY+lM9/WQ== +ajv@^8.11.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== dependencies: - fast-deep-equal "^3.1.1" + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" json-schema-traverse "^1.0.0" require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1, ansi-colors@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-escapes@^6.2.0: version "6.2.0" @@ -1436,14 +1538,6 @@ any-promise@^1.0.0: resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== -anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - append-transform@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-2.0.0.tgz#99d9d29c7b38391e6f428d28ce136551f0b77e12" @@ -1461,11 +1555,6 @@ archy@^1.0.0, archy@~1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= -arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -1483,36 +1572,98 @@ argv-formatter@~1.0.0: resolved "https://registry.yarnpkg.com/argv-formatter/-/argv-formatter-1.0.0.tgz#a0ca0cbc29a5b73e836eebe1cbf6c5e0e4eb82f9" integrity sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw== +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + is-string "^1.0.7" + +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + axios@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" @@ -1522,11 +1673,6 @@ axios@^1.6.0: form-data "^4.0.0" proxy-from-env "^1.1.0" -bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" @@ -1553,7 +1699,7 @@ bin-links@^5.0.0: read-cmd-shim "^5.0.0" write-file-atomic "^6.0.0" -binary-extensions@^2.0.0, binary-extensions@^2.3.0: +binary-extensions@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== @@ -1578,18 +1724,13 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: +braces@^3.0.2, braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" -browser-stdout@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - browserslist@^4.24.0: version "4.24.4" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.4.tgz#c6b2865a3f08bcb860a0e827389003b9fe686e4b" @@ -1605,10 +1746,10 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= -buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== cacache@^19.0.0, cacache@^19.0.1: version "19.0.1" @@ -1638,75 +1779,64 @@ caching-transform@^4.0.0: package-hash "^4.0.0" write-file-atomic "^3.0.0" +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.0.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" - integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== - caniuse-lite@^1.0.30001688: version "1.0.30001699" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz#a102cf330d153bf8c92bfb5be3cd44c0a89c8c12" integrity sha512-b+uH5BakXZ9Do9iK+CkDmctUSEqZl+SP056vc5usa0PL+ev5OHw003rZXcnjNDv3L8P5j6rwT6C0BPKSikW08w== -chai-arrays@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/chai-arrays/-/chai-arrays-2.2.0.tgz#571479cbc5eca81605ed4eed1e8a2a28552d2a25" - integrity sha512-4awrdGI2EH8owJ9I58PXwG4N56/FiM8bsn4CVSNEgr4GKAM6Kq5JPVApUbhUBjDakbZNuRvV7quRSC38PWq/tg== - -chai-as-promised@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" - integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== - dependencies: - check-error "^1.0.2" - -chai-like@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/chai-like/-/chai-like-1.1.1.tgz#8c558a414c34514e814d497c772547ceb7958f64" - integrity sha512-VKa9z/SnhXhkT1zIjtPACFWSoWsqVoaz1Vg+ecrKo5DCKVlgL30F/pEyEvXPBOVwCgLZcWUleCM/C1okaKdTTA== - -chai-sorted@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/chai-sorted/-/chai-sorted-0.2.0.tgz#1fee8f07fef4b0043bdff9e07022a0812c12ef55" - integrity sha1-H+6PB/70sAQ73/ngcCKggSwS71U= - -chai@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" - integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== +chai@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.2.0.tgz#1358ee106763624114addf84ab02697e411c9c05" + integrity sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw== dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.1" - type-detect "^4.0.5" + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" chalk@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.2: +chalk@^2.3.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1715,7 +1845,7 @@ chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1733,40 +1863,10 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - -character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - -character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= - -chokidar@^3.5.3: - version "3.6.0" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" - integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== chownr@^2.0.0: version "2.0.0" @@ -1778,11 +1878,6 @@ chownr@^3.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4" integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g== -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - ci-info@^4.0.0, ci-info@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-4.1.0.tgz#92319d2fa29d2620180ea5afed31f589bc98cf83" @@ -1883,11 +1978,6 @@ cmd-shim@^7.0.0: resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-7.0.0.tgz#23bcbf69fff52172f7e7c02374e18fb215826d95" integrity sha512-rtpaCbr164TPPh+zFdkWpCyZuKkjpAzODfaZCf/SVJZzJN+4bHQb/LP3Jzq5/+84um3XXY8r548XiWKSborwVw== -collapse-white-space@^1.0.2: - version "1.0.6" - resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" - integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== - color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1947,26 +2037,11 @@ compare-func@^2.0.0: array-ify "^1.0.0" dot-prop "^5.1.0" -compare-versions@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" - integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" - integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.0.2" - typedarray "^0.0.6" - concurrently@^9.1.2: version "9.1.2" resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-9.1.2.tgz#22d9109296961eaee773e12bfb1ce9a66bc9836c" @@ -1988,13 +2063,12 @@ config-chain@^1.1.11: ini "^1.3.4" proto-list "~1.2.1" -conventional-changelog-angular@^5.0.11, conventional-changelog-angular@^5.0.12: - version "5.0.13" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" - integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== +conventional-changelog-angular@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-7.0.0.tgz#5eec8edbff15aa9b1680a8dcfbd53e2d7eb2ba7a" + integrity sha512-ROjNchA9LgfNMTTFSIWPzebCwOGFdgkEq45EnvvrmSLvCtAw0HSmrCs7/ty+wAeYUZyNay0YMUNYFTRL72PkBQ== dependencies: compare-func "^2.0.0" - q "^1.5.1" conventional-changelog-angular@^8.0.0: version "8.0.0" @@ -2003,42 +2077,12 @@ conventional-changelog-angular@^8.0.0: dependencies: compare-func "^2.0.0" -conventional-changelog-atom@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/conventional-changelog-atom/-/conventional-changelog-atom-2.0.8.tgz#a759ec61c22d1c1196925fca88fe3ae89fd7d8de" - integrity sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw== - dependencies: - q "^1.5.1" - -conventional-changelog-codemirror@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/conventional-changelog-codemirror/-/conventional-changelog-codemirror-2.0.8.tgz#398e9530f08ce34ec4640af98eeaf3022eb1f7dc" - integrity sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw== - dependencies: - q "^1.5.1" - -conventional-changelog-config-spec@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" - integrity sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ== - -conventional-changelog-conventionalcommits@4.6.1: - version "4.6.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.1.tgz#f4c0921937050674e578dc7875f908351ccf4014" - integrity sha512-lzWJpPZhbM1R0PIzkwzGBCnAkH5RKJzJfFQZcl/D+2lsJxAwGnDKBqn/F4C1RD31GJNn8NuKWQzAZDAVXPp2Mw== - dependencies: - compare-func "^2.0.0" - lodash "^4.17.15" - q "^1.5.1" - -conventional-changelog-conventionalcommits@^4.3.1, conventional-changelog-conventionalcommits@^4.5.0: - version "4.6.3" - resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz#0765490f56424b46f6cb4db9135902d6e5a36dc2" - integrity sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g== +conventional-changelog-conventionalcommits@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-7.0.2.tgz#aa5da0f1b2543094889e8cf7616ebe1a8f5c70d5" + integrity sha512-NKXYmMR/Hr1DevQegFB4MwfM5Vv0m4UIxKZTTYuD98lpTknaZlSRrDOG4X7wIXpGkfsYxZTghUN+Qq+T0YQI7w== dependencies: compare-func "^2.0.0" - lodash "^4.17.15" - q "^1.5.1" conventional-changelog-conventionalcommits@^8.0.0: version "8.0.0" @@ -2047,82 +2091,6 @@ conventional-changelog-conventionalcommits@^8.0.0: dependencies: compare-func "^2.0.0" -conventional-changelog-core@^4.2.1: - version "4.2.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz#e50d047e8ebacf63fac3dc67bf918177001e1e9f" - integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== - dependencies: - add-stream "^1.0.0" - conventional-changelog-writer "^5.0.0" - conventional-commits-parser "^3.2.0" - dateformat "^3.0.0" - get-pkg-repo "^4.0.0" - git-raw-commits "^2.0.8" - git-remote-origin-url "^2.0.0" - git-semver-tags "^4.1.1" - lodash "^4.17.15" - normalize-package-data "^3.0.0" - q "^1.5.1" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - through2 "^4.0.0" - -conventional-changelog-ember@^2.0.9: - version "2.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-ember/-/conventional-changelog-ember-2.0.9.tgz#619b37ec708be9e74a220f4dcf79212ae1c92962" - integrity sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A== - dependencies: - q "^1.5.1" - -conventional-changelog-eslint@^3.0.9: - version "3.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-eslint/-/conventional-changelog-eslint-3.0.9.tgz#689bd0a470e02f7baafe21a495880deea18b7cdb" - integrity sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA== - dependencies: - q "^1.5.1" - -conventional-changelog-express@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/conventional-changelog-express/-/conventional-changelog-express-2.0.6.tgz#420c9d92a347b72a91544750bffa9387665a6ee8" - integrity sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ== - dependencies: - q "^1.5.1" - -conventional-changelog-jquery@^3.0.11: - version "3.0.11" - resolved "https://registry.yarnpkg.com/conventional-changelog-jquery/-/conventional-changelog-jquery-3.0.11.tgz#d142207400f51c9e5bb588596598e24bba8994bf" - integrity sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw== - dependencies: - q "^1.5.1" - -conventional-changelog-jshint@^2.0.9: - version "2.0.9" - resolved "https://registry.yarnpkg.com/conventional-changelog-jshint/-/conventional-changelog-jshint-2.0.9.tgz#f2d7f23e6acd4927a238555d92c09b50fe3852ff" - integrity sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA== - dependencies: - compare-func "^2.0.0" - q "^1.5.1" - -conventional-changelog-preset-loader@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" - integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== - -conventional-changelog-writer@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz#e0757072f045fe03d91da6343c843029e702f359" - integrity sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ== - dependencies: - conventional-commits-filter "^2.0.7" - dateformat "^3.0.0" - handlebars "^4.7.7" - json-stringify-safe "^5.0.1" - lodash "^4.17.15" - meow "^8.0.0" - semver "^6.0.0" - split "^1.0.0" - through2 "^4.0.0" - conventional-changelog-writer@^8.0.0: version "8.0.1" resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-8.0.1.tgz#656e156ea0ab02b3bb574b7073beeb4f81c5b4bb" @@ -2133,47 +2101,20 @@ conventional-changelog-writer@^8.0.0: meow "^13.0.0" semver "^7.5.2" -conventional-changelog@3.1.24: - version "3.1.24" - resolved "https://registry.yarnpkg.com/conventional-changelog/-/conventional-changelog-3.1.24.tgz#ebd180b0fd1b2e1f0095c4b04fd088698348a464" - integrity sha512-ed6k8PO00UVvhExYohroVPXcOJ/K1N0/drJHx/faTH37OIZthlecuLIRX/T6uOp682CAoVoFpu+sSEaeuH6Asg== - dependencies: - conventional-changelog-angular "^5.0.12" - conventional-changelog-atom "^2.0.8" - conventional-changelog-codemirror "^2.0.8" - conventional-changelog-conventionalcommits "^4.5.0" - conventional-changelog-core "^4.2.1" - conventional-changelog-ember "^2.0.9" - conventional-changelog-eslint "^3.0.9" - conventional-changelog-express "^2.0.6" - conventional-changelog-jquery "^3.0.11" - conventional-changelog-jshint "^2.0.9" - conventional-changelog-preset-loader "^2.3.4" - -conventional-commits-filter@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" - integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== - dependencies: - lodash.ismatch "^4.4.0" - modify-values "^1.0.0" - conventional-commits-filter@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz#72811f95d379e79d2d39d5c0c53c9351ef284e86" integrity sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q== -conventional-commits-parser@^3.2.0, conventional-commits-parser@^3.2.2: - version "3.2.4" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz#a7d3b77758a202a9b2293d2112a8d8052c740972" - integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q== +conventional-commits-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-5.0.0.tgz#57f3594b81ad54d40c1b4280f04554df28627d9a" + integrity sha512-ZPMl0ZJbw74iS9LuX9YIAiW8pfM5p3yh2o/NbXHbkFuZzY5jvdi5jFycEOkmBW5H5I7nA+D6f3UcsCLP2vvSEA== dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" + JSONStream "^1.3.5" + is-text-path "^2.0.0" + meow "^12.0.1" + split2 "^4.0.0" conventional-commits-parser@^6.0.0: version "6.1.0" @@ -2182,20 +2123,6 @@ conventional-commits-parser@^6.0.0: dependencies: meow "^13.0.0" -conventional-recommended-bump@6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" - integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.3.4" - conventional-commits-filter "^2.0.7" - conventional-commits-parser "^3.2.0" - git-raw-commits "^2.0.8" - git-semver-tags "^4.1.1" - meow "^8.0.0" - q "^1.5.1" - convert-hrtime@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/convert-hrtime/-/convert-hrtime-5.0.0.tgz#f2131236d4598b95de856926a67100a0a97e9fa3" @@ -2213,24 +2140,12 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cosmiconfig-typescript-loader@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-1.0.3.tgz#528f2bb3e6b6705020dc42df659f24837e75b611" - integrity sha512-ARo21VjxdacJUcHxgVMEYNIoVPYiuKOEwWBIYej4M22+pEbe3LzKgmht2UPM+0u7/T/KnZf2r/5IzHv2Nwz+/w== +cosmiconfig-typescript-loader@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz#7f644503e1c2bff90aed2d29a637008f279646bb" + integrity sha512-tJ1w35ZRUiM5FeTzT7DtYWAFFv37ZLqSRkGi2oeCK1gPhvaWjkAtfXvLmvE1pRfxxp9aQo6ba/Pvg1dKj05D4g== dependencies: - cosmiconfig "^7" - ts-node "^10.4.0" - -cosmiconfig@^7, cosmiconfig@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" + jiti "^2.4.1" cosmiconfig@^9.0.0: version "9.0.0" @@ -2242,15 +2157,10 @@ cosmiconfig@^9.0.0: js-yaml "^4.1.0" parse-json "^5.2.0" -create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - -cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== +cross-spawn@^7.0.0, cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== dependencies: path-key "^3.1.0" shebang-command "^2.0.0" @@ -2268,17 +2178,39 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== +dargs@^8.0.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/dargs/-/dargs-8.1.0.tgz#a34859ea509cbce45485e5aa356fef70bfcc7272" + integrity sha512-wAV9QHOsNbwnWdNW2FYvE1P56wtgSbM+3SZcdGiWQILwVjACCXDCI3Ai8QlCjMDB8YK5zySiXZYBiwGmNY3lnw== -dateformat@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" - integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@^4.3.5, debug@^4.3.6: +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.6, debug@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -2292,30 +2224,22 @@ debug@4.3.4: dependencies: ms "2.1.2" -decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" + ms "^2.1.1" -decamelize@^1.1.0, decamelize@^1.2.0: +decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== deep-extend@^0.6.0: version "0.6.0" @@ -2334,27 +2258,30 @@ default-require-extensions@^3.0.0: dependencies: strip-bom "^4.0.0" +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= -detect-indent@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" - integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== - -detect-newline@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" - integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== - -diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - -diff@^5.0.0, diff@^5.1.0, diff@^5.2.0: +diff@^5.0.0, diff@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== @@ -2366,10 +2293,10 @@ dir-glob@^3.0.0, dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== dependencies: esutils "^2.0.2" @@ -2385,13 +2312,14 @@ dotenv@^8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== -dotgitignore@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/dotgitignore/-/dotgitignore-2.1.0.tgz#a4b15a4e4ef3cf383598aaf1dfa4a04bcc089b7b" - integrity sha512-sCm11ak2oY6DglEPpCB8TixLjWAxd3kJTs6UIcSasNYxXdFPV+YKlye92c8H4kKFqV5qYMIh7d+cYecEg0dIkA== +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== dependencies: - find-up "^3.0.0" - minimatch "^3.0.4" + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" duplexer2@~0.1.0: version "0.1.4" @@ -2444,13 +2372,6 @@ encoding@^0.1.13: dependencies: iconv-lite "^0.6.2" -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - env-ci@^11.0.0: version "11.1.0" resolved "https://registry.yarnpkg.com/env-ci/-/env-ci-11.1.0.tgz#b26eeb692f76c1f69ddc1fb2d4a3d371088a54f9" @@ -2481,6 +2402,111 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.23.2, es-abstract@^1.23.5, es-abstract@^1.23.9: + version "1.23.9" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.9.tgz#5b45994b7de78dada5c1bebf1379646b32b9d606" + integrity sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.2.7" + get-proto "^1.0.0" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-regex "^1.2.1" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.0" + math-intrinsics "^1.1.0" + object-inspect "^1.13.3" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.3" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.18" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.6.0.tgz#da49f587fd9e68ee2404fe4e256c0c7d3a81be21" + integrity sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-shim-unscopables@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== + dependencies: + hasown "^2.0.2" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + es6-error@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" @@ -2537,126 +2563,123 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-prettier@^8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz#4ef1eaf97afe5176e6a75ddfb57c335121abc5a6" - integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw== - -eslint-plugin-markdown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-markdown/-/eslint-plugin-markdown-2.0.0.tgz#cd650beda2b599cd9e4535ea369266b5d0e49d23" - integrity sha512-zt10JoexHeJFMTE5egDcetAJ34bn5k/92s0wAuRZfhDAyI0ryEj+O91JL2CbBExajie6BE5L63y47dN1Sbp6mQ== - dependencies: - remark-parse "^5.0.0" - unified "^6.1.2" - -eslint-plugin-prettier@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz#7079cfa2497078905011e6f82e8dd8453d1371b7" - integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ== - dependencies: - prettier-linter-helpers "^1.0.0" - -eslint-plugin-sonarjs@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.6.0.tgz#3ee3b04f1f9587ef02b255a5d2f96e500c4789bb" - integrity sha512-y+sXXWsYVW2kNEjmZI87laFspwC/hic7wyMjsPFoST8aQ2hESUVavkZjnTeVdHMOmlmcloKkyX/GJJetmfBY4Q== - -eslint-plugin-typescript-sort-keys@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-typescript-sort-keys/-/eslint-plugin-typescript-sort-keys-1.5.0.tgz#cc2ae7a9311422d8eab760ae01524426fd204004" - integrity sha512-Pq0geV5TbkoGyxiPUH9AZhloRbQekrprmiXpMWmtSURfWvsWtPtsEPDLVKhDN19S791zbqnw+cm7enzu6833/w== - dependencies: - "@typescript-eslint/experimental-utils" "^2.32.0" - json-schema "^0.2.5" - natural-compare-lite "^1.4.0" +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + string.prototype.trimend "^1.0.8" + tsconfig-paths "^3.15.0" -eslint-scope@^5.0.0, eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== dependencies: esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.0.0, eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + estraverse "^5.2.0" -eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@7.21.0: - version "7.21.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.21.0.tgz#4ecd5b8c5b44f5dedc9b8a110b01bbfeb15d1c83" - integrity sha512-W2aJbXpMNofUp0ztQaF40fveSsJBjlSCSWpy//gzfTvwC+USs/nceBrKmlJOiM8r1bLwP2EuYkCqArn/6QTIgg== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.0" - ajv "^6.10.0" +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9.21.0: + version "9.21.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.21.0.tgz#b1c9c16f5153ff219791f627b94ab8f11f811591" + integrity sha512-KjeihdFqTPhOMXTt7StsDxriV4n66ueuF/jfPNC3j/lduHwr/ijDwJMsF+wyMJethgiKi5wniIE243vi07d3pg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.2" + "@eslint/core" "^0.12.0" + "@eslint/eslintrc" "^3.3.0" + "@eslint/js" "9.21.0" + "@eslint/plugin-kit" "^0.2.7" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" esutils "^2.0.2" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash "^4.17.20" - minimatch "^3.0.4" + lodash.merge "^4.6.2" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.4" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" + optionator "^0.9.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -2667,16 +2690,18 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" @@ -2735,32 +2760,27 @@ execa@^9.0.0: strip-final-newline "^4.0.0" yoctocolors "^2.0.0" +expect-type@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/expect-type/-/expect-type-1.1.0.tgz#a146e414250d13dfc49eafcfd1344a4060fa4c75" + integrity sha512-bFi65yM+xZgk+u/KRIpekdSYkTB5W1pEf0Lt8Q8Msh7b+eQ7LXVtIB1Bkm4fvclDEL1b2CZkMhv2mOeF8tMdkA== + exponential-backoff@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.2.tgz#a8f26adb96bf78e8cd8ad1037928d5e5c0679d91" integrity sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA== -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - fast-content-type-parse@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz#c236124534ee2cb427c8d8e5ba35a4856947847b" integrity sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q== -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - -fast-glob@^3.1.1, fast-glob@^3.3.3: +fast-glob@^3.3.2, fast-glob@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== @@ -2781,6 +2801,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + fastest-levenshtein@^1.0.16: version "1.0.16" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" @@ -2800,13 +2825,6 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -figures@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - figures@^6.0.0, figures@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/figures/-/figures-6.1.0.tgz#935479f51865fa7479f6fa94fc6fc7ac14e62c4a" @@ -2814,12 +2832,12 @@ figures@^6.0.0, figures@^6.1.0: dependencies: is-unicode-supported "^2.0.0" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" fill-range@^7.1.1: version "7.1.1" @@ -2849,13 +2867,6 @@ find-up@^2.0.0: dependencies: locate-path "^2.0.0" -find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" @@ -2872,12 +2883,14 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-versions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" - integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== +find-up@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-7.0.0.tgz#e8dec1455f74f78d888ad65bf7ca13dd2b4e66fb" + integrity sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g== dependencies: - semver-regex "^3.1.2" + locate-path "^7.2.0" + path-exists "^5.0.0" + unicorn-magic "^0.1.0" find-versions@^6.0.0: version "6.0.0" @@ -2887,29 +2900,31 @@ find-versions@^6.0.0: semver-regex "^4.0.5" super-regex "^1.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" + flatted "^3.2.9" + keyv "^4.5.4" -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.1.tgz#c4b489e80096d9df1dfc97c79871aea7c617c469" - integrity sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA== +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== follow-redirects@^1.15.0: version "1.15.3" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== +for-each@^0.3.3: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + foreground-child@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" @@ -2948,22 +2963,6 @@ fromentries@^1.2.0: resolved "https://registry.yarnpkg.com/fromentries/-/fromentries-1.3.2.tgz#e4bca6808816bf8f93b52750f1127f5a6fd86e3a" integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== -fs-access@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fs-access/-/fs-access-1.0.1.tgz#d6a87f262271cefebec30c553407fb995da8777a" - integrity sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o= - dependencies: - null-check "^1.0.0" - -fs-extra@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" - integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - fs-extra@^11.0.0: version "11.3.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.0.tgz#0daced136bbaf65a555a326719af931adc7a314d" @@ -2992,10 +2991,10 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== function-bind@^1.1.2: version "1.1.2" @@ -3007,10 +3006,22 @@ function-timeout@^1.0.1: resolved "https://registry.yarnpkg.com/function-timeout/-/function-timeout-1.0.2.tgz#e5a7b6ffa523756ff20e1231bbe37b5f373aadd5" integrity sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== gensync@^1.0.0-beta.2: version "1.0.0-beta.2" @@ -3027,25 +3038,34 @@ get-east-asian-width@^1.0.0: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz#5e6ebd9baee6fb8b7b6bd505221065f0cd91f64e" integrity sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-pkg-repo@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" - integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== dependencies: - "@hutson/parse-repository-url" "^3.0.0" - hosted-git-info "^4.0.0" - through2 "^2.0.0" - yargs "^16.2.0" + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" get-stream@^6.0.0: version "6.0.1" @@ -3070,6 +3090,15 @@ get-stream@^9.0.0: "@sec-ant/readable-stream" "^0.4.1" is-stream "^4.0.1" +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + git-log-parser@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/git-log-parser/-/git-log-parser-1.2.1.tgz#44355787b37af7560dcc4ddc01cb53b5d139cc28" @@ -3082,47 +3111,29 @@ git-log-parser@^1.2.0: through2 "~2.0.0" traverse "0.6.8" -git-raw-commits@^2.0.0, git-raw-commits@^2.0.8: - version "2.0.11" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz#bc3576638071d18655e1cc60d7f524920008d723" - integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== - dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - -git-remote-origin-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= - dependencies: - gitconfiglocal "^1.0.0" - pify "^2.3.0" - -git-semver-tags@^4.0.0, git-semver-tags@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" - integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== - dependencies: - meow "^8.0.0" - semver "^6.0.0" - -gitconfiglocal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= +git-raw-commits@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-4.0.0.tgz#b212fd2bff9726d27c1283a1157e829490593285" + integrity sha512-ICsMM1Wk8xSGMowkOmPrzo2Fgmfo4bMHLNX6ytHjajRJUqvHOw/TFapQ+QG75c3X/tTDDhOSRPGC52dDbNM8FQ== dependencies: - ini "^1.3.2" + dargs "^8.0.0" + meow "^12.0.1" + split2 "^4.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^10.2.2, glob@^10.3.10, glob@^10.3.7, glob@^10.4.5: version "10.4.5" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" @@ -3147,36 +3158,35 @@ glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" - integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= +global-directory@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/global-directory/-/global-directory-4.0.1.tgz#4d7ac7cfd2cb73f304c53b8810891748df5e361e" + integrity sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q== dependencies: - ini "^1.3.4" + ini "4.1.1" globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-16.0.0.tgz#3d7684652c5c4fbd086ec82f9448214da49382d8" + integrity sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A== -globby@^11.0.1: - version "11.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.2.tgz#1af538b766a3b540ebfb58a32b2e2d5897321d83" - integrity sha512-2ZThXDvvV8fYFRVIxnrMQBipZQDr7MxKAmQK1vujaj9/7eF0efG7BPUKJ7jP7G5SLF37xKDXvO4S/KKLj/Z0og== +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.1.1" - ignore "^5.1.4" - merge2 "^1.3.0" - slash "^3.0.0" + define-properties "^1.2.1" + gopd "^1.0.1" globby@^14.0.0: version "14.1.0" @@ -3190,6 +3200,11 @@ globby@^14.0.0: slash "^5.1.0" unicorn-magic "^0.3.0" +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + graceful-fs@4.2.10: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -3200,6 +3215,11 @@ graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" @@ -3212,10 +3232,10 @@ handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== has-flag@^3.0.0: version "3.0.0" @@ -3227,6 +3247,32 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + hasha@^5.0.0: version "5.2.2" resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.2.2.tgz#a48477989b3b327aea3c04f53096d816d97522a1" @@ -3242,11 +3288,6 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" -he@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" @@ -3257,18 +3298,6 @@ hook-std@^3.0.0: resolved "https://registry.yarnpkg.com/hook-std/-/hook-std-3.0.0.tgz#47038a01981e07ce9d83a6a3b2eb98cad0f7bd58" integrity sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw== -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - -hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" - integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== - dependencies: - lru-cache "^6.0.0" - hosted-git-info@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-7.0.2.tgz#9b751acac097757667f30114607ef7b661ff4f17" @@ -3324,21 +3353,10 @@ human-signals@^8.0.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-8.0.0.tgz#2d3d63481c7c2319f0373428b01ffe30da6df852" integrity sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA== -husky@^4.3.8: - version "4.3.8" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" - integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== - dependencies: - chalk "^4.0.0" - ci-info "^2.0.0" - compare-versions "^3.6.0" - cosmiconfig "^7.0.0" - find-versions "^4.0.0" - opencollective-postinstall "^2.0.2" - pkg-dir "^5.0.0" - please-upgrade-node "^3.2.0" - slash "^3.0.0" - which-pm-runs "^1.0.0" +husky@^9.1.7: + version "9.1.7" + resolved "https://registry.yarnpkg.com/husky/-/husky-9.1.7.tgz#d46a38035d101b46a70456a850ff4201344c0b2d" + integrity sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA== iconv-lite@^0.6.2: version "0.6.3" @@ -3354,22 +3372,17 @@ ignore-walk@^7.0.0: dependencies: minimatch "^9.0.0" -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - -ignore@^5.1.4: - version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" - integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== ignore@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.3.tgz#397ef9315dfe0595671eefe8b633fec6943ab733" integrity sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA== -import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: +import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== @@ -3418,12 +3431,17 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1" + integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g== + +ini@^1.3.4, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -3446,6 +3464,15 @@ init-package-json@^7.0.2: validate-npm-package-license "^3.0.4" validate-npm-package-name "^6.0.0" +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + into-stream@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-7.0.0.tgz#d1a211e146be8acfdb84dabcbf00fe8205e72936" @@ -3467,35 +3494,50 @@ ip-regex@^5.0.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-5.0.0.tgz#cd313b2ae9c80c07bd3851e12bf4fa4dc5480632" integrity sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw== -is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - -is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== dependencies: - binary-extensions "^2.0.0" + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" -is-buffer@^1.1.4: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== is-cidr@^5.1.0: version "5.1.1" @@ -3504,23 +3546,42 @@ is-cidr@^5.1.0: dependencies: cidr-regex "^4.1.1" -is-core-module@^2.16.0, is-core-module@^2.5.0: +is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== dependencies: hasown "^2.0.2" -is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -3538,17 +3599,35 @@ is-fullwidth-code-point@^5.0.0: dependencies: get-east-asian-width "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-generator-function@^1.0.10: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== + dependencies: + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" -is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" is-number@^7.0.0: version "7.0.0" @@ -3560,21 +3639,33 @@ is-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== -is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - is-plain-obj@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + is-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" @@ -3590,48 +3681,82 @@ is-stream@^4.0.1: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-4.0.1.tgz#375cf891e16d2e4baec250b85926cffc14720d9b" integrity sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A== -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= +is-string@^1.0.7, is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== dependencies: - text-extensions "^1.0.0" + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-text-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-2.0.0.tgz#b2484e2b720a633feb2e85b67dc193ff72c75636" + integrity sha512-+oDTluR6WEjdXEJMnC2z6A4FRwFoYuvShVVEGsS7ewc0UTi2QtAKMDJuL4BDEVt+5T7MjFo12RP8ghOM75oKJw== + dependencies: + text-extensions "^2.0.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - is-unicode-supported@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a" integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ== -is-whitespace-character@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" - integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== + dependencies: + call-bound "^1.0.3" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-word-character@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" - integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== - isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -3738,6 +3863,11 @@ java-properties@^1.0.2: resolved "https://registry.yarnpkg.com/java-properties/-/java-properties-1.0.2.tgz#ccd1fa73907438a5b5c38982269d0e771fe78211" integrity sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ== +jiti@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -3768,6 +3898,11 @@ jsesc@^3.0.2: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -3793,11 +3928,6 @@ json-schema-traverse@^1.0.0: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== -json-schema@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.5.tgz#97997f50972dd0500214e208c407efa4b5d7063b" - integrity sha512-gWJOWYFrhQ8j7pVm0EM8Slr+EPVq1Phf6lvzvD/WCeqkrx/f2xBI0xOsRRS9xCn3I4vKtP519dvs3TP09r24wQ== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" @@ -3808,10 +3938,12 @@ json-stringify-nice@^1.1.4: resolved "https://registry.yarnpkg.com/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz#2c937962b80181d3f317dd39aa323e14f5a60a67" integrity sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw== -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" json5@^2.2.1: version "2.2.1" @@ -3880,10 +4012,12 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" -kind-of@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" levn@^0.4.1: version "0.4.1" @@ -4060,14 +4194,6 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - locate-path@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" @@ -4082,11 +4208,23 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +locate-path@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-7.2.0.tgz#69cb1779bd90b35ab1e771e1f2f89a202c2a8a8a" + integrity sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA== + dependencies: + p-locate "^6.0.0" + lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.capitalize@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" @@ -4122,11 +4260,6 @@ lodash.isinteger@^4.0.4: resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" integrity sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA== -lodash.ismatch@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" - integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= - lodash.isnumber@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" @@ -4142,29 +4275,56 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.kebabcase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" + integrity sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.mergewith@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" + integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== + lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== +lodash.snakecase@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d" + integrity sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw== + +lodash.startcase@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.startcase/-/lodash.startcase-4.4.0.tgz#9436e34ed26093ed7ffae1936144350915d9add8" + integrity sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg== + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== + lodash.uniqby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302" integrity sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww== -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4: +lodash.upperfirst@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce" + integrity sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg== + +lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -log-symbols@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - log-update@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/log-update/-/log-update-6.0.0.tgz#0ddeb7ac6ad658c944c1de902993fce7c33f5e59" @@ -4176,6 +4336,11 @@ log-update@^6.0.0: strip-ansi "^7.1.0" wrap-ansi "^9.0.0" +loupe@^3.1.0, loupe@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.3.tgz#042a8f7986d77f3d0f98ef7990a2b2fef18b0fd2" + integrity sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug== + lru-cache@^10.0.1, lru-cache@^10.2.0, lru-cache@^10.2.2: version "10.4.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" @@ -4188,12 +4353,12 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== +magic-string@^0.30.17: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== dependencies: - yallist "^4.0.0" + "@jridgewell/sourcemap-codec" "^1.5.0" make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" @@ -4202,11 +4367,6 @@ make-dir@^3.0.0, make-dir@^3.0.2: dependencies: semver "^6.0.0" -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - make-fetch-happen@^14.0.0, make-fetch-happen@^14.0.1, make-fetch-happen@^14.0.2, make-fetch-happen@^14.0.3: version "14.0.3" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz#d74c3ecb0028f08ab604011e0bc6baed483fcdcd" @@ -4224,21 +4384,6 @@ make-fetch-happen@^14.0.0, make-fetch-happen@^14.0.1, make-fetch-happen@^14.0.2, promise-retry "^2.0.1" ssri "^12.0.0" -map-obj@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - -map-obj@^4.0.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - -markdown-escapes@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" - integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== - marked-terminal@^7.0.0: version "7.3.0" resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-7.3.0.tgz#7a86236565f3dd530f465ffce9c3f8b62ef270e8" @@ -4257,28 +4402,21 @@ marked@^12.0.0: resolved "https://registry.yarnpkg.com/marked/-/marked-12.0.2.tgz#b31578fe608b599944c69807b00f18edab84647e" integrity sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q== +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +meow@^12.0.1: + version "12.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-12.1.1.tgz#e558dddbab12477b69b2e9a2728c327f191bace6" + integrity sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw== + meow@^13.0.0: version "13.2.0" resolved "https://registry.yarnpkg.com/meow/-/meow-13.2.0.tgz#6b7d63f913f984063b3cc261b6e8800c4cd3474f" integrity sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA== -meow@^8.0.0: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -4332,25 +4470,13 @@ mimic-fn@^4.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== +minimatch@^3.0.4, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" -minimatch@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== - dependencies: - brace-expansion "^2.0.1" - minimatch@^9.0.0, minimatch@^9.0.4, minimatch@^9.0.5: version "9.0.5" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" @@ -4358,16 +4484,7 @@ minimatch@^9.0.0, minimatch@^9.0.4, minimatch@^9.0.5: dependencies: brace-expansion "^2.0.1" -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist@^1.2.0, minimist@^1.2.5: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -4454,37 +4571,6 @@ mkdirp@^3.0.1: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== -mocha@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-11.1.0.tgz#20d7c6ac4d6d6bcb60a8aa47971fca74c65c3c66" - integrity sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg== - dependencies: - ansi-colors "^4.1.3" - browser-stdout "^1.3.1" - chokidar "^3.5.3" - debug "^4.3.5" - diff "^5.2.0" - escape-string-regexp "^4.0.0" - find-up "^5.0.0" - glob "^10.4.5" - he "^1.2.0" - js-yaml "^4.1.0" - log-symbols "^4.1.0" - minimatch "^5.1.6" - ms "^2.1.3" - serialize-javascript "^6.0.2" - strip-json-comments "^3.1.1" - supports-color "^8.1.1" - workerpool "^6.5.1" - yargs "^17.7.2" - yargs-parser "^21.1.1" - yargs-unparser "^2.0.0" - -modify-values@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" - integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -4509,10 +4595,10 @@ mz@^2.4.0: object-assign "^4.0.1" thenify-all "^1.0.0" -natural-compare-lite@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" - integrity sha1-F7CVgZiJef3a/gIB6TG6kzyWy7Q= +nanoid@^3.3.8: + version "3.3.8" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== natural-compare@^1.4.0: version "1.4.0" @@ -4590,26 +4676,6 @@ nopt@^8.0.0: dependencies: abbrev "^3.0.0" -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - -normalize-package-data@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - normalize-package-data@^6.0.0: version "6.0.2" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-6.0.2.tgz#a7bc22167fe24025412bcff0a9651eb768b03506" @@ -4628,11 +4694,6 @@ normalize-package-data@^7.0.0: semver "^7.3.5" validate-npm-package-license "^3.0.4" -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - normalize-url@^8.0.0: version "8.0.1" resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" @@ -4812,11 +4873,6 @@ npm@^10.5.0: which "^5.0.0" write-file-atomic "^6.0.0" -null-check@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" - integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= - nyc@^15.1.0: version "15.1.0" resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" @@ -4855,6 +4911,57 @@ object-assign@^4.0.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -4876,22 +4983,26 @@ onetime@^6.0.0: dependencies: mimic-fn "^4.0.0" -opencollective-postinstall@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" + word-wrap "^1.2.5" + +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" p-each-series@^3.0.0: version "3.0.0" @@ -4917,7 +5028,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0: +p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -4931,6 +5042,13 @@ p-limit@^3.0.2: dependencies: yocto-queue "^0.1.0" +p-limit@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-4.0.0.tgz#914af6544ed32bfa54670b061cafcbd04984b644" + integrity sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ== + dependencies: + yocto-queue "^1.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -4938,13 +5056,6 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -4959,6 +5070,13 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" +p-locate@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-6.0.0.tgz#3da9a49d4934b901089dca3302fa65dc5a05c04f" + integrity sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw== + dependencies: + p-limit "^4.0.0" + p-map@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" @@ -5072,20 +5190,8 @@ parse-conflict-json@^4.0.0: integrity sha512-37CN2VtcuvKgHUs8+0b1uJeEsbGn61GRHz469C94P5xiOoqpDYJYwjg4RY9Vmz39WyZAVkR5++nbJwLMIgOCnQ== dependencies: json-parse-even-better-errors "^4.0.0" - just-diff "^6.0.0" - just-diff-apply "^5.2.0" - -parse-entities@^1.1.0: - version "1.2.2" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" - integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" + just-diff "^6.0.0" + just-diff-apply "^5.2.0" parse-json@^4.0.0: version "4.0.0" @@ -5095,7 +5201,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0, parse-json@^5.2.0: +parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -5146,6 +5252,11 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== +path-exists@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-5.0.0.tgz#a6aad9489200b21fab31e49cf09277e5116fb9e7" + integrity sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -5181,13 +5292,6 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - path-type@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" @@ -5198,17 +5302,22 @@ path-type@^6.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-6.0.0.tgz#2f1bb6791a91ce99194caede5d6c5920ed81eb51" integrity sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ== -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== picocolors@^1.0.0, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: +picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -5218,11 +5327,6 @@ pidtree@0.6.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== -pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - pify@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" @@ -5243,19 +5347,10 @@ pkg-dir@^4.1.0: dependencies: find-up "^4.0.0" -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - -please-upgrade-node@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" - integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== - dependencies: - semver-compare "^1.0.0" +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== postcss-selector-parser@^6.1.2: version "6.1.2" @@ -5265,22 +5360,24 @@ postcss-selector-parser@^6.1.2: cssesc "^3.0.0" util-deprecate "^1.0.2" +postcss@^8.5.3: + version "8.5.3" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.3.tgz#1463b6f1c7fb16fe258736cba29a2de35237eafb" + integrity sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A== + dependencies: + nanoid "^3.3.8" + picocolors "^1.1.1" + source-map-js "^1.2.1" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - -prettier@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" - integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== +prettier@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.2.tgz#d066c6053200da0234bf8fa1ef45168abed8b914" + integrity sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg== pretty-ms@^9.0.0: version "9.2.0" @@ -5311,11 +5408,6 @@ proggy@^3.0.0: resolved "https://registry.yarnpkg.com/proggy/-/proggy-3.0.0.tgz#874e91fed27fe00a511758e83216a6b65148bd6c" integrity sha512-QE8RApCM3IaRRxVzxrjbgNMpQEX6Wu0p0KBeoSiSEw5/bsGwZHsshF4LCxH2jp/r6BU+bqA3LrMDEYNfJnpD8Q== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - promise-all-reject-late@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz#f8ebf13483e5ca91ad809ccc2fcf25f26f8643c2" @@ -5356,11 +5448,6 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== -q@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - qrcode-terminal@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz#bb5b699ef7f9f0505092a3748be4464fe71b5819" @@ -5371,18 +5458,6 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.2.tgz#abf64491e6ecf0f38a6502403d4cda04f372dfd3" integrity sha512-dB15eXv3p2jDlbOiNLyMabYg1/sXvppd8DP2J3EOCQ0AkuSXCW2tP7mnVouVLJKgUMY6yP0kcQDVpLCN13h4Xg== -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -5415,42 +5490,6 @@ read-package-up@^11.0.0: read-pkg "^9.0.0" type-fest "^4.6.0" -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - read-pkg@^9.0.0: version "9.0.1" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-9.0.1.tgz#b1b81fb15104f5dbb121b6bbdee9bbc9739f569b" @@ -5469,15 +5508,6 @@ read@^4.0.0: dependencies: mute-stream "^2.0.0" -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" - integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" @@ -5491,25 +5521,31 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - -regexpp@^3.0.0, regexpp@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" - integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" registry-auth-token@^5.0.0: version "5.1.0" @@ -5525,37 +5561,6 @@ release-zalgo@^1.0.0: dependencies: es6-error "^4.0.1" -remark-parse@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95" - integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA== - dependencies: - collapse-white-space "^1.0.2" - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - is-whitespace-character "^1.0.0" - is-word-character "^1.0.0" - markdown-escapes "^1.0.0" - parse-entities "^1.1.0" - repeat-string "^1.5.4" - state-toggle "^1.0.0" - trim "0.0.1" - trim-trailing-lines "^1.0.0" - unherit "^1.0.4" - unist-util-remove-position "^1.0.0" - vfile-location "^2.0.0" - xtend "^4.0.1" - -repeat-string@^1.5.4: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - -replace-ext@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" - integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -5571,24 +5576,17 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -resolve-from@5.0.0, resolve-from@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" - integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== - resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve-global@1.0.0, resolve-global@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-global/-/resolve-global-1.0.0.tgz#a2a79df4af2ca3f49bf77ef9ddacd322dad19255" - integrity sha512-zFa12V4OLtT5XUX/Q4VLvTfBf+Ok0SPc1FNGM/z9ctUdiU618qwKpWnd0CHs3+RqROfyEg/DhuHbMWYqcgljEw== - dependencies: - global-dirs "^0.1.1" +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve@^1.10.0: +resolve@^1.22.4: version "1.22.10" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== @@ -5620,7 +5618,7 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -5634,6 +5632,34 @@ rimraf@^5.0.5: dependencies: glob "^10.3.7" +rollup@^4.30.1: + version "4.34.8" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.34.8.tgz#e859c1a51d899aba9bcf451d4eed1d11fb8e2a6e" + integrity sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.34.8" + "@rollup/rollup-android-arm64" "4.34.8" + "@rollup/rollup-darwin-arm64" "4.34.8" + "@rollup/rollup-darwin-x64" "4.34.8" + "@rollup/rollup-freebsd-arm64" "4.34.8" + "@rollup/rollup-freebsd-x64" "4.34.8" + "@rollup/rollup-linux-arm-gnueabihf" "4.34.8" + "@rollup/rollup-linux-arm-musleabihf" "4.34.8" + "@rollup/rollup-linux-arm64-gnu" "4.34.8" + "@rollup/rollup-linux-arm64-musl" "4.34.8" + "@rollup/rollup-linux-loongarch64-gnu" "4.34.8" + "@rollup/rollup-linux-powerpc64le-gnu" "4.34.8" + "@rollup/rollup-linux-riscv64-gnu" "4.34.8" + "@rollup/rollup-linux-s390x-gnu" "4.34.8" + "@rollup/rollup-linux-x64-gnu" "4.34.8" + "@rollup/rollup-linux-x64-musl" "4.34.8" + "@rollup/rollup-win32-arm64-msvc" "4.34.8" + "@rollup/rollup-win32-ia32-msvc" "4.34.8" + "@rollup/rollup-win32-x64-msvc" "4.34.8" + fsevents "~2.3.2" + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -5648,7 +5674,18 @@ rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + +safe-buffer@^5.0.1: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5658,6 +5695,23 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" @@ -5698,11 +5752,6 @@ semantic-release@^24.2.3: signale "^1.2.1" yargs "^17.5.1" -semver-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" - integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= - semver-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-4.0.0.tgz#3afcf5ed6d62259f5c72d0d5d50dffbdc9680df5" @@ -5710,50 +5759,57 @@ semver-diff@^4.0.0: dependencies: semver "^7.3.5" -semver-regex@^3.1.2: - version "3.1.4" - resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.4.tgz#13053c0d4aa11d070a2f2872b6b1e3ae1e1971b4" - integrity sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA== - semver-regex@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-4.0.5.tgz#fbfa36c7ba70461311f5debcb3928821eb4f9180" integrity sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw== -"semver@2 || 3 || 4 || 5": - version "5.7.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" - integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== - -semver@7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.1.1, semver@^7.1.2, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: +semver@^7.1.1, semver@^7.1.2, semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: version "7.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== -serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -5771,6 +5827,51 @@ shell-quote@^1.8.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.6" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" @@ -5821,25 +5922,11 @@ skin-tone@^2.0.0: dependencies: unicode-emoji-modifier-base "^1.0.0" -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - slash@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - slice-ansi@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" @@ -5878,6 +5965,11 @@ socks@^2.8.3: ip-address "^9.0.5" smart-buffer "^4.2.0" +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -5934,12 +6026,10 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== -split2@^3.0.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== split2@~1.0.0: version "1.0.0" @@ -5948,13 +6038,6 @@ split2@~1.0.0: dependencies: through2 "~2.0.0" -split@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - sprintf-js@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" @@ -5972,31 +6055,15 @@ ssri@^12.0.0: dependencies: minipass "^7.0.3" -standard-version@^9.3.2: - version "9.3.2" - resolved "https://registry.yarnpkg.com/standard-version/-/standard-version-9.3.2.tgz#28db8c1be66fd2d736f28f7c5de7619e64cd6dab" - integrity sha512-u1rfKP4o4ew7Yjbfycv80aNMN2feTiqseAhUhrrx2XtdQGmu7gucpziXe68Z4YfHVqlxVEzo4aUA0Iu3VQOTgQ== - dependencies: - chalk "^2.4.2" - conventional-changelog "3.1.24" - conventional-changelog-config-spec "2.1.0" - conventional-changelog-conventionalcommits "4.6.1" - conventional-recommended-bump "6.1.0" - detect-indent "^6.0.0" - detect-newline "^3.1.0" - dotgitignore "^2.1.0" - figures "^3.1.0" - find-up "^5.0.0" - fs-access "^1.0.1" - git-semver-tags "^4.0.0" - semver "^7.1.1" - stringify-package "^1.0.1" - yargs "^16.0.0" +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== -state-toggle@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" - integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== +std-env@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.8.0.tgz#b56ffc1baf1a29dcc80a3bdf11d7fca7c315e7d5" + integrity sha512-Bc3YwwCB+OzldMxOXJIIvC6cPRWr/LxOp48CdQTOkPyk/t4JWWJbrilwBd7RJzKV8QW7tJkcgAmeuLLJugl5/w== stream-combiner2@~1.1.1: version "1.1.1" @@ -6047,12 +6114,37 @@ string-width@^7.0.0: get-east-asian-width "^1.0.0" strip-ansi "^7.1.0" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== dependencies: - safe-buffer "~5.2.0" + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" string_decoder@~1.1.1: version "1.1.1" @@ -6061,11 +6153,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringify-package@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" - integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== - "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" @@ -6112,14 +6199,7 @@ strip-final-newline@^4.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz#35a369ec2ac43df356e3edd5dcebb6429aa1fa5c" integrity sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw== -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -6176,16 +6256,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -table@^6.0.4: - version "6.0.7" - resolved "https://registry.yarnpkg.com/table/-/table-6.0.7.tgz#e45897ffbcc1bcf9e8a87bf420f2c9e5a7a52a34" - integrity sha512-rxZevLGTUzWna/qBLObOe16kB2RTnnbhciwgPbMMlazz1yZGVEgnZK762xyVdVznhqxrfCeBMmMkgOOaPwjH7g== - dependencies: - ajv "^7.0.2" - lodash "^4.17.20" - slice-ansi "^4.0.0" - string-width "^4.2.0" - tar@^6.1.11, tar@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" @@ -6234,12 +6304,12 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== +text-extensions@^2.0.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-2.4.0.tgz#a1cfcc50cf34da41bfd047cc744f804d1680ea34" + integrity sha512-te/NtwBwfiNRLf9Ijqx3T0nlqZiQ2XrrtBvu+cLL8ZRrGkO0NHTug8MYFKyoSrv/sHTaSKfilUkizV6XhxMJ3g== -text-table@^0.2.0, text-table@~0.2.0: +text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= @@ -6258,7 +6328,7 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -through2@^2.0.0, through2@~2.0.0: +through2@~2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -6266,17 +6336,10 @@ through2@^2.0.0, through2@~2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - -through@2, "through@>=2.2.7 <3": +"through@>=2.2.7 <3": version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== time-span@^5.1.0: version "5.1.0" @@ -6290,6 +6353,31 @@ tiny-relative-date@^1.3.0: resolved "https://registry.yarnpkg.com/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz#fa08aad501ed730f31cc043181d995c39a935e07" integrity sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A== +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.0, tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinypool@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-1.0.2.tgz#706193cc532f4c100f66aa00b01c42173d9051b2" + integrity sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA== + +tinyrainbow@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== + +tinyspy@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-3.0.2.tgz#86dd3cf3d737b15adcf17d7887c84a75201df20a" + integrity sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q== + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -6312,62 +6400,26 @@ treeverse@^3.0.0: resolved "https://registry.yarnpkg.com/treeverse/-/treeverse-3.0.0.tgz#dd82de9eb602115c6ebd77a574aae67003cb48c8" integrity sha512-gcANaAnd2QDZFmHFEOF4k7uc1J/6a6z3DJMd/QwEyxLoKGiptJRwid582r7QIsFlFMIZ3SnxfS52S4hm2DHkuQ== -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - -trim-trailing-lines@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0" - integrity sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ== - -trim@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" - integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= - -trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +ts-api-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd" + integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w== -ts-node@^10.4.0, ts-node@^10.9.2: - version "10.9.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" - integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== - dependencies: - "@cspotcode/source-map-support" "^0.8.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.1" - yn "3.1.1" - -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" tslib@^2.1.0, tslib@^2.8.1: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== -tsutils@^3.17.1: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - tuf-js@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/tuf-js/-/tuf-js-3.0.1.tgz#e3f07ed3d8e87afaa70607bd1ef801d5c1f57177" @@ -6384,22 +6436,12 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.5, type-detect@^4.0.8: +type-detect@4.0.8, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.0, type-fest@^0.8.1: +type-fest@^0.8.0: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== @@ -6424,6 +6466,51 @@ type-fest@^4.6.0, type-fest@^4.7.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.35.0.tgz#007ed74d65c2ca0fb3b564b3dc8170d5c872d665" integrity sha512-2/AwEFQDFEy30iOLjrvHDIH7e4HEWH+f1Yl1bI5XMqzuoCUqwYCdxachgsgv0og/JdVZUhbfjcJAoHj5L1753A== +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + typedarray-to-buffer@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" @@ -6431,15 +6518,14 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - -typescript@^4.4.3: - version "4.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" - integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== +typescript-eslint@^8.25.0: + version "8.25.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.25.0.tgz#73047c157cd70ee93cf2f9243f1599d21cf60239" + integrity sha512-TxRdQQLH4g7JkoFlYG3caW5v1S6kEkz8rqt80iQJZUYPq1zD1Ra7HfQBJJ88ABRaMvHAXnwRvRB4V+6sQ9xN5Q== + dependencies: + "@typescript-eslint/eslint-plugin" "8.25.0" + "@typescript-eslint/parser" "8.25.0" + "@typescript-eslint/utils" "8.25.0" typescript@^5.7.3: version "5.7.3" @@ -6451,19 +6537,21 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.5.tgz#cdabb7d4954231d80cb4a927654c4655e51f4859" integrity sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ== +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + undici-types@~6.20.0: version "6.20.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== -unherit@^1.0.4: - version "1.1.3" - resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" - integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== - dependencies: - inherits "^2.0.0" - xtend "^4.0.0" - unicode-emoji-modifier-base@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz#dbbd5b54ba30f287e2a8d5a249da6c0cef369459" @@ -6479,18 +6567,6 @@ unicorn-magic@^0.3.0: resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104" integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA== -unified@^6.1.2: - version "6.2.0" - resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba" - integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-plain-obj "^1.1.0" - trough "^1.0.0" - vfile "^2.0.0" - x-is-string "^0.1.0" - unique-filename@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-4.0.0.tgz#a06534d370e7c977a939cd1d11f7f0ab8f1fed13" @@ -6512,37 +6588,6 @@ unique-string@^3.0.0: dependencies: crypto-random-string "^4.0.0" -unist-util-is@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" - integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== - -unist-util-remove-position@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" - integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== - dependencies: - unist-util-visit "^1.1.0" - -unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" - integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== - -unist-util-visit-parents@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" - integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== - dependencies: - unist-util-is "^3.0.0" - -unist-util-visit@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" - integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== - dependencies: - unist-util-visit-parents "^2.0.0" - universal-user-agent@^7.0.0, universal-user-agent@^7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-7.0.2.tgz#52e7d0e9b3dc4df06cc33cb2b9fd79041a54827e" @@ -6573,32 +6618,22 @@ url-join@^5.0.0: resolved "https://registry.yarnpkg.com/url-join/-/url-join-5.0.0.tgz#c2f1e5cbd95fa91082a93b58a1f42fecb4bdbcf1" integrity sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA== -util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: +util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +uuid@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-11.1.0.tgz#9549028be1753bb934fc96e2bca09bb4105ae912" + integrity sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A== + uuid@^3.3.3: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -v8-compile-cache-lib@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" - integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== - -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: +validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== @@ -6611,42 +6646,115 @@ validate-npm-package-name@^6.0.0: resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-6.0.0.tgz#3add966c853cfe36e0e8e6a762edd72ae6f1d6ac" integrity sha512-d7KLgL1LD3U3fgnvWEY1cQXoO/q6EQ1BSz48Sa149V/5zVTAbgmZIpyI8TRi6U9/JNyeYLlTKsEMPtLC27RFUg== -vfile-location@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" - integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== - -vfile-message@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" - integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== +vite-node@3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-3.0.7.tgz#f15bc1e0c343ac00115a52c7e110471a5a315c72" + integrity sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A== dependencies: - unist-util-stringify-position "^1.1.1" + cac "^6.7.14" + debug "^4.4.0" + es-module-lexer "^1.6.0" + pathe "^2.0.3" + vite "^5.0.0 || ^6.0.0" -vfile@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a" - integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w== +"vite@^5.0.0 || ^6.0.0": + version "6.2.0" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.2.0.tgz#9dcb543380dab18d8384eb840a76bf30d78633f0" + integrity sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ== dependencies: - is-buffer "^1.1.4" - replace-ext "1.0.0" - unist-util-stringify-position "^1.0.0" - vfile-message "^1.0.0" + esbuild "^0.25.0" + postcss "^8.5.3" + rollup "^4.30.1" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-3.0.7.tgz#ed8f42e1b0e09e2179eaefd966cb58a8b75f0f6a" + integrity sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg== + dependencies: + "@vitest/expect" "3.0.7" + "@vitest/mocker" "3.0.7" + "@vitest/pretty-format" "^3.0.7" + "@vitest/runner" "3.0.7" + "@vitest/snapshot" "3.0.7" + "@vitest/spy" "3.0.7" + "@vitest/utils" "3.0.7" + chai "^5.2.0" + debug "^4.4.0" + expect-type "^1.1.0" + magic-string "^0.30.17" + pathe "^2.0.3" + std-env "^3.8.0" + tinybench "^2.9.0" + tinyexec "^0.3.2" + tinypool "^1.0.2" + tinyrainbow "^2.0.0" + vite "^5.0.0 || ^6.0.0" + vite-node "3.0.7" + why-is-node-running "^2.3.0" walk-up-path@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" integrity sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA== +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which-pm-runs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" - integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= +which-typed-array@^1.1.16, which-typed-array@^1.1.18: + version "1.1.18" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" + integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" + for-each "^0.3.3" + gopd "^1.2.0" + has-tostringtag "^1.0.2" which@^2.0.1: version "2.0.2" @@ -6662,21 +6770,24 @@ which@^5.0.0: dependencies: isexe "^3.1.1" -word-wrap@^1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= -workerpool@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" - integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== - "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" @@ -6750,12 +6861,7 @@ ws@^8.18.1: resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.1.tgz#ea131d3784e1dfdff91adb0a4a116b127515e3cb" integrity sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w== -x-is-string@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" - integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= - -xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: +xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== @@ -6790,11 +6896,6 @@ yaml@2.3.4: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== -yaml@^1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e" - integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg== - yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" @@ -6803,7 +6904,7 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2, yargs-parser@^20.2.3: +yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== @@ -6813,16 +6914,6 @@ yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs-unparser@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - yargs@^15.0.2: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" @@ -6840,7 +6931,7 @@ yargs@^15.0.2: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^16.0.0, yargs@^16.2.0: +yargs@^16.0.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -6866,16 +6957,16 @@ yargs@^17.0.0, yargs@^17.5.1, yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +yocto-queue@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.1.1.tgz#fef65ce3ac9f8a32ceac5a634f74e17e5b232110" + integrity sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g== + yoctocolors@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.1.1.tgz#e0167474e9fbb9e8b3ecca738deaa61dd12e56fc"