diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index e7ab5c05..00000000 --- a/.eslintrc +++ /dev/null @@ -1,137 +0,0 @@ -{ - "root": true, - "env": { - "node": true - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": ["./tsconfig.json"] - }, - "plugins": [ - "eslint-plugin-import", - "eslint-plugin-prefer-arrow", - "@typescript-eslint", - "prettier" - ], - "extends": [ - "plugin:@typescript-eslint/recommended", - "plugin:@typescript-eslint/recommended-requiring-type-checking", - "plugin:prettier/recommended" - ], - "rules": { - // "indent": ["warn", 2], - "prefer-rest-params": "off", - "prefer-spread": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-return": "off", - "@typescript-eslint/no-floating-promises": "off", - "@typescript-eslint/restrict-template-expressions": "off", - "@typescript-eslint/explicit-module-boundary-types": "off", - "@typescript-eslint/require-await": "off", - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/unbound-method": "off", - "@typescript-eslint/no-this-alias": "off", - "@typescript-eslint/prefer-regexp-exec": "off", - "@typescript-eslint/no-misused-promises": "off", - "@typescript-eslint/restrict-plus-operands": "off", - // ---- - "@typescript-eslint/adjacent-overload-signatures": "error", - "@typescript-eslint/array-type": [ - "error", - { - "default": "array" - } - ], - "@typescript-eslint/ban-types": "off", - "@typescript-eslint/consistent-type-assertions": "error", - "@typescript-eslint/dot-notation": "error", - "@typescript-eslint/explicit-member-accessibility": [ - "error", - { - "accessibility": "no-public" - } - ], - "@typescript-eslint/naming-convention": "off", - "@typescript-eslint/no-empty-function": "off", - "@typescript-eslint/no-empty-interface": "error", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-misused-new": "error", - "@typescript-eslint/no-namespace": "error", - "@typescript-eslint/no-parameter-properties": "off", - "@typescript-eslint/no-unused-expressions": "error", - "@typescript-eslint/no-use-before-define": "off", - "@typescript-eslint/no-var-requires": "error", - "@typescript-eslint/prefer-for-of": "error", - "@typescript-eslint/prefer-function-type": "error", - "@typescript-eslint/prefer-namespace-keyword": "error", - "@typescript-eslint/triple-slash-reference": [ - "error", - { - "path": "always", - "types": "prefer-import", - "lib": "always" - } - ], - "@typescript-eslint/unified-signatures": "error", - "@typescript-eslint/consistent-type-imports": ["warn", { "prefer": "type-imports" }], - "arrow-parens": ["off", "always"], - "complexity": "off", - "constructor-super": "error", - "eqeqeq": ["error", "smart"], - "guard-for-in": "error", - "id-blacklist": "off", - "id-match": "off", - "import/order": "off", - "max-classes-per-file": "off", - "max-len": "off", - "no-bitwise": "error", - "no-caller": "error", - "no-cond-assign": "error", - "no-console": "error", - "no-debugger": "error", - "no-empty": "off", - "no-eval": "error", - "no-fallthrough": "off", - "no-invalid-this": "off", - "no-new-wrappers": "error", - "no-shadow": [ - "off", - { - "hoist": "all" - } - ], - "no-throw-literal": "error", - "no-undef-init": "error", - "no-underscore-dangle": "off", - "no-unsafe-finally": "error", - "no-unused-labels": "error", - "no-var": "error", - "object-shorthand": "error", - "one-var": ["error", "never"], - "prefer-arrow/prefer-arrow-functions": "off", - "prefer-const": "error", - "radix": "error", - "spaced-comment": [ - "error", - "always", - { - "markers": ["/"] - } - ], - "use-isnan": "error", - "valid-typeof": "off" - }, - "overrides": [ - { - "files": ["test/**/*.ts"], - "rules": { - "@typescript-eslint/ban-ts-comment": "off", - "@typescript-eslint/no-unused-vars": "off", - "no-console": "off" - } - } - ] -} diff --git a/.github/contributing.md b/.github/contributing.md index 52f1de26..e4005303 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -2,31 +2,29 @@ Thank you for contributing to Feathers! :heart: :tada: -This repo is the main core and where most issues are reported. Feathers embraces modularity and is broken up across many repos. To make this easier to manage we currently use [Zenhub](https://www.zenhub.com/) for issue triage and visibility. They have a free browser plugin you can install so that you can see what is in flight at any time, but of course you also always see current issues in Github. - ## Report a bug Before creating an issue please make sure you have checked out the docs, specifically the [FAQ](https://docs.feathersjs.com/help/faq.html) section. You might want to also try searching Github. It's pretty likely someone has already asked a similar question. -If you haven't found your answer please feel free to join our [slack channel](http://slack.feathersjs.com), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathers` or `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Slack and Github. +If you haven't found your answer please feel free to join our [Discord server](https://discord.gg/qa8kez8QBx), create an issue on Github, or post on [Stackoverflow](http://stackoverflow.com) using the `feathersjs` tag. We try our best to monitor Stackoverflow but you're likely to get more immediate responses in Discord and Github. -Issues can be reported in the [issue tracker](https://github.com/feathersjs/feathers/issues). Since feathers combines many modules it can be hard for us to assess the root cause without knowing which modules are being used and what your configuration looks like, so **it helps us immensely if you can link to a simple example that reproduces your issue**. +Issues can be reported in the [issue tracker](https://github.com/feathersjs/feathers/issues). Since feathers combines many modules it can be hard for us to assess the root cause without knowing which modules are being used and what your configuration looks like, so **it helps us immensely if you can link to a simple example that reproduces your issue**. ## Report a Security Concern We take security very seriously at Feathers. We welcome any peer review of our 100% open source code to ensure nobody's Feathers app is ever compromised or hacked. As a web application developer you are responsible for any security breaches. We do our very best to make sure Feathers is as secure as possible by default. -In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Slack](http://slack.feathersjs.com) or email us at hello@feathersjs.com with details and we will respond ASAP. +In order to give the community time to respond and upgrade we strongly urge you report all security issues to us. Send one of the core team members a PM in [Discord](https://discord.gg/qa8kez8QBx) or email us at hello@feathersjs.com with details and we will respond ASAP. For full details refer to our [Security docs](https://docs.feathersjs.com/SECURITY.html). ## Pull Requests -We :heart: pull requests and we're continually working to make it as easy as possible for people to contribute, including a [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) and a [common test suite](https://github.com/feathersjs/feathers-service-tests) for database adapters. +We :heart: pull requests and we're continually working to make it as easy as possible for people to contribute. -We prefer small pull requests with minimal code changes. The smaller they are the easier they are to review and merge. A core team member will pick up your PR and review it as soon as they can. They may ask for changes or reject your pull request. This is not a reflection of you as an engineer or a person. Please accept feedback graciously as we will also try to be sensitive when providing it. +We prefer small pull requests with minimal code changes. The smaller they are the easier they are to review and merge. A FeathersJS maintainer will pick up your PR and review it as soon as they can. They may ask for changes or reject your pull request. This is not a reflection of you as an engineer or a person. Please accept feedback graciously as we will also try to be sensitive when providing it. -Although we generally accept many PRs they can be rejected for many reasons. We will be as transparent as possible but it may simply be that you do not have the same context or information regarding the roadmap that the core team members have. We value the time you take to put together any contributions so we pledge to always be respectful of that time and will try to be as open as possible so that you don't waste it. :smile: +Although we generally accept many PRs they can be rejected for many reasons. We will be as transparent as possible but it may simply be that you do not have the same context, historical knowledge or information regarding the roadmap that the maintainers have. We value the time you take to put together any contributions so we pledge to always be respectful of that time and will try to be as open as possible so that you don't waste it. :smile: **All PRs (except documentation) should be accompanied with tests and pass the linting rules.** @@ -34,27 +32,19 @@ Although we generally accept many PRs they can be rejected for many reasons. We Before running the tests from the `test/` folder `npm test` will run ESlint. You can check your code changes individually by running `npm run lint`. -### ES6 compilation - -Feathers uses [Babel](https://babeljs.io/) to leverage the latest developments of the JavaScript language. All code and samples are currently written in ES2015. To transpile the code in this repository run - -> npm run compile - -__Note:__ `npm test` will run the compilation automatically before the tests. - ### Tests [Mocha](http://mochajs.org/) tests are located in the `test/` folder and can be run using the `npm run mocha` or `npm test` (with ESLint and code coverage) command. ### Documentation -Feathers documentation is contained in Markdown files in the [feathers-docs](https://github.com/feathersjs/feathers-docs) repository. To change the documentation submit a pull request to that repo, referencing any other PR if applicable, and the docs will be updated with the next release. +Feathers documentation is contained in Markdown files in the [docs folder](https://github.com/feathersjs/feathers) of the main repository. To change the documentation submit a pull request to that repo, referencing any other PR if applicable, and the docs will be updated as soon as it is merged. -## External Modules +## Community Contributions -If you're written something awesome for Feathers, the Feathers ecosystem, or using Feathers please add it to the [showcase](https://docs.feathersjs.com/why/showcase.html). You also might want to check out the [Plugin Generator](https://github.com/feathersjs/generator-feathers-plugin) that can be used to scaffold plugins to be Feathers compliant from the start. +If you've written something awesome about Feathers, for the Feathers ecosystem, or created an app using Feathers please add it to the [awesome-feathersjs](https://github.com/feathersjs-ecosystem/awesome-feathersjs). -If you think it would be a good core module then please contact one of the Feathers core team members in [Slack](http://slack.feathersjs.com) and we can discuss whether it belongs in core and how to get it there. :beers: +If you think your module would be a good core `feathersjs` module or [featherjs-ecosystem](https://github.com/feathersjs-ecosystem) module then please contact one of the Feathers maintainers on [Discord](https://discord.gg/qa8kez8QBx) and we can discuss whether it belongs and how to get it there. :beers: ## Contributor Code of Conduct diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 93cf86b8..e46af5ea 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [18.x, 20.x, 22.5.1] + node-version: [18.x, 20.x, 22.x] steps: - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} @@ -19,9 +19,22 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - name: Use Node.js 20.x + - name: Use Node.js 22.x uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 22.x - run: npm install - - run: npm run compile + - run: npm run build + + are_the_types_wrong: + name: Are The Types Wrong? + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 22.x + uses: actions/setup-node@v4 + with: + node-version: 22.x + - run: npm install + - run: npm run build + - run: npx --yes @arethetypeswrong/cli --pack . --profile esm-only diff --git a/.nvmrc b/.nvmrc index 1efe0ac6..517f3866 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.15.1 +v22.14.0 diff --git a/.nycrc b/.nycrc deleted file mode 100644 index 2e76e8e8..00000000 --- a/.nycrc +++ /dev/null @@ -1,21 +0,0 @@ -{ - "all": true, - "include": [ - "src/**/*.js", - "src/**/*.ts" - ], - "exclude": [ - "coverage/**", - "node_modules/**", - "**/*.d.ts", - "**/*.test.ts" - ], - "sourceMap": true, - "reporter": ["text", "html", "lcov"], - "watermarks": { - "statements": [50, 80], - "lines": [50, 80], - "functions": [50, 80], - "branches": [50, 80] - } -} diff --git a/LICENSE b/LICENSE index b8be257c..9d988b48 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2022 Feathers +Copyright (c) 2025 Feathers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index b97998b9..b079244f 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,76 @@ ## feathers-hooks-common +#### hooks + +- added transformData, transformResult, rm alterItems +- added discardData, discardResult, rm discard + - moved to omitData, omitResult, rm omit + - MaybeArray +- added keepData, keepResult, rm keep + - moved to pickData, pickResult, rm pick + - MaybeArray +- added lowercaseData, lowercaseResult, rm lowercase + - MaybeArray +- added setNowData, setNowResult, rm setNow + +- removed several checks that are handled by typescript +- removed check for `preventChanges(true, ...fieldNames)` + + - switch `true` to second argument options + - async + +- renamed 'keepQuery' to 'pickQuery', added alias +- renamed 'required' to 'checkRequired', added alias + +- removed 'actOn', 'actOnDefault', 'actOnDispatch' + +- added throwIf +- added throwIfIsProvider +- added throwIfIsMulti + +- removed old paramsForServer & changed to hook + +- added 'onDelete' & 'createRelated' + +- stashBefore multi + +- softDelete: added 'transformParams' & added 'key' option + +- disallow: MaybeArray + +- rm support for spread argument + +- rm 'actOnDispatch' & 'actOnDefault' + +- rm 'validate', 'validateSchema', 'setNow', 'sequelizeConvert', 'serialize', 'required', 'runHook', 'populate', 'pick', 'omit', 'mongoKeys', 'lowercase', 'lowerCase', 'keepQuery', 'keepQueryInArray', 'isNot', fgraphql', 'fastJoin', 'discard...', 'dePopulate', 'actOnDefault', 'actOnDispatch', 'sifter' + +- softDelete: need to pass 'deletedQuery' and 'removeData' + +#### predicates + +- renamed 'isNot' to 'not' (added alias for 'isNot') +- added predicate isMulti +- added predicate isPaginated +- added predicate isContext + +#### utils + +- added getDataIsArray, getResultIsArray, deprecated getItems +- added replaceData, replaceResult, deprecated replaceItems +- added util getPaginate +- added util skipResult +- rm 'runHook' + +### Hooks to discuss + +- cache +- populate +- dePopulate +- fgraphql +- fastJoin +- sequelizeConvert +- serialize +

diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 19c3cb4a..d5ecbd97 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,54 +1,87 @@ -import { defineConfig } from "vitepress"; -import { name, description, ogUrl, ogImage } from "./meta"; +import { defineConfig } from 'vitepress' +import { name, description, ogUrl, ogImage, repository, mainBranch } from './meta' import { version } from '../../package.json' +import { resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { discoverUtilities } from './utilities' +import { MarkdownTransform } from './plugins/markdownTransform' +import { transformerTwoslash } from '@shikijs/vitepress-twoslash' +import tailwindcss from '@tailwindcss/vite' + +const __dirname = fileURLToPath(new URL('.', import.meta.url)) + +const utilities = await discoverUtilities() export default defineConfig({ - title: "feathers-hooks-common", + title: name, lastUpdated: true, - description: "", + description: '', head: [ - ["meta", { name: "theme-color", content: "#ae0bb1" }], - ["link", { rel: "icon", href: "/feathers-hooks-common-logo.png" }], - ["meta", { property: "og:title", content: name }], - ["meta", { property: "og:description", content: description }], - ["meta", { property: "og:url", content: ogUrl }], - ["meta", { property: "og:image", content: ogImage }], - ["meta", { name: "twitter:title", content: name }], - ["meta", { name: "twitter:description", content: description }], - ["meta", { name: "twitter:image", content: ogImage }], - ["meta", { name: "twitter:card", content: "summary_large_image" }], + ['meta', { name: 'theme-color', content: '#ae0bb1' }], + ['link', { rel: 'icon', href: '/feathers-hooks-common-logo.png' }], + ['meta', { property: 'og:title', content: name }], + ['meta', { property: 'og:description', content: description }], + ['meta', { property: 'og:url', content: ogUrl }], + ['meta', { property: 'og:image', content: ogImage }], + ['meta', { name: 'twitter:title', content: name }], + ['meta', { name: 'twitter:description', content: description }], + ['meta', { name: 'twitter:image', content: ogImage }], + ['meta', { name: 'twitter:card', content: 'summary_large_image' }], ], themeConfig: { - siteTitle: "feathers-hooks-common", + siteTitle: name, editLink: { - pattern: - "https://github.com/feathersjs-ecosystem/feathers-hooks-common/edit/master/docs/:path", + pattern: `https://github.com/${repository}/edit/${mainBranch}/docs/:path`, }, - lastUpdatedText: "Last Updated", + lastUpdatedText: 'Last Updated', socialLinks: [ { - icon: "twitter", - link: "https://twitter.com/feathersjs", - }, - { - icon: "discord", - link: "https://discord.gg/qa8kez8QBx", + icon: 'discord', + link: 'https://discord.gg/qa8kez8QBx', }, { - icon: "github", - link: "https://github.com/feathersjs-ecosystem/feathers-hooks-common", + icon: 'github', + link: `https://github.com/${repository}`, }, ], - logo: "/feathers-hooks-common-logo.png", + logo: '/feathers-hooks-common-logo.png', sidebar: [ { - text: "Guide", + text: 'Guide', items: [ - { text: "Overview", link: "/overview" }, - { text: "Hooks", link: "/hooks" }, - { text: "Utilities", link: "/utilities" }, - { text: "Migrating", link: "/migrating" }, - { text: "Guides", link: "/guides" }, + { text: 'Overview', link: '/overview' }, + { + text: 'Hooks', + link: '/hooks', + items: utilities + .filter(x => x.category === 'hooks') + .map(x => ({ + text: x.title, + link: x.path, + })), + }, + { + text: 'Utilities', + link: '/utils', + items: utilities + .filter(x => x.category === 'utils') + .map(x => ({ + text: x.title, + link: x.path, + })), + }, + { + text: 'Predicates', + link: '/predicates', + items: utilities + .filter(x => x.category === 'predicates') + .map(x => ({ + text: x.title, + link: x.path, + })), + }, + { text: 'Migrating', link: '/migrating' }, + { text: 'Guides', link: '/guides' }, ], }, ], @@ -58,23 +91,55 @@ export default defineConfig({ items: [ { text: 'Changelog', - link: 'https://github.com/feathersjs-ecosystem/feathers-hooks-common/blob/master/CHANGELOG.md' + link: `https://github.com/${repository}/blob/${mainBranch}/CHANGELOG.md`, }, { text: 'Contributing', - link: 'https://github.com/feathersjs-ecosystem/feathers-hooks-common/blob/master/.github/contributing.md' - } - ] - } + link: `https://github.com/${repository}/blob/${mainBranch}/.github/contributing.md`, + }, + ], + }, ], footer: { - message: "Released under the MIT License.", - copyright: "Copyright © 2016-present Feathers contributors", + message: 'Released under the MIT License.', + copyright: 'Copyright © 2016-present Feathers contributors', }, algolia: { appId: '4GNLWKU0RF', apiKey: '8114a3bec3c82b65c26a4ed113659bce', - indexName: 'feathers-hooks' - } + indexName: 'feathers-hooks', + }, + }, + markdown: { + codeTransformers: [ + transformerTwoslash({ + twoslashOptions: { + compilerOptions: { + paths: { + 'feathers-commons': [resolve(__dirname, '../../src/index.ts')], + 'feathers-commons/hooks': [resolve(__dirname, '../../src/hooks/index.ts')], + 'feathers-commons/utils': [resolve(__dirname, '../../src/utils/index.ts')], + 'feathers-commons/predicates': [resolve(__dirname, '../../src/predicates/index.ts')], + 'feathers-commons/resolvers': [resolve(__dirname, '../../src/resolvers/index.ts')], + }, + }, + }, + }), + ], + // Explicitly load these languages for types hightlighting + languages: ['js', 'ts'], + }, + vite: { + server: { + fs: { + allow: [resolve(__dirname, '../../src')], + }, + }, + plugins: [ + MarkdownTransform({ + vitepressDirectory: resolve(__dirname, '../'), + }), + tailwindcss(), + ], }, -}); +}) diff --git a/docs/.vitepress/meta.ts b/docs/.vitepress/meta.ts index c7b4ba02..a7ddeb8d 100644 --- a/docs/.vitepress/meta.ts +++ b/docs/.vitepress/meta.ts @@ -1,5 +1,8 @@ -export const name = "feathers-hooks-common"; -export const description = "Common hooks and utils for FeathersJS apps"; +export const name = 'feathers-commons' +export const description = 'Common hooks and utils for FeathersJS apps' -export const ogUrl = "https://hooks-common.feathersjs.com/"; -export const ogImage = "https://hooks-common.feathersjs.com/feathers-hooks-common-logo.png"; +export const repository = 'feathersjs-ecosystem/feathers-hooks-common' +export const mainBranch = 'master' + +export const ogUrl = 'https://hooks-common.feathersjs.com/' +export const ogImage = 'https://hooks-common.feathersjs.com/feathers-hooks-common-logo.png' diff --git a/docs/.vitepress/plugins/markdownTransform.ts b/docs/.vitepress/plugins/markdownTransform.ts new file mode 100644 index 00000000..f2ede496 --- /dev/null +++ b/docs/.vitepress/plugins/markdownTransform.ts @@ -0,0 +1,83 @@ +import type { Plugin } from 'vite' + +import { discoverUtilities, type Utility } from '../utilities' +import md from './utility' + +export type MarkdownTransformOptions = { + srcDir?: string + pattern?: string + exclude?: string[] + vitepressDirectory: string +} + +export function MarkdownTransform(options: MarkdownTransformOptions): Plugin { + const { + srcDir = '../../src', + pattern = '**/*.md', + exclude = ['**/node_modules/**', '**/dist/**'], + vitepressDirectory, + } = options ?? {} + + let utilitiesList: Utility[] = [] + + return { + name: 'feathers-commons-md-transform', + enforce: 'pre', + async buildStart() { + const result = await discoverUtilities() + utilitiesList = result + }, + async transform(code, id) { + if (!id.match(/\.md\b/)) return null + + const slug = id.replace(vitepressDirectory, '') + + const utility = utilitiesList.find(x => x.pathMd === slug) + if (!utility) { + return null + } + + return md(utility) + }, + // configureServer(server) { + // const watcher = server.watcher + + // watcher.add(`${srcDir}/**/*.md`) + + // watcher.on('change', async filePath => { + // console.log(`🔄 Utility changed: ${filePath}`) + // if (filePath.includes(srcDir) && filePath.endsWith('.md')) { + // console.log(`📝 Utility changed: ${filePath}`) + // await discoverUtilities(options) + + // // Invalidate virtual modules + // const moduleGraph = server.moduleGraph + // const virtualModules = Array.from(moduleGraph.urlToModuleMap.keys()).filter( + // url => url.startsWith(VIRTUAL_UTILITY_PREFIX) || url === VIRTUAL_UTILITIES_LIST, + // ) + + // virtualModules.forEach(url => { + // const module = moduleGraph.getModuleById(url) + // if (module) { + // server.reloadModule(module) + // } + // }) + // } + // }) + + // watcher.on('add', async filePath => { + // if (filePath.includes(srcDir) && filePath.endsWith('.md')) { + // console.log(`➕ New utility: ${filePath}`) + // await discoverUtilities(options) + // } + // }) + + // watcher.on('unlink', async filePath => { + // if (filePath.includes(srcDir) && filePath.endsWith('.md')) { + // console.log(`➖ Utility removed: ${filePath}`) + // await discoverUtilities(options) + // } + // }) + // }, + } +} diff --git a/docs/.vitepress/plugins/utility.ts b/docs/.vitepress/plugins/utility.ts new file mode 100644 index 00000000..7a91f4cc --- /dev/null +++ b/docs/.vitepress/plugins/utility.ts @@ -0,0 +1,39 @@ +import type { Utility } from '../utilities' +import dedent from 'dedent' + +const arr = (value: any[]) => { + if (!value || !value.length) return '[]' + const val = value + .map(x => { + if (typeof x === 'string') return `'${x}'` + if (typeof x === 'number') return x.toString() + return JSON.stringify(x) + }) + .join(', ') + + return `[${val}]` +} + +export default (utility: Utility) => { + const code = [ + dedent`# ${utility.title} + + [Source Code](${utility.sourceUrl}) + + ${utility.description} + + \`\`\`ts twoslash + import { ${utility.name} } from 'feathers-commons/${utility.category}'; + \`\`\` `, + ] + + if (utility.hook) { + code.push(dedent` + + `) + } + + code.push(utility.content) + + return code.join('\n\n') +} diff --git a/docs/.vitepress/style/main.css b/docs/.vitepress/style/main.css index b1f5af0f..501543f0 100644 --- a/docs/.vitepress/style/main.css +++ b/docs/.vitepress/style/main.css @@ -1,3 +1,5 @@ +@import "tailwindcss"; + /** * Colors * -------------------------------------------------------------------------- */ diff --git a/docs/.vitepress/theme/components/HookTable.vue b/docs/.vitepress/theme/components/HookTable.vue new file mode 100644 index 00000000..11792f8c --- /dev/null +++ b/docs/.vitepress/theme/components/HookTable.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 5b9ffcab..633262dd 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,6 +1,16 @@ -import Theme from 'vitepress/theme' +import DefaultTheme from 'vitepress/theme' +import TwoslashFloatingVue from '@shikijs/vitepress-twoslash/client' + +import type { Theme } from 'vitepress' +import HookTable from './components/HookTable.vue' + import '../style/main.css' +import '@shikijs/vitepress-twoslash/style.css' export default { - ...Theme, -} + extends: DefaultTheme, + enhanceApp({ app }) { + app.use(TwoslashFloatingVue) + app.component('HookTable', HookTable) + }, +} satisfies Theme diff --git a/docs/.vitepress/utilities.ts b/docs/.vitepress/utilities.ts new file mode 100644 index 00000000..0f564a67 --- /dev/null +++ b/docs/.vitepress/utilities.ts @@ -0,0 +1,76 @@ +import fs from 'node:fs/promises' +import matter from 'gray-matter' +import { glob } from 'glob' +import kebabCase from 'lodash/kebabCase.js' +import { mainBranch, repository } from './meta' + +export type Utility = { + name: string + title: string + description: string + category: 'hooks' | 'utils' | 'resolvers' | 'predicates' + slug: string + path: string + pathMd: string + frontmatter: Record + content: string + lastModified: Date + sourceUrl: string + hook?: Record +} + +const utilities = new Map() +let utilitiesList: Utility[] = [] + +export async function discoverUtilities() { + const { srcDir = 'src', pattern = '**/*.md', exclude = ['**/node_modules/**', '**/dist/**'] } = {} + + const markdownFiles = await glob(`${srcDir}/${pattern}`, { ignore: exclude }) + utilities.clear() + utilitiesList = [] + + for (const filePath of markdownFiles) { + try { + const content = await fs.readFile(filePath, 'utf-8') + const { data: frontmatter, content: body } = matter(content) + + const { title = '', description = '', category, hook } = frontmatter + + if (!title || ['hooks', 'utils', 'resolvers', 'predicates'].indexOf(category) === -1) { + console.warn( + `Skipping ${filePath}: Missing title or invalid category`, + title, + category, + frontmatter, + ) + continue + } + + const slug = kebabCase(title) + + const utility: Utility = { + name: title, + title, + description, + category, + slug, + path: `/${category}/${slug}`, + pathMd: `/${category}/${slug}.md`, + frontmatter, + content: body, + hook, + lastModified: (await fs.stat(filePath)).mtime, + sourceUrl: `https://github.com/${repository}/blob/${mainBranch}/src/${category}/${slug}/${slug}.ts`, + } + + utilities.set(slug, utility) + utilitiesList.push(utility) + } catch (error) { + console.warn(`Failed to process ${filePath}:`, error.message) + } + } + + utilitiesList.sort((a, b) => a.title.localeCompare(b.title)) + + return utilitiesList +} diff --git a/docs/components/HookTable.vue b/docs/components/HookTable.vue deleted file mode 100644 index 5361db48..00000000 --- a/docs/components/HookTable.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - - - diff --git a/docs/guides.md b/docs/guides.md index d9b6527c..926637a7 100755 --- a/docs/guides.md +++ b/docs/guides.md @@ -9,11 +9,7 @@ function disallowWhat() { return someVariableCircumstance() ? 'rest' : 'external'; } // ... -module.exports = { - before: { - all: disallow(disallowWhat()) - } -}; +module.exports = { before: { all: disallow(disallowWhat()) } }; ``` This code will also **not do**, as most parameters do not permit functions, and `disallowWhat` will not be called for each service call. @@ -23,11 +19,7 @@ function disallowWhat() { return someVariableCircumstance() ? 'rest' : 'external'; } // ... -module.exports = { - before: { - all: disallow(disallowWhat) - } -}; +module.exports = { before: { all: disallow(disallowWhat) } }; ``` You are able to call `disallowWhat` for each service call as follows. @@ -37,11 +29,7 @@ function disallowWhat() { return someVariableCircumstance() ? 'rest' : 'external'; } // ... -module.exports = { - before: { - all: context => disallow(disallowWhat())(context) - } -}; +module.exports = { before: { all: context => disallow(disallowWhat())(context) } }; ``` `disallowWhat` is called each time the hook is run. `disallow(disallowWhat())` creates a new hook with the value returned by `disallowWhat()`, and then that hook is invoked with `(context)`. @@ -49,11 +37,7 @@ module.exports = { Let's look at another example. The `user` record identifies information the user permits to be public, in its `public` field. We can write a hook retaining only the fields allowed to be exposed. ```js -module.exports = { - after: { - get: context => keep(...context.params.user.public)(context) - } -}; +module.exports = { after: { get: context => keep(...context.params.user.public)(context) } }; ``` ## fastJoin @@ -101,40 +85,27 @@ It also takes an optional query with which you can customise the current operati ```js // project/src/services/posts/posts.hooks.js -const { fastJoin } = require('feathers-hooks-common'); +const { fastJoin } = require('feathers-hooks-common/index.js'); const postResolvers = { joins: { author: (...args) => async (post, { app }) => { - post.author = ( - await app.service('users').find({ - query: { - id: post.userId - } - }) - )[0]; + post.author = (await app.service('users').find({ query: { id: post.userId } }))[0]; }, starers: $select => async (post, { app }) => { - post.starers = await app.service('users').find({ - query: { - id: { $in: post.starIds }, - $select: $select || ['name'] - } - }); - } - } + post.starers = await app + .service('users') + .find({ query: { id: { $in: post.starIds }, $select: $select || ['name'] } }); + }, + }, }; -module.exports = { - after: { - all: [fastJoin(postResolvers)] - } -}; +module.exports = { after: { all: [fastJoin(postResolvers)] } }; ``` The above example has two resolvers. Let's focus on `author`. @@ -161,7 +132,7 @@ The result would look like: userId: 101, starIds: [102, 103, 104], author: { id: 101, name: 'John' }, - starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }] + starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }], } ]; ``` @@ -169,15 +140,9 @@ The result would look like: ### Shaping the Result ```js -const query = { - author: true -}; +const query = { author: true }; -module.exports = { - after: { - all: [fastJoin(postResolvers, query)] - } -}; +module.exports = { after: { all: [fastJoin(postResolvers, query)] } }; ``` The above query requests the author resolver be run, but not the starers resolver. This is a GraphQL concept which _shapes_ the result. The result will not contain the `starers` field which the starers resolver would have otherwise added. @@ -192,8 +157,8 @@ The above query requests the author resolver be run, but not the starers resolve body: 'John post', userId: 101, starIds: [102, 103, 104], - author: { id: 101, name: 'John' } - } + author: { id: 101, name: 'John' }, + }, ]; ``` @@ -241,9 +206,9 @@ The `paginate:false` suppress pagination for this call, ensuring all the matchin starers: [ { id: 102, name: 'Marshall' }, { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' } - ] - } + { id: 104, name: 'Aubree' }, + ], + }, ]; ``` @@ -272,8 +237,8 @@ Here, the starerCount resolver adds the field `starerCount` containing a count o starIds: [102, 103, 104], starerCount: 3, author: { id: 101, name: 'John' }, - starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }] - } + starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }], + }, ]; ``` @@ -348,23 +313,23 @@ const query = { text: 'John post Marshall comment 11', postId: 1, userId: 102, - author: { id: 102, name: 'Marshall' } + author: { id: 102, name: 'Marshall' }, }, { id: 12, text: 'John post Marshall comment 12', postId: 1, userId: 102, - author: { id: 102, name: 'Marshall' } + author: { id: 102, name: 'Marshall' }, }, { id: 13, text: 'John post Marshall comment 13', postId: 1, userId: 102, - author: { id: 102, name: 'Marshall' } - } - ] + author: { id: 102, name: 'Marshall' }, + }, + ], } ]; ``` @@ -382,11 +347,11 @@ const commentResolvers = { comment.author = ( await users.find({ query: { id: comment.userId, $select: $select || ['name'] }, - paginate: false + paginate: false, }) )[0]; - } - } + }, + }, }; const postResolvers = { @@ -398,16 +363,16 @@ const postResolvers = { postId: post.id, $select: $select, $limit: $limit || 5, - [$sort]: { createdAt: -1 } + [$sort]: { createdAt: -1 }, }, - paginate: false + paginate: false, }); return post.comments; }, - joins: commentResolvers - } - } + joins: commentResolvers, + }, + }, }; ``` @@ -424,16 +389,14 @@ You need to understand batch-loaders before we proceed, so [read about them now. ### Using a Simple Batch-Loader ```js -const { fastJoin } = require('feathers-hooks-common'); +const { fastJoin } = require('feathers-hooks-common/index.js'); const BatchLoader = require('@feathers-plus/batch-loader'); const { loaderFactory } = BatchLoader; const postResolvers = { before: context => { context._loaders = { user: {} }; - context._loaders.user.id = loaderFactory(users, 'id', false, { - paginate: false - })(context); + context._loaders.user.id = loaderFactory(users, 'id', false, { paginate: false })(context); }, joins: { @@ -441,8 +404,8 @@ const postResolvers = { (post.author = await context._loaders.user.id.load(post.userId)), starers: () => async (post, context) => - !post.starIds ? null : (post.starers = await context._loaders.user.id.loadMany(post.starIds)) - } + !post.starIds ? null : (post.starers = await context._loaders.user.id.loadMany(post.starIds)), + }, }; ``` @@ -471,8 +434,8 @@ Let's look at the code in this example: starers: [ { id: 102, name: 'Marshall' }, { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' } - ] + { id: 104, name: 'Aubree' }, + ], } ]; ``` @@ -484,7 +447,7 @@ Let's look at the code in this example: The `loaderFactory(users, 'id', false)` above is just a convenience wrapper for building a BatchLoader. We can create our batch loaders directly should we need them to do more. ```js -const { fastJoin, makeCallingParams } = require('feathers-hooks-common'); +const { fastJoin, makeCallingParams } = require('feathers-hooks-common/index.js'); const BatchLoader = require('@feathers-plus/batch-loader'); const { getResultsByKey, getUniqueKeys } = BatchLoader; @@ -496,12 +459,12 @@ const postResolvers = { async (keys, context) => { const result = await users.find( makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }, undefined, { - paginate: false - }) + paginate: false, + }), ); return getResultsByKey(keys, result, user => user.id, '!'); }, - { context } + { context }, ); }, @@ -510,8 +473,8 @@ const postResolvers = { (post.author = await context._loaders.user.id.load(post.userId)), starers: () => async (post, context) => - !post.starIds ? null : (post.starers = await context._loaders.user.id.loadMany(post.starIds)) - } + !post.starIds ? null : (post.starers = await context._loaders.user.id.loadMany(post.starIds)), + }, }; ``` @@ -525,7 +488,7 @@ Let's also add a `reputation` array of objects to `posts`. This will show the in ```js // project/src/services/posts/posts.hooks.js -const { fastJoin, makeCallingParams } = require('feathers-hooks-common'); +const { fastJoin, makeCallingParams } = require('feathers-hooks-common/index.js'); const BatchLoader = require('@feathers-plus/batch-loader'); const { getResultsByKey, getUniqueKeys } = BatchLoader; @@ -534,8 +497,8 @@ const commentResolvers = { author: () => async (comment, context) => !comment.userId ? null - : (comment.userRecord = await context._loaders.user.id.load(comment.userId)) - } + : (comment.userRecord = await context._loaders.user.id.load(comment.userId)), + }, }; const postResolvers = { @@ -546,24 +509,24 @@ const postResolvers = { async (keys, context) => { const result = await users.find( makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }, undefined, { - paginate: false - }) + paginate: false, + }), ); return getResultsByKey(keys, result, user => user.id, '!'); }, - { context } + { context }, ); context._loaders.comments.postId = new BatchLoader( async (keys, context) => { const result = await comments.find( makeCallingParams(context, { postId: { $in: getUniqueKeys(keys) } }, undefined, { - paginate: false - }) + paginate: false, + }), ); return getResultsByKey(keys, result, comment => comment.postId, '[!]'); }, - { context } + { context }, ); }, @@ -579,7 +542,7 @@ const postResolvers = { reputation_author: () => async (post, context) => { if (!post.reputation) return null; const authors = await context._loaders.user.id.loadMany( - post.reputation.map(rep => rep.userId) + post.reputation.map(rep => rep.userId), ); post.reputation.forEach((rep, i) => { rep.author = authors[i].name; @@ -591,25 +554,18 @@ const postResolvers = { (...args) => async (post, context) => (post.commentRecords = await context._loaders.comments.postId.load(post.id)), - joins: commentResolvers - } - } + joins: commentResolvers, + }, + }, }; const query = { author: true, starers: [['id', 'name']], - comments: { - args: null, - author: [['id', 'name']] - } + comments: { args: null, author: [['id', 'name']] }, }; -module.exports = { - after: { - all: [fastJoin(postResolvers, context => query)] - } -}; +module.exports = { after: { all: [fastJoin(postResolvers, context => query)] } }; ``` We are using 2 batch-loaders, one for single user records, the other for arrays of comment records. @@ -721,7 +677,7 @@ We can improve the situation by using persistent caches with the BatchLoaders. A Let's see how we can use the [cache hook](./index.html#cache) as it maintains a persistent cache for the service its registered on. ```js -const { cache, fastJoin, makeCallingParams } = require('feathers-hooks-common'); +const { cache, fastJoin, makeCallingParams } = require('feathers-hooks-common/index.js'); const BatchLoader = require('@feathers-plus/batch-loader'); const CacheMap = require('@feathers-plus/cache'); const { getResultsByKey, getUniqueKeys } = BatchLoader; @@ -733,13 +689,11 @@ const cacheMapUsers = CacheMap({ max: 100 }); const userBatchLoader = new BatchLoader( async keys => { const result = await users.find( - makeCallingParams({}, { id: { $in: getUniqueKeys(keys) } }, undefined, { - paginate: false - }) + makeCallingParams({}, { id: { $in: getUniqueKeys(keys) } }, undefined, { paginate: false }), ); return getResultsByKey(keys, result, user => user.id, '!'); }, - { cacheMap: cacheMapUsers } + { cacheMap: cacheMapUsers }, ); const postResolvers = { @@ -753,26 +707,19 @@ const postResolvers = { (post.author = await context._loaders.user.id.load(post.userId)), starers: () => async (post, context) => - !post.starIds ? null : (post.starers = await context._loaders.user.id.loadMany(post.starIds)) - } + !post.starIds ? null : (post.starers = await context._loaders.user.id.loadMany(post.starIds)), + }, }; const query = { author: true, starers: [['id', 'name']], - comments: { - args: null, - author: [['id', 'name']] - } + comments: { args: null, author: [['id', 'name']] }, }; module.exports = { - before: { - all: cache(cacheMapUsers) - }, - after: { - all: [cache(cacheMapUsers), fastJoin(postResolvers, () => query)] - } + before: { all: cache(cacheMapUsers) }, + after: { all: [cache(cacheMapUsers), fastJoin(postResolvers, () => query)] }, }; ``` @@ -807,22 +754,13 @@ Populates items _recursively_ to any depth. Supports 1:1, 1:n and n:1 relationsh ```javascript // users like { _id: '111', name: 'John', roleId: '555' } // roles like { _id: '555', permissions: ['foo', bar'] } -import { populate } from 'feathers-hooks-common'; +import { populate } from 'feathers-hooks-common/index.js'; const userRoleSchema = { - include: { - service: 'roles', - nameAs: 'role', - parentField: 'roleId', - childField: '_id' - } + include: { service: 'roles', nameAs: 'role', parentField: 'roleId', childField: '_id' }, }; -app.service('users').hooks({ - after: { - all: populate({ schema: userRoleSchema }) - } -}); +app.service('users').hooks({ after: { all: populate({ schema: userRoleSchema }) } }); // result like // { _id: '111', name: 'John', roleId: '555', @@ -835,19 +773,10 @@ app.service('users').hooks({ // users like { _id: '111', name: 'John', roleIds: ['555', '666'] } // roles like { _id: '555', permissions: ['foo', 'bar'] } const userRolesSchema = { - include: { - service: 'roles', - nameAs: 'roles', - parentField: 'roleIds', - childField: '_id' - } + include: { service: 'roles', nameAs: 'roles', parentField: 'roleIds', childField: '_id' }, }; -usersService.hooks({ - after: { - all: populate({ schema: userRolesSchema }) - } -}); +usersService.hooks({ after: { all: populate({ schema: userRolesSchema }) } }); // result like // { _id: '111', name: 'John', roleIds: ['555', '666'], roles: [ @@ -862,19 +791,10 @@ usersService.hooks({ // posts like { _id: '111', body: '...' } // comments like { _id: '555', text: '...', postId: '111' } const postCommentsSchema = { - include: { - service: 'comments', - nameAs: 'comments', - parentField: '_id', - childField: 'postId' - } + include: { service: 'comments', nameAs: 'comments', parentField: '_id', childField: 'postId' }, }; -postService.hooks({ - after: { - all: populate({ schema: postCommentsSchema }) - } -}); +postService.hooks({ after: { all: populate({ schema: postCommentsSchema }) } }); // result like // { _id: '111', body: '...' }, comments: [ @@ -934,15 +854,11 @@ const postCommentsSchema = { include: { service: 'comments', nameAs: 'comments', - select: (hook, parentItem) => ({ postId: parentItem._id }) - } + select: (hook, parentItem) => ({ postId: parentItem._id }), + }, }; -postService.hooks({ - after: { - all: populate({ schema: postCommentsSchema }) - } -}); +postService.hooks({ after: { all: populate({ schema: postCommentsSchema }) } }); // result like // { _id: '111', body: '...' }, comments: [ @@ -1109,7 +1025,7 @@ The following example shows how the client can ask for the type of schema it nee ```javascript // on client -import { paramsForServer } from 'feathers-hooks-common'; +import { paramsForServer } from 'feathers-hooks-common/index.js'; purchaseOrders.get(id, paramsForServer({ schema: 'po-acct' })); // pass schema name to server // or purchaseOrders.get(id, paramsForServer({ schema: 'po-rec' })); @@ -1117,7 +1033,7 @@ purchaseOrders.get(id, paramsForServer({ schema: 'po-rec' })); ```javascript // on server -import { paramsFromClient } from 'feathers-hooks-common'; +import { paramsFromClient } from 'feathers-hooks-common/index.js'; const poSchemas = { 'po-acct': /* populate schema for Accounting oriented PO e.g. { include: ... } */, 'po-rec': /* populate schema for Receiving oriented PO */ @@ -1181,7 +1097,7 @@ A full featured example of such a process appears below. It validates and saniti ```javascript // file /server/services/users/users.hooks.js const auth = require('feathers-authentication').hooks; -const { callbackToPromise, remove, validate } = require('feathers-hooks-common'); +const { callbackToPromise, remove, validate } = require('feathers-hooks-common/index.js'); const validateSchema = require('feathers-hooks-validate-joi'); const clientValidations = require('/common/usersClientValidations'); @@ -1197,8 +1113,8 @@ exports.before = { validate(values => clientValidations.signupAsync(values, 'someMoreParams')), // re-run form async validate(serverValidationsSignup), // run server validation remove('confirmPassword'), - auth.hashPassword() - ] + auth.hashPassword(), + ], }; ``` @@ -1263,19 +1179,14 @@ const password = Joi.string() const email = Joi.string().trim().email().required(); module.exports = { - options: { - abortEarly: false, - convert: true, - allowUnknown: false, - stripUnknown: true - }, + options: { abortEarly: false, convert: true, allowUnknown: false, stripUnknown: true }, signup: Joi.object().keys({ name: Joi.string().trim().min(8).max(30).required(), username, password, confirmPassword: password.label('Confirm password'), - email - }) + email, + }), }; ``` @@ -1294,7 +1205,7 @@ module.exports = { }); cb(Object.keys(formErrors).length > 0 ? formErrors : null, sanitized); - } + }, }; ``` diff --git a/docs/hooks.md b/docs/hooks.md deleted file mode 100644 index b6f34ffe..00000000 --- a/docs/hooks.md +++ /dev/null @@ -1,2157 +0,0 @@ - - -# Hooks - -## actOnDefault - -Runs a series of hooks which mutate context.data or content.result (the Feathers default). - - - -- **Arguments** - - - `{...Function}` Hook functions. - -| Argument | Type | Default | Description | -| -------- | :-----------: | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| `hooks` | `...Function` | | The hooks to run. They will mutate `context.data` for before hooks, or `context.result` for after hooks. This is the default action for hooks. | - -- **Example** - - ```js - const { actOnDefault, actOnDispatch } = require('feathers-hooks-common'); - - module.exports = { - after: { - find: [hook1(), actOnDispatch(hook2(), actOnDefault(hook3()), hook4()), hook5()] - } - }; - ``` - - Hooks `hook1`, `hook3` and `hook5` will run "normally", mutating `content.result`. - Hooks `hook2` and `hook4` will mutate `context.dispatch`. - -- **Details** - - A hook can call a series of hooks using `actOnDispatch`. Some of those hooks may call other hooks with `actOnDefault` or `actOnDispatch`. This can "turtle down" to further layers. - - The main purpose of `actOnDefault` is to "undo" `actOnDispatch`. - -## actOnDispatch - -Runs a series of hooks which mutate context.dispatch. - - - -- **Arguments** - - - `{...Function}` Hook functions. - -| Argument | Type | Default | Description | -| -------- | :-----------: | ------- | ------------------------------------------------------ | -| `hooks` | `...Function` | | The hooks to run. They will mutate `context.dispatch`. | - -- **Example** - - ```js - const { actOnDefault, actOnDispatch } = require('feathers-hooks-common'); - - module.exports = { - after: { - find: [hook1(), actOnDispatch(hook2(), actOnDefault(hook3()), hook4()), hook5()] - } - }; - ``` - - Hooks `hook1`, `hook3` and `hook5` will run "normally", mutating `content.result`. - Hooks `hook2` and `hook4` will mutate `context.dispatch`. - -- **Details** - - A hook can call a series of hooks using `actOnDispatch`. Some of those hooks may call other hooks with `actOnDefault` or `actOnDispatch`. This can "turtle down" to further layers. - -

context.dispatch is a writeable, optional property and contains a "safe" version of the data that should be sent to any client. If context.dispatch has not been set context.result will be sent to the client instead.

Note: context.dispatch only affects the data sent through a Feathers Transport like REST or Socket.io. An internal method call will still get the data set in context.result.

- -## alterItems - -Make changes to data or result items. Very flexible. - - - -- **Arguments** - - `{Function} func` - -| Argument | Type | Default | Description | -| -------- | :--------: | --------------------------- | --------------------------------------------- | -| `func` | `Function` | `(item,` `context) =>` `{}` | Function modifies `item` in place. See below. | - -- **returns** - -The mutated `item`. Returning `undefined` means the `item` in the parameters was mutated in place. returns result `undefined || item` - -- **Example** - - ```js - const { alterItems } = require('feathers-hooks-common'); - - module.exports = { before: { - all: [ - alterItems(rec => { delete rec.password; }) // Like `discard('password')`. - alterItems(rec => rec.email = email.lowerCase()), // Like `lowerCase('email')`. - ], - } }; - ``` - - Async mutations can be handled with async/await: - - ```js - alterItems(rec => { - rec.userRecord = (async () => await service.get(...) )() - }) - ``` - - You can also perform async mutations using Promises by returning a Promise that is resolved once all mutations are complete: - - ```js - alterItems(rec => new Promise(resolve => { - service.get(...).then(result => { - rec.userRecord = result; - resolve(); - }}); - ``` - - You can also perform async mutations using Promises by returning a Promise that is resolved once all mutations are complete: - - ```js - alterItems(async rec => { - rec.userRecord = await service.get(...); - }) - ``` - -- **Details** - - The declarative nature of most of the common hooks, e.g. `discard('password')`, requires you to remember the names of a fair number of hooks, their parameters, and any possible nuances. - - The `alterItems` hook offers an imperative alternative where you directly alter the items. It allows you to reduce the number of trivial hooks you have to register, and you are aware of exactly what your `alterItems` hooks do. - - `func` is called for each item in `context.data` (before hook) or `context.result[.data]` (after hook). It receives the parameters - - - `{Object} item` - - `{Object} context` - - | Argument | Type | Description | - | --------- | :------: | ---------------------------------------------------------------------- | - | `item` | `Object` | The item. The function modifies it in place. | - | `context` | `Object` | The current context. It contains any alterations made to items so far. | - -- **Returns** - - `func` may alternatively return a replacement `item` rather than `undefined`. This is a convenience feature which permits, for example, use of functions from the [Lodash](https://lodash.com/) library, as such functions tend to return new objects. - -## cache - -Persistent, least-recently-used record cache for services. - - - -- **Arguments** - - - `{Object | Map} cacheMap` - - `{String} [ keyField ]` - - `{Object} [ options ]` - - `{Function} [ clone ]` - - `{Function} [makeCacheKey]` - -| Argument | Type | Default | Description | -| ---------- | :------------: | -------------------------------------------------- | ---------------------------------------------------------------------------- | -| `cacheMap` | `Object` `Map` | | Instance of `Map`, or an object with a similar API, to be used as the cache. | -| `keyField` | `String` | `context.service.id` or `item._id ? '_id' !! 'id'` | The name of the record id field. | -| `option` | `Object` | | Options. | - -| `options` | Argument | Type | Default | Description | -| -------------- | ---------- | :--------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | -| `clone` | `Function` | `item => JSON.parse(` `JSON.stringify(item) )` | Function to perform a deep clone. See below. | -| `makeCacheKey` | `Function` | `key => key` | Function to convert record key to cache key. Use this to convert MongoDB/Mongoose ObjectId/bson keys to a cache key using `item._id.toString()`. | - -- **Example** - - ```js - const CacheMap = require('@feathers-plus/cache'); - const { cache } = require('feathers-hooks-common'); - - const cacheMap = CacheMap({ max: 100 }); // Keep the 100 most recently used. - - module.exports = { - before: { - all: cache(cacheMap) - }, - after: { - all: cache(cacheMap) - } - }; - ``` - - ```js - const { cache } = require('feathers-hooks-common'); - - const cacheMap = new Map(); - - module.exports = { - before: { - all: cache(cacheMap) - }, - after: { - all: cache(cacheMap) - } - }; - ``` - - ```js - const CacheMap = require('@feathers-plus/cache'); - const mongoose = require('mongoose'); - const { cache } = require('feathers-hooks-common'); - - const cacheMap = CacheMap({ max: 100 }); - const makeCacheKey = key => (key instanceof mongoose.Types.ObjectId ? key.toString() : key); - - module.exports = { - before: { - all: cache(cacheMap, undefined, { makeCacheKey }) - }, - after: { - all: cache(cacheMap, undefined, { makeCacheKey }) - } - }; - ``` - - > The `cache` hook **must** be registered in both `before` and `after`. - -

The cache will grow without limit when `Map` is used and the resulting memory pressure may adversely affect your performance. `Map` should only be used when you know or can control its size.

- -- **Details** - - The `cache` hook maintain a persistent cache for the service it is registerd on. A persistent cache stores records so future requests for those records can be served faster; the records stored in the cache are duplicates of records stored in the database. - - The `get` service method retrieves records from the cache and updates `context.result` `[.data]`. The other methods remove their `context.data` entries from the cache in the `before` hook, and add entries in the `after` hook. All the records returned by a `find` call are added to the cache. - - The `cache` hook may be provided a custom Map instance to use as its memoization cache. Any object that implements the methods get(), set(), delete() and clear() can be provided. This allows for custom Maps which implement various [cache algorithms](https://en.wikipedia.org/wiki/Cache_replacement_policies) to be provided. - - The companion `@feathers-plus/cache` provides a least recently-used cache which discards the least recently used items first. It is compatible with `cache` as well as the BatchLoaders used with the `fastJoin` hook. - - > The `cache` hook can make [fastJoin](#fastjoin) hooks run more efficiently. - - MongoDB and Mongoose store record keys as bson objects rather than as scalars. The safest way to use the cache is in conjunction with the `makeCacheKey` option. - -- **options.clone** - - The clone function has a single parameter. - - - `{Object} item` - - It returns - - - `{Object} clonedItem` - -| Argument | Type | Default | Description | -| ------------ | :------: | ------- | ------------------ | -| `item` | `Object` | | The record. | -| `clonedItem` | `Object` | | A clone of `item`. | - -## debug - -Display the current hook context for debugging. - - - -- **Arguments** - - `{String} label` - - `{Array < String >} [ fieldNames ]` - -| Argument | Type | Default | Description | -| ------------ | :----------: | ------- | ------------------------------------------------ | -| `label` | `String` | | Label to identify the logged information. | -| `fieldNames` | dot notation | | The field values in `context.params` to display. | - -- **Example** - - ```js - const { debug } = require('feathers-hooks-common'); - - module.exports = { before: { - all: [ debug('step 1'), setNow('updatedAt'), debug(' step 2') ], - } }; - - // Result - * step 1 - type: before, method: create - data: { name: 'Joe Doe' } - query: { sex: 'm' } - result: { assigned: true } - params props: [ 'query' ] - * step 2 - type: before, method: create - data: { name: 'Joe Doe', createdAt: 1510518511547 } - query: { sex: 'm' } - result: { assigned: true } - params props: [ 'query' ] - params.query: { sex: 'm' } - error: ... - ``` - -- **Details** - - `debug` is great for debugging issues with hooks. Log the hook context before and after a hook to see what the hook started with, and what it changed. - -## dePopulate - -Remove records and properties created by the populate hook. - - - -- **Arguments** - - `{Function} customDepop` - -| Argument | Type | Default | Description | -| ------------- | :--------: | ------------ | -------------------------------------- | -| `customDepop` | `Function` | `rec => rec` | Additional modifications for a record. | - -- **Example** - - ```js - const { dePopulate } = require('feathers-hooks-common'); - - module.exports = { - before: { - all: [depopulate()] - } - }; - ``` - -- **Details** - - Removes joined records, computed properties, and profile information created by [`populate`](#populate). Populated and serialized items may, after dePopulate, be used in service calls. - - Removes fields created by resolver functions using `fgraphql`. Populated items may, after dePopulate, be used in a patch service call. - -## disablePagination - -Disables pagination when query.$limit is -1 or '-1'. - - - -- **Example** - - ```js - const { disablePagination } = require('feathers-hooks-common'); - - module.exports = { - before: { - find: disablePagination() - } - }; - ``` - -- **Details** - - Pagination is disabled if `context.query.$limit` is -1 or '-1'. It works for all types of calls including REST. - -## disallow - -Prevents access to a service method completely or for specific transports. - - - -- **Arguments** - - - `{Array< String >} transports` - -| Argument | Type | Default | Description | -| ------------ | :---------------: | ----------------------- | ----------------------------------------- | -| `transports` | `Array< String >` | disallow all transports | The transports that you want to disallow. | - -| `transports` | Value | Description | -| ------------ | ------------------------------------- | ----------- | -| `socketio` | disallow calls by Socket.IO transport | -| `rest` | disallow calls by REST transport | -| `external` | disallow calls other than from server | -| `server` | disallow calls from server | - -- **Example** - - ```js - const { disallow, iff } = require('feathers-hooks-common'); - - module.exports = { - before: { - // Users can not be created by external access - create: disallow('external'), - // A user can not be deleted through the REST provider - remove: disallow('rest'), - // disallow calling `update` completely (e.g. to allow only `patch`) - update: disallow(), - // disallow the remove hook if the user is not an admin - remove: iff(context => !context.params.user.isAdmin, disallow()) - } - }; - ``` - -- **Details** - - Prevents access to a service method completely or just for specific transports. All transports set the `context.params.provider` property, and `disallow` checks this. - -## discard - -Delete certain fields from the record(s). - - - -> **Note:** The discard hook will remove fields even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), discard(...))`. - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | --------------------------------------------------------- | -| fieldNames | dot notation | One or more fields you want to remove from the record(s). | - -- **Example** - - ```js - const { discard, iff, isProvider } = require('feathers-hooks-common'); - - module.exports = { - after: { - all: iff(isProvider('external'), discard('password', 'address.city')) - } - }; - ``` - -- **Details** - - Delete the fields either from `context.data` (before hook) or `context.result[.data]` (after hook). - They are not modified if they are not an object, so a `null` value is supported. - -## discardQuery - -Delete certain fields from the query object. - - - -> **Note:** The discardQuery hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), discardQuery(...))`. - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | ----------------------------------------------------- | -| fieldNames | dot notation | One or more fields you want to remove from the query. | - -- **Example** - - ```js - const { discardQuery, iff, isProvider } = require('feathers-hooks-common'); - - module.exports = { - after: { - all: iff(isProvider('external'), discardQuery('secret')) - } - }; - ``` - -- **Details** - - Delete the fields from `context.params.query`. - -## fastJoin - -Join related records. - - - -> `fastJoin` is preferred over using `populate`. - -- **Arguments** - - - `{Object | Function} resolvers` - - - `{Function} [ before ]` - - `{Function} [ after ]` - - `{Object} joins` - - - `{Object | Function} [ query ]` - -| Argument | Type | Default | Description | -| ----------- | --------------------------------- | ----------------------------------------- | ----------------------------------------------------------------- | -| `resolvers` | `Object` or `context` `=> Object` | | The group of operations to perform on the data. | -| `query` | `Object` | run all resolvers with `undefined` params | You can customise the current operations with the optional query. | - -| `resolvers` | Argument | Type | Default | Description | -| ----------- | ------------------ | ---- | -------------------------------------------------------------------------------------------------------------------------- | ----------- | -| `before` | `context` `=> { }` | | Processing performed before the operations are started. Batch-loaders are usually created here. | -| `after` | `context` `=> { }` | | Processing performed after all other operations are completed. | -| `joins` | `Object` | | Resolver functions provide a mapping between a portion of a operation and actual backend code responsible for handling it. | - -> Read the [guide](guides.html#fastjoin) for more information on the arguments. - -- **Example using Feathers services** - -

The services in all these examples are assumed, for simplicity, to have pagination disabled. You will have to decide when to use `paginate: false` in your code.

- - ```js - // project/src/services/posts/posts.hooks.js - const { fastJoin } = require('feathers-hooks-common'); - - const postResolvers = { - joins: { - author: - (...args) => - async post => - (post.author = ( - await users.find({ - query: { id: post.userId }, - paginate: false - }) - )[0]), - - starers: $select => async post => - (post.starers = await users.find({ - query: { id: { $in: post.starIds }, $select: $select || ['name'] }, - paginate: false - })) - } - }; - - const query = { - author: true, - starers: [['id', 'name']] - }; - - module.exports = { - after: { - all: [fastJoin(postResolvers, query)] - } - }; - - // Original record - [{ id: 1, body: 'John post', userId: 101, starIds: [102, 103, 104] }][ - // Result - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - author: { id: 101, name: 'John' }, - starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }] - } - ]; - ``` - -- **Example with recursive operations** - - ```js - // project/src/services/posts/posts.hooks.js - const { fastJoin } = require('feathers-hooks-common'); - - const postResolvers = { - joins: { - comments: { - resolver: ($select, $limit, $sort) => async post => post.comments = await comments.find({ - query: { postId: post.id, $select: $select, $limit: $limit || 5, [$sort]: { createdAt: -1 } }, - paginate: false - }), - - joins: { - author: $select => async comment => comment.author = (await users.find({ - query: { id: comment.userId, $select: $select }, - paginate: false - }))[0], - }, - }, - } - }; - - const query = { - comments: { - args: [...], - author: [['id', 'name']] - }, - }; - - module.exports = { after: { - all: [ fastJoin(postResolvers, query) ], - } }; - - // Original record - [ { id: 1, body: 'John post', userId: 101, starIds: [102, 103, 104] } ] - - // Result - [ { id: 1, - body: 'John post', - userId: 101, - starIds: [ 102, 103, 104 ], - comments: - [ { id: 11, - text: 'John post Marshall comment 11', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' } }, - { id: 12, - text: 'John post Marshall comment 12', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' } }, - { id: 13, - text: 'John post Marshall comment 13', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' } } ] - } ] - ``` - -- **Example with a simple batch-loader** - - ```js - // project/src/services/posts/posts.hooks.js - const { fastJoin } = require('feathers-hooks-common'); - const BatchLoader = require('@feathers-plus/batch-loader'); - const { loaderFactory } = BatchLoader; - - const postResolvers = { - before: context => { - context._loaders = { user: {} }; - context._loaders.user.id = loaderFactory(users, 'id', false, { - paginate: false - })(context); - }, - joins: { - author: () => async (post, context) => - (post.author = await context._loaders.user.id.load(post.userId)), - - starers: () => async (post, context) => - !post.starIds - ? null - : (post.starers = await context._loaders.user.id.loadMany(post.starIds)) - } - }; - - module.exports = { - after: { - all: [fastJoin(postResolvers)] - } - }; - - // Original record - [{ id: 1, body: 'John post', userId: 101, starIds: [102, 103, 104] }][ - // Result - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' } - ] - } - ]; - ``` - -- **Comprehensive example** - - ```js - // project/src/services/posts/posts.hooks.js - const { fastJoin, makeCallingParams } = require('feathers-hooks-common'); - const BatchLoader = require('@feathers-plus/batch-loader'); - const { getResultsByKey, getUniqueKeys } = BatchLoader; - - const commentResolvers = { - joins: { - author: () => async (comment, context) => !comment.userId ? null : - comment.userRecord = await context._loaders.user.id.load(comment.userId) - }, - }; - - const postResolvers = { - before: context => { - context._loaders = { user: {}, comments: {} }; - - context._loaders.user.id = new BatchLoader(async (keys, context) => { - const result = await users.find(makeCallingParams( - context, { id: { $in: getUniqueKeys(keys) } }, undefined, { paginate: false } - )); - return getResultsByKey(keys, result, user => user.id, '!'); - }, - { context } - ); - - context._loaders.comments.postId = new BatchLoader(async (keys, context) => { - const result = await comments.find(makeCallingParams( - context, { postId: { $in: getUniqueKeys(keys) } }, undefined, { paginate: false } - )); - return getResultsByKey(keys, result, comment => comment.postId, '[!]'); - }, - { context } - ); - }, - joins: { - author: () => async (post, context) => - post.userRecord = await context._loaders.user.id.load(post.userId), - - starers: () => async (post, context) => !post.starIds ? null : - post.starIdsRecords = await context._loaders.user.id.loadMany(post.starIds), - - comments: { - resolver: (...args) => async (post, context) => - post.commentRecords = await context._loaders.comments.postId.load(post.id), - - joins: commentResolvers, - }, - } - }; - - const query = { - author: true, - starers: [['id', 'name']], - comments: { - args: null, - author: [['id', 'name']] - }, - }; - - module.exports = { after: { - all: [ fastJoin(postResolvers, context => query) ], - } }; - - // Original record - [ { id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ // The `populate` hook cannot handle this structure. - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 } - ]}, - ] - - // Results - [ { id: 1, - body: 'John post', - userId: 101, - starIds: [ 102, 103, 104 ], - reputation: - [ { userId: 102, points: 1, author: 'Marshall' }, - { userId: 103, points: 1, author: 'Barbara' }, - { userId: 104, points: 1, author: 'Aubree' } ], - author: { id: 101, name: 'John' }, - comments: - [ { id: 11, - text: 'John post Marshall comment 11', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' } }, - { id: 12, - text: 'John post Marshall comment 12', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' } }, - { id: 13, - text: 'John post Marshall comment 13', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' } } ], - starers: - [ { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' } ] }, - ] - ``` - -- **Example Using a Persistent Cache** - - ```js - const { cache, fastJoin, makeCallingParams } = require('feathers-hooks-common'); - const BatchLoader = require('@feathers-plus/batch-loader'); - const CacheMap = require('@feathers-plus/cache'); - const { getResultsByKey, getUniqueKeys } = BatchLoader; - - // Create a cache for a maximum of 100 users - const cacheMapUsers = CacheMap({ max: 100 }); - - // Create a batchLoader using the persistent cache - const userBatchLoader = new BatchLoader( - async keys => { - const result = await users.find( - makeCallingParams({}, { id: { $in: getUniqueKeys(keys) } }, undefined, { - paginate: false - }) - ); - return getResultsByKey(keys, result, user => user.id, '!'); - }, - { cacheMap: cacheMapUsers } - ); - - const postResolvers = { - before: context => { - context._loaders = { user: {} }; - context._loaders.user.id = userBatchLoader; - }, - - joins: { - author: () => async (post, context) => - (post.author = await context._loaders.user.id.load(post.userId)), - - starers: () => async (post, context) => - !post.starIds - ? null - : (post.starers = await context._loaders.user.id.loadMany(post.starIds)) - } - }; - - const query = { - author: true, - starers: [['id', 'name']], - comments: { - args: null, - author: [['id', 'name']] - } - }; - - module.exports = { - before: { - all: cache(cacheMapUsers) - }, - after: { - all: [cache(cacheMapUsers), fastJoin(postResolvers, () => query)] - } - }; - ``` - - The number of service calls needed to run the `query` above **the second time**: - -| Using | number of service calls | -| ---------------------: | :---------------------: | -| `populate` | **22** | -| `fastJoin` alone | **2** | -| `fastJoin` and `cache` | **0** | - -The `cache` hook also makes `get` service calls more efficient. - -> The `cache` hook **must** be registered in both `before` and `after`. - -- **Details** - - We often want to combine rows from two or more tables based on a relationship between them. The `fastJoin` hook will select records that have matching values in both tables. It can batch service calls and cache records, thereby needing roughly an order of magnitude fewer database calls than the `populate` hook, e.g. _2_ calls instead of _20_. - - Relationships such as `1:1`, `1:m`, `n:1`, and `n:m` relationships can be handled. - - `fastJoin` uses a GraphQL-like imperative API, and it is not restricted to using data from Feathers services. Resources for which there are no Feathers adapters can [be used.](https://github.com/feathersjs-ecosystem/batch-loader) - - The companion `@feathers-plus/cache` implements a least recently-used cache which discards the least recently used items first. When used in conjunction with the `cache` hook, it can be used to implement persistent caches for BatchLoaders. BatchLoaders configured this way would retain their cache between requests, eliminating the need to _prime_ the cache at the start of each request. - -## iff - -Execute one or another series of hooks depending on a sync or async predicate. - - - -- **Arguments** - - `{Boolean | Promise | Function} predicate` - - `{Array< Function >} hookFuncsTrue` - - `{Array< Function >} hookFuncsFalse` - -| Argument | Type | Default | Description | -| ---------------- | :--------------------------------: | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `predicate` | `Boolean`, `Promise` or `Function` | | Determine if `hookFuncsTrue` or `hookFuncsFalse` should be run. If a function, `predicate` is called with the `context` as its param. It returns either a boolean or a Promise that evaluates to a boolean. | -| `hookFuncsTrue` | `Array<` `Function >` | | Sync or async hook functions to run if `true`. They may include other conditional hooks. | -| `hookFuncsFalse` | `Array<` `Function >` | | Sync or async hook functions to run if `false`. They may include other conditional hooks. | - -- **Example** - - ```js - const { discard, iff, isProvider, populate } = require('feathers-hooks-common'); - const isNotAdmin = adminRole => context => context.params.user.roles.indexOf(adminRole || 'admin') === -1; - - module.exports = { before: { - create: iff( - () => new Promise((resolve, reject) => { ... }), - populate('user', { field: 'authorisedByUserId', service: 'users' }) - ), - - get: [ iff(isNotAdmin(), discard('budget')) ] - - update: - iff(isProvider('server'), - hookA, - iff(isProvider('rest'), hook1, hook2, hook3) - .else(hook4, hook5), - hookB - ) - .else( - iff(hook => hook.path === 'users', hook6, hook7) - ) - } }; - ``` - -- **Details** - - Resolve the predicate, then run one set of hooks sequentially. - - The predicate and hook functions will not be called with `this` set to the service, as is normal for hook functions. Use `hook.service` instead. - -## iffElse - -Execute one array of hooks or another based on a sync or async predicate. - - - -- **Arguments** - - `{Function} predicate` - - `{Array< Functions >} hookFuncsTrue` - - `{Array< Functions >} hookFuncsFalse` - -| Argument | Type | Default | Description | -| ---------------- | :--------------------------------: | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `predicate` | `Boolean`, `Promise` or `Function` | | Determine if `hookFuncsTrue` or `hookFuncsFalse` should be run. If a function, `predicate` is called with the `context` as its param. It returns either a boolean or a Promise that evaluates to a boolean. | -| `hookFuncsTrue` | `Array<` `Function >` | | Sync or async hook functions to run if `true`. They may include other conditional hooks. | -| `hookFuncsFalse` | `Array<` `Function >` | | Sync or async hook functions to run if `false`. They may include other conditional hooks. | - -- **Example** - - ```js - const { iffElse, populate, serialize } = require('feathers-hooks-common'); - - module.exports = { after: { - create: iffElse(() => { ... }, - [populate(poAccting), serialize( ... )], - [populate(poReceiving), serialize( ... )] - ) - } }; - ``` - -- **Details** - - Resolve the predicate, then run one set of hooks sequentially. - - The predicate and hook functions will not be called with `this` set to the service, as is normal for hook functions. Use `hook.service` instead. - -## keep - -Keep certain fields in the record(s), deleting the rest. - - - -> **Note:** The keep hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), keep(...))`. - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | -------------------------------------------------- | -| fieldNames | dot notation | The only fields you want to keep in the record(s). | - -- **Example** - - ```js - const { keep } = require('feathers-hooks-common'); - - module.exports = { - after: { - create: keep('name', 'dept', 'address.city') - } - }; - ``` - -- **Details** - - Update either `context.data` (before hook) or `context.result[.data]` (after hook). - Their values are returned if they are not an object, so a `null` value is supported. - -## keepInArray - -Keep certain fields in a nested array inside the record(s), deleting the rest. - - - -> **Note:** The keepInArray hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), keepInArray(...))`. - -- **Arguments** - - `{String} arrayName` - - `{Array< String >} fieldNames` - -| Argument | Type | Default | Description | -| ------------ | ----------------- | ------- | --------------------------------------------------------------------- | -| `arrayName` | `String` | | Field name containing an array of objects. Dot notation is supported. | -| `fieldNames` | `Array< String >` | | Field names to keep in each object. Dot notation is supported. | - -- **Example** - - ```js - const { keepInArray } = require('feathers-hooks-common'); - - module.exports = { - after: { - create: keepInArray('users', ['name', 'dept', 'address.city']), - find: keepInArray('account.users', ['name', 'dept', 'address.city']) - } - }; - ``` - -- **Details** - - Update either `context.data` (before hook) or `context.result[.data]` (after hook). - Their values are returned if they are not an object, so a `null` value is supported. - -## keepQuery - -Keep certain fields in the query object, deleting the rest. - - - -> **Note:** The keepQuery hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), keepQuery(...))`. - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | ----------------------------------------------------- | -| fieldNames | dot notation | The only fields you want to keep in the query object. | - -- **Example** - - ```js - const { keepQuery } = require('feathers-hooks-common'); - - module.exports = { - after: { - create: keepQuery('name', 'address.city') - } - }; - ``` - -- **Details** - - Updates `context.params.query`. - -## keepQueryInArray - -Keep certain fields in a nested array inside the query object, deleting the rest. - - - -> **Note:** The keepQueryInArray hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), keepQueryInArray(...))`. - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | --------------------------------------------------------------------------- | -| fieldNames | dot notation | The only fields you want to keep in a nested array inside the query object. | - -- **Arguments** - - `{String} arrayName` - - `{Array< String >} fieldNames` - -| Argument | Type | Default | Description | -| ------------ | ----------------- | ------- | --------------------------------------------------------------------- | -| `arrayName` | `String` | | Field name containing an array of objects. Dot notation is supported. | -| `fieldNames` | `Array< String >` | | Field names to keep in each object. Dot notation is supported. | - -- **Example** - - ```js - const { keepQueryInArray } = require('feathers-hooks-common'); - - module.exports = { - before: { - find: keepQueryInArray('$or', ['name', 'dept', 'address.city']) - } - }; - ``` - -- **Details** - - Updates `context.params.query`. - Their values are returned if they are not an object, so a `null` value is supported. - -## lowerCase - -Convert certain field values to lower case. - - - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | --------------------------------------------------------------------- | -| fieldNames | dot notation | The fields in the record(s) whose values are converted to lower case. | - -- **Example** - - ```js - const { lowerCase } = require('feathers-hooks-common'); - - module.exports = { - before: { - create: lowerCase('email', 'username', 'div.dept') - } - }; - ``` - -- **Details** - - Update either `context.data` (before hook) or `context.result[.data]` (after hook). - -## mongoKeys - -Wrap MongoDB foreign keys in ObjectID. - - - -- **Arguments** - - - `{Function} ObjectID` - - `{Array < String >} foreignKeyNames` - -| Argument | Type | Default | Description | -| ----------------- | :-------------------------------------: | ------- | -------------------------------------------- | -| `ObjectID` | `Function` | - | `require('mongodb').ObjectID` or equivalent. | -| `foreignKeyNames` | `Array < String >` dot notation allowed | - | Field names of the foreign keys. | - -- **Example** - - ```js - const { ObjectID } = require('mongodb'); - const { mongoKeys } = require('feathers-hooks-common'); - - /* Comment Schema - { - _id, - body, - authorId, // User creating this Comment - postId, // Comment is for this Post - edit: { - reason, - editorId, // User last editing Comment - ) - } - */ - - const foreignKeys = [ - '_id', 'authorId', 'postId', 'edit.editorId' - ]; - - module.exports = { before: { - find: mongoKeys(ObjectID, foreignKeys) - } }; - - // Usage - comment.find({ query: { postId: '111111111111' } }) // Get all Comments for the Post. - comment.find({ query: { authorId: { $in: [...] } } }) // Get all Comments from these authors. - comment.find({ query: { edit: { editorId: { $in: [...] } } } }) // Get all comments edited by these editors. - ``` - -- **Details** - - In MongoDB, foreign keys must be wrapped in ObjectID when used in a query, e.g. `comment.find({ query: { authorId: new ObjectID('111111111111') } })`. - - `mongoKeys` automates this, given the field names of all the foreign keys in the schema. This reduces the boilerplate clutter and reduces the chance of bugs occurring. - -## paramsFromClient - -Pass `context.params` from client to server. Server hook. - - - -- **Arguments** - - - `{Array< String > | String} whitelist` - -| Argument | Type | Default | Description | -| ----------- | :----------: | ------- | ------------------------------------------------------------------------------------------------------------ | -| `whitelist` | dot notation | | Names of the props permitted to be in `context.params`. Other props are ignored. This is a security feature. | - -- **Example** - - ```js - // client - const { paramsForServer } = require('feathers-hooks-common'); - - service.update( - id, - data, - paramsForServer({ - query: { dept: 'a' }, - populate: 'po-1', - serialize: 'po-mgr' - }) - ); - - // server - const { paramsFromClient } = require('feathers-hooks-common'); - - module.exports = { - before: { - all: [paramsFromClient('populate', 'serialize', 'otherProp'), myHook] - } - }; - - // myHook's `context.params` will now be - // { query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' } } - ``` - -- **Details** - - By default, only the `context.params.query` object is transferred from a Feathers client to the server, for security among other reasons. However you can explicitly transfer other `context.params` props with the client utility function `paramsForServer` in conjunction with the `paramsFromClient` hook on the server. - - This technique also works for service calls made on the server. - -## populate - -Join related records. - - - -> `fastJoin` is preferred over using `populate`. - -- **Arguments** - - - `{Object} options` - - - `{Object | Function} schema` - - - `{String} service` - - `{any} [ permissions ]` - - `{Array< Object > | Object} include` - - - `{String} service` - - `{String} [ nameAs ]` - - `{String} [ parentField ]` - - `{String} [ childField]` - - `{String} [ permissions ]` - - `{Object} [ query ]` - - `{Function} [ select ]` - - `{Boolean} [ asArray ]` - - `{Boolean | Number} [ paginate ]` - - `{Boolean} [ useInnerPopulate ]` - - `{undefined}} [ provider ]` - - `{Array< Object > | Object} include` - - - ... - - - `{Function} [ checkPermissions ]` - - `{Boolean} [ profile ]` - -| Argument | Type | Default | Description | -| ------------------ | ------------------- | ---------------------------- | ---------------------------------- | -| `options` | `Object` | | Options. | -| `schema` | `Object` `Function` | `(context, options)` `=> {}` | Info on how to join records. | -| `checkPermissions` | `Function` | no permission check | Check if call allowed joins. | -| `profile` | `Boolean` | `false` | If profile info is to be gathered. | - -| `schema` | Argument | Type | Default | Description | -| ------------------ | ------------------------------------ | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -| `service` | `String` | | The name of the service providing the items, actually its path. | -| `nameAs` | dot notation | `service` | Where to place the items from the join | -| `parentField` | dot notation | | The name of the field in the parent item for the relation. | -| `childField` | dot notation if database supports it | | The name of the field in the child item for the relation. Dot notation is allowed and will result in a query like `{ 'name.first':` `'John' }` which is not suitable for all DBs. You may use query or select to create a query suitable for your DB. | -| `permissions` | `any` | no permission check | Who is allowed to perform this join. See `checkPermissions` above. | -| `query` | `Object` | | An object to inject into `context.params.query`. | -| `select` | `Function` | `(context,` `parentItem,` `depth)` `=> {}` | A function whose result is injected into the query. | -| `asArray` | `Boolean` | `false` | Force a single joined item to be stored as an array. | -| `paginate` | `Boolean` `Number` | `false` | Controls pagination for this service. | -| `useInnerPopulate` | `Boolean` | `false` | Perform any `populate` or `fastJoin` registered on this service. | -| `provider` | `undefined` | | Call the service as the server, not with the client's transport. | -| `include` | `Array<` `Object >` or `Object` | | Continue recursively join records to these records. | - -> Read the [guide](guides.html#populate) for more information on the arguments. - -- **Examples** - - - 1:1 relationship - - ```javascript - // users like { _id: '111', name: 'John', roleId: '555' } - // roles like { _id: '555', permissions: ['foo', bar'] } - import { populate } from 'feathers-hooks-common'; - - const userRoleSchema = { - include: { - service: 'roles', - nameAs: 'role', - parentField: 'roleId', - childField: '_id' - } - }; - - app.service('users').hooks({ - after: { - all: populate({ schema: userRoleSchema }) - } - }); - - // result like - // { _id: '111', name: 'John', roleId: '555', - // role: { _id: '555', permissions: ['foo', bar'] } } - ``` - - - 1:n relationship - - ```javascript - // users like { _id: '111', name: 'John', roleIds: ['555', '666'] } - // roles like { _id: '555', permissions: ['foo', 'bar'] } - const userRolesSchema = { - include: { - service: 'roles', - nameAs: 'roles', - parentField: 'roleIds', - childField: '_id' - } - }; - - usersService.hooks({ - after: { - all: populate({ schema: userRolesSchema }) - } - }); - - // result like - // { _id: '111', name: 'John', roleIds: ['555', '666'], roles: [ - // { _id: '555', permissions: ['foo', 'bar'] } - // { _id: '666', permissions: ['fiz', 'buz'] } - // ]} - ``` - - - n:1 relationship - - ```javascript - // posts like { _id: '111', body: '...' } - // comments like { _id: '555', text: '...', postId: '111' } - const postCommentsSchema = { - include: { - service: 'comments', - nameAs: 'comments', - parentField: '_id', - childField: 'postId' - } - }; - - postService.hooks({ - after: { - all: populate({ schema: postCommentsSchema }) - } - }); - - // result like - // { _id: '111', body: '...' }, comments: [ - // { _id: '555', text: '...', postId: '111' } - // { _id: '666', text: '...', postId: '111' } - // ]} - ``` - - - Multiple and recursive includes - - ```javascript - const schema = { - service: '...', - permissions: '...', - include: [ - { - service: 'users', - nameAs: 'authorItem', - parentField: 'author', - childField: 'id', - include: [ ... ], - }, - { - service: 'comments', - parentField: 'id', - childField: 'postId', - query: { - $limit: 5, - $select: ['title', 'content', 'postId'], - $sort: {createdAt: -1} - }, - select: (hook, parent, depth) => ({ $limit: 6 }), - asArray: true, - provider: undefined, - }, - { - service: 'users', - permissions: '...', - nameAs: 'readers', - parentField: 'readers', - childField: 'id' - } - ], - }; - - module.exports.after = { - all: populate({ schema, checkPermissions, profile: true }) - }; - ``` - - - Flexible relationship, similar to the n:1 relationship example above - - ```javascript - // posts like { _id: '111', body: '...' } - // comments like { _id: '555', text: '...', postId: '111' } - const postCommentsSchema = { - include: { - service: 'comments', - nameAs: 'comments', - select: (hook, parentItem) => ({ postId: parentItem._id }) - } - }; - - postService.hooks({ - after: { - all: populate({ schema: postCommentsSchema }) - } - }); - - // result like - // { _id: '111', body: '...' }, comments: [ - // { _id: '555', text: '...', postId: '111' } - // { _id: '666', text: '...', postId: '111' } - // ]} - ``` - -- **Details** - - We often want to combine rows from two or more tables based on a relationship between them. The `populate` hook will select records that have matching values in both tables. - - `populate` supports 1:1, 1:n and n:1 relationships. It can provide performance profile information. - -## preventChanges - -Prevent patch service calls from changing certain fields. - - - -- **Arguments** - -- `{Boolean} ifThrow` -- `{Array < String >} fieldNames` - -| Argument | Type | Default | Description | -| ------------ | :----------: | ------- | ------------------------------------------------------ | -| `ifThrow` | `Boolean` | | Deletes any `fieldNames` if `false`; throws if `true`. | -| `fieldNames` | dot notation | | The fields names which may not be patched. | - -- **Example** - - ```js - const { preventChanges } = require('feathers-hooks-common'); - - module.exports = { - before: { - patch: preventChanges(true, 'security.badge') - } - }; - ``` - -- **Details** - - Consider using validateSchema if you would rather specify which fields are allowed to change. - -## required - -Check selected fields exist and are not falsey. Numeric 0 is acceptable. - - - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | ------------------------------------------------------------------- | -| fieldNames | dot notation | These fields must exist and not be falsey. Numeric 0 is acceptable. | - -- **Example** - - ```js - const { required } = require('feathers-hooks-common'); - - module.exports = { - before: { - all: required('email', 'password') - } - }; - ``` - -## runParallel - -Run a hook in parallel to the other hooks and the service call. - - - -- **Arguments** - - - `{Function} hookFunc` - - `{Function} clone` - - `{Number} [ depth ]` - -| Argument | Type | Default | Description | -| ---------- | :--------: | :-----: | ------------------------------------------------------------------------------------------------------------------- | -| `hookFunc` | `Function` | | The hook function to run in parallel to the rest of the service call. | -| `clone` | `Function` | | Function to deep clone its only parameter. | -| `depth` | `Number` | 6 | Depth to which `context` is to be cloned. 0 does not clone. A depth of 5 would clone `context.result.data.[].item`. | - -- **Example** - - ```js - const { runParallel } = require('feathers-hooks-common'); - const clone = require('clone'); - - function sendEmail(...) { - return context => { ... }; - } - - module.exports = { after: { - create: runParallel(sendEmail(...), clone) - } }; - ``` - -- **Details** - - `hookFunc` is scheduled with a `setTimeout`. The next hook starts immediately. - - The hook was provided by bedeoverend. Thank you. - -## serialize - -Prune values from related records. Calculate new values. - - - -- **Arguments** - - `{Object | Function} schema` - - `{Array< String> | String} only` - - `{Array< String> | String} exclude` - - `[fieldName]: {Object} schema` - - `{Object} computed` - - `[fieldName]: {Function} computeFunc` - -| Argument | Type | Default | Description | -| -------- | :-----------------: | --------------------- | --------------------------- | -| `schema` | `Object` `Function` | `context` `=> schema` | How to serialize the items. | - -| `schema` | Argument | Type | Default | Description | -| ---------- | ------------------------------ | :--: | -------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -| `only` | `Array<` `String>` or `String` | | The names of the fields to keep in each item. The names for included sets of items plus `_include` and `_elapsed` are not removed by `only`. | -| `exclude` | `Array<` `String>` or `String` | | The names of fields to drop in each item. You may drop, at your own risk, names of included sets of items, `_include` and `_elapsed`. | -| `computed` | `Object` | | The new names you want added and how to compute their values. | - -| `schema` `.computed` | Argument | Type | Default | Description | -| -------------------- | ---------- | :------------------------------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | -| `fieldName` | `String` | | The name of the field to add to the records. | -| `computeFunnc` | `Function` | `(record,` `context)` `=> value` | Function to calculate the computed value. `item`: The item with all its initial values, plus all of its included items. The function can still reference values which will be later removed by only and exclude. `context`: The context passed to `serialize`. | - -- **Example** - - The schema reflects the structure of the populated records. The base records for this example have included `post` records, which themselves have included `authorItem`, `readersInfo` and `commentsInfo` records. - - ```js - const schema = { - only: 'updatedAt', - computed: { - commentsCount: (recommendation, hook) => recommendation.post.commentsInfo.length, - }, - post: { - exclude: ['id', 'createdAt', 'author', 'readers'], - authorItem: { - exclude: ['id', 'password', 'age'], - computed: { - isUnder18: (authorItem, hook) => authorItem.age < 18, - }, - }, - readersInfo: { - exclude: 'id', - }, - commentsInfo: { - only: ['title', 'content'], - exclude: 'content', - }, - }, - }; - purchaseOrders.after({ - all: [ populate( ... ), serialize(schema) ] - }); - - module.exports = { after: { - get: [ populate( ... ), serialize(schema) ], - find: [ fastJoin( ... ), serialize(schema) ] - } }; - ``` - -- **Details** - - Works with fastJoin and populate. - -## setField - -The `setField` hook allows to set a field on the hook context based on the value of another field on the hook context. - - - -### Options - -- `from` _required_ - The property on the hook context to use. Can be an array (e.g. `[ 'params', 'user', 'id' ]`) or a dot separated string (e.g. `'params.user.id'`). -- `as` _required_ - The property on the hook context to set. Can be an array (e.g. `[ 'params', 'query', 'userId' ]`) or a dot separated string (e.g. `'params.query.userId'`). -- `allowUndefined` (default: `false`) - If set to `false`, an error will be thrown if the value of `from` is `undefined` in an external request (`params.provider` is set). On internal calls (or if set to true `true` for external calls) the hook will do nothing. - -> **Important:** This hook should be used after the [authenticate hook](https://docs.feathersjs.com/api/authentication/hook.html#authenticate-options) when accessing user fields (from `params.user`). - -**Note:** When the service enable `multi:true` and `data` is an array data type, this hook may working to an unexpected result - -### Examples - -Limit all external access of the `users` service to the authenticated user: - -> **Note:** For MongoDB, Mongoose and NeDB `params.user.id` needs to be changed to `params.user._id`. For any other custom id accordingly. - -```js -const { authenticate } = require('@feathersjs/authentication'); -const { setField } = require('feathers-hooks-common'); - -app.service('users').hooks({ - before: { - all: [ - authenticate('jwt'), - setField({ - from: 'params.user.id', - as: 'params.query.id' - }) - ] - } -}); -``` - -Only allow access to invoices for the users organization: - -```js -const { authenticate } = require('@feathersjs/authentication'); -const { setField } = require('feathers-hooks-common'); - -app.service('invoices').hooks({ - before: { - all: [ - authenticate('jwt'), - setField({ - from: 'params.user.organizationId', - as: 'params.query.organizationId' - }) - ] - } -}); -``` - -Set the current user id as `userId` when creating a message and only allow users to edit and remove their own messages: - -```js -const { authenticate } = require('@feathersjs/authentication'); -const { setField } = require('feathers-hooks-common'); - -const setUserId = setField({ - from: 'params.user.id', - as: 'data.userId' -}); -const limitToUser = setField({ - from: 'params.user.id', - as: 'params.query.userId' -}); - -app.service('messages').hooks({ - before: { - all: [ - authenticate('jwt') - ], - create: [ - setUserId - ], - patch: [ - limitToUser - ], - update: [ - limitToUser - ] - remove: [ - limitToUser - ] - } -}) -``` - -## setNow - -Create/update certain fields to the current date-time. - - - -- Arguments - - `{Array < String >} fieldNames` - -| Name | Type | Description | -| ---------- | ------------ | ---------------------------------------------------------------- | -| fieldNames | dot notation | The fields that you want to add or set to the current date-time. | - -- **Example** - - ```js - const { setNow } = require('feathers-hooks-common'); - - module.exports = { - before: { - create: setNow('createdAt', 'updatedAt') - } - }; - ``` - -- **Details** - - Update either `context.data` (before hook) or `context.result[.data]` (after hook). - -## setSlug - -Set slugs in URL, e.g. /stores/:storeId. - - - -- **Arguments** - - `{String} slug` - - `{String} [ fieldName ]` - -| Argument | Type | Default | Description | -| ----------- | :------: | ------------- | ---------------------------------------------------------------------------------- | -| `slug` | `String` | | The slug as it appears in the route, e.g. `storeId` for`/stores/:storeId/candies`. | -| `fieldName` | `String` | `query[slug]` | The field to contain the slug value. | - -- **Example** - - ```js - const { setSlug } = require('feathers-hooks-common'); - - module.exports = { - before: { - all: [hooks.setSlug('storeId')] - } - }; - - // `context.params.query` will always be normalized, - // e.g. `{ size: 'large', storeId: '123' }` - ``` - -- **Details** - - A service may have a slug in its URL, e.g. `storeId` in `app.use(` `'/stores/:storeId/candies',` `new Service());`. The service gets slightly different values depending on the transport used by the client. - -| transport | `hook.data` `.storeId` | `hook.params` `.query` | code run on client | -| --------- | ---------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- | -| socketio | `undefined` | `{ size: 'large',` `storeId: '123' }` | `candies.create({ name: 'Gummi',qty: 100 },` `{ query: { size: 'large', storeId: '123' } })` | -| rest | `:storeId` | same as above | same as above | -| raw HTTP | `123` | `{ size: 'large' }` | `fetch('/stores/123/candies?size=large', ..` | - -This hook normalizes the difference between the transports. - -## sifter - -Filter data or result records using a MongoDB-like selection syntax. - - - -- **Arguments** - - - `{Function} siftFunc` - -| Argument | Type | Default | Description | -| ---------- | :--------: | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `siftFunc` | `Function` | | Function similar to `context => sift(mongoQueryObj)`. Information about the mongoQueryObj syntax is available at [crcn/sift](https://github.com/crcn/sift.js). | - -- **Example** - - ```js - const sift = require('sift'); - const { sifter } = require('feathers-hooks-common'); - - const selectCountry = hook => sift({ 'address.country': hook.params.country }); - - module.exports = { - before: { - find: sifter(selectCountry) - } - }; - ``` - - ```js - const sift = require('sift'); - const { sifter } = require('feathers-hooks-common'); - - const selectCountry = country => () => sift({ address: { country: country } }); - - module.exports = { - before: { - find: sifter(selectCountry('Canada')) - } - }; - ``` - -- **Details** - - All official Feathers database adapters support a common way for querying, sorting, limiting and selecting find method calls. These are limited to what is commonly supported by all the databases. - - The `sifter` hook provides an extensive MongoDB-like selection capabilities, and it may be used to more extensively select records. - - `sifter` filters the result of a find call. Therefore more records will be physically read than needed. You can use the Feathers database adapters query to reduce this number.` - -## softDelete - -Flag records as logically deleted instead of physically removing them. Requires a Feathers v4 or later database adapter. - - - -- **Arguments** - -| Argument | Type | Default | Description | | -| -------------- | --------- | ------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------- | -| `deletedQuery` | `Function | Object` | `{ deleted: { $ne: true } }` | An object or async function that takes the query which returns the part of the query to exclude deleted entrie | -| `removeData` | `Function | Object` | `{ deleted: true }` | An object or async function that returns the data used to flag an entry as deleted | - -By default, `softDelete` queries for a `deleted` property not set to `true` (meaning it can either exist or be anything else). - -Setting `params.disableSoftDelete` to `true` allows to skip the `softDelete` hook. - -- **Example** - - Basic usage: - - ```js - const { softDelete } = require('feathers-hooks-common'); - - // Use standard softDelete which uses `deleted: true` - app.service('people').hooks({ - before: { - all: [softDelete()] - } - }); - - // will set `deleted: true` for entry with id 1 - app.service('people').remove(1); - - // Will find all people where `deleted` is not `true` - let people = app.service('people').find(); - - // `get`, `patch`, `update` or `remove` on a deleted entry will throw NotFound - app.service('people').get(1); - ``` - - Customizing `deletedQuery` and `removeData` to e.g. use `deletedAt`: - - ```js - // Use deletedAt and set when the entry was deleted - app.service('people').hooks({ - before: { - all: [ - hooks.softDelete({ - // context is the normal hook context - deletedQuery: async context => { - return { deletedAt: null }; - }, - removeData: async context => { - return { deletedAt: new Date() }; - } - }) - ], - create: [ - context => { - context.data.deletedAt = null; - } - ] - } - }); - ``` - -## stashBefore - -Stash current value of record, usually before mutating it. Performs a get call. - - - -- **Arguments** - - `{String} fieldName` - -| Argument | Type | Default | Description | -| ----------- | :--: | ---------- | ------------------------------------------------------------------------------ | -| `fieldName` | | `'before'` | The name of the `context.params` property to contain the current record value. | - -- **Example** - - ```js - const { stashBefore } = require('feathers-hooks-common'); - - module.exports = { - before: { - patch: stashBefore() - } - }; - ``` - -- **Details** - - The hook performs its own preliminary `get` call. If the original service call is also a `get`, its `context.params` is used for the preliminary `get`. The preliminary `get` will be skipped if `params.disableStashBefore` is truthy. - - For any other method the calling params are formed from the original calling context: - - ```js - { provider: context.params.provider, - authenticated: context.params.authenticated, - user: context.params.user } - ``` - -## traverse - -Transform fields & objects in place in the record(s) using a recursive walk. Powerful. - - - -- **Arguments** - - `{Function} transformer` - - `{Function} [ getObject ]` - -| Argument | Type | Default | Description | -| ------------- | :--------: | ----------------------------------------- | ----------------------------------------------------------------------------- | -| `transformer` | `Function` | | Called for every node in every record(s). May change the node in place. | -| `getObject` | `Function` | `context.data` or `context.result[.data]` | Function with signature `context => {}` which returns the object to traverse. | - -- **Example** - - ```js - const { traverse } = require('feathers-hooks-common'); - - // Trim strings - const trimmer = function (node) { - if (typeof node === 'string') { - this.update(node.trim()); - } - }; - - // REST HTTP request may use the string 'null' in its query string. - // Replace these strings with the value null. - const nuller = function (node) { - if (node === 'null') { - this.update(null); - } - }; - - module.exports = { - before: { - create: traverse(trimmer), - find: traverse(nuller, context => context.params.query) - } - }; - ``` - -- **Details** - - Traverse and transform objects in place by visiting every node on a recursive walk. Any object in the hook may be traversed, including the query object. - - > [traverse (NPM)](https://npmjs.com/package/traverse) documents the extensive methods and context available to the transformer function. - -## unless - -Execute a series of hooks if a sync or async predicate is falsey. - - - -- **Arguments** - - `{Boolean | Promise | Function} predicate` - - `{Array< Function >} hookFuncs` - -| Argument | Type | Default | Description | -| ----------- | :--------------------------------: | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `predicate` | `Boolean`, `Promise` or `Function` | | Run `hookFunc` if the `predicate` is false. If a function, `predicate` is called with the `context` as its param. It returns either a boolean or a Promise that evaluates to a boolean. | -| `hookFuncs` | `Array<` `Function >` | | Sync or async hook functions to run if `true`. They may include other conditional hooks. | - -- **Example** - - ```js - const { isProvider, unless } = require('feathers-hooks-common'); - - module.exports = { - before: { - create: unless( - isProvider('server'), - hookA, - unless(isProvider('rest'), hook1, hook2, hook3), - hookB - ) - } - }; - ``` - -- **Details** - - Resolve the predicate to a boolean. Run the hooks sequentially if the result is falsey. - - The predicate and hook functions will not be called with `this` set to the service, as is normal for hook functions. Use `hook.service` instead. - -## validate - -Validate data using a validation function. - - - -- **Arguments** - - - `{Function} validator` - -| Argument | Type | Default | Description | -| ----------- | :--------: | ------- | ---------------------------------------- | -| `validator` | `Function` | | Validation function. See Details below.. | - -- **Example** - - ```js - const { validate } = require('feathers-hooks-common'); - const { promisify } = require('util'); - - // function myCallbackValidator(values, cb) { ... } - const myValidator = promisify(myCallbackValidator); - - module.exports = { - before: { - create: validate(myValidator) - } - }; - ``` - -- **Details** - - The validation function may be sync or return a Promise. Sync functions return either an error object like `{ fieldName1: 'message', ... }` or `null`. They may also throw with `throw new errors.BadRequest({ errors: errors });`. - - Promise functions should throw on an error or reject with `new errors.BadRequest('Error message', { errors: { fieldName1: 'message', ... } });`. Their `.then` returns either sanitized values to replace `context.data`, or `null`. - - The validator's parameters are - - - `{Object} formValues` - - `{Object} context` - - Sync functions return either an error object like `{ fieldName1: 'message', ... }` or `null`. `Validate` will throw on an error object with `throw new errors.BadRequest({ errors: errorObject });`. - - - `{Object | null} errors` - -| Argument | Type | Default | Description | -| ------------ | :-------------: | ------- | ----------------------------------------------------- | -| `formValues` | `Object` | | The data, e.g. `{ name: 'John', ... }` | -| `context` | `Object` | | The hook context. | -| `errors` | `Object` `null` | | An error object like `{ fieldName1: 'message', ... }` | - -> If you have a different signature for the validator then pass a wrapper as the validator e.g. `values => myValidator(..., values, ...)`. - -> Wrap your validator in Node's `util.promisify` if it uses a callback. - -## validateSchema - -Validate data using JSON-Schema. - - - -- **Arguments** - - `{Object} schema` - - `{Function | Object} ajv` - - `{Object} options` - - `{Function} [ addNewError ]` - - `...` - -| Argument | Type | Default | Description | -| --------- | :-----------------: | ------- | ---------------------------------------------------------------------------------------------------------- | -| `schema` | `Object` | | The [JSON-schema.](https://code.tutsplus.com/tutorials/validating-data-with-json-schema-part-1--cms-25343) | -| `ajv` | `Function` `Object` | | The ajv validator. Could be either the Ajv constructor or an instance of it. | -| `options` | `Object` | | Options for `validateSchema` and `ajv`. | - -| `options` | Argument | Type | Default | Description | -| ------------- | ---------- | :-------: | ------------------------------------------------------------------------------------- | ----------- | -| `addNewError` | `Function` | see below | Custom error message formatter. | -| other | `any` | | Any `ajv` options. Only effective when the second parameter is the `Ajv` constructor. | - -- **Example** - - ```js - const Ajv = require('ajv'); - const createSchema = { - /* JSON-Schema */ - }; - - module.before({ - create: validateSchema(createSchema, Ajv) - }); - ``` - - ```js - const Ajv = require('ajv'); - const ajv = new Ajv({ allErrors: true, $data: true }); - - ajv.addFormat('allNumbers', '^d+$'); - const createSchema = { - /* JSON-Schema */ - }; - - module.before({ - create: validateSchema(createSchema, ajv) - }); - ``` - -- **Details** - - There are some good [tutorials](https://code.tutsplus.com/tutorials/validating-data-with-json-schema-part-1--cms-25343) on using JSON-Schema with [Ajv](https://github.com/epoberezkin/ajv). - - If you need to customize `Ajv` with new keywords, formats or schemas, then instead of passing the `Ajv` constructor, you may pass in an instance of `Ajv` as the second parameter. In this case you need to pass `Ajv` options to the `Ajv` instance when `new`ing, rather than passing them in the third parameter of `validateSchema`. See the examples. - -- **options.addNewError** - - The hook will throw if the data does not match the JSON-Schema. `error.errors` will, by default, contain an array of error messages. You may change this with a custom formatting function. Its a reducing function which works similarly to `Array.reduce()`. Its parameters are - - - `{any} currentFormattedMessages` - - `{Object} ajvErrorObject` - - `{Number} itemsLen` - - `{Number} index` - - It returns - - - `{any} newFormattedMessages` - -| Argument | Type | Default | Description | -| -------------------------- | :------: | ---------------- | -------------------------------------------------------------------- | -| `currentFormattedMessages` | `any` | initially `null` | Formatted messages so far. Initially null. | -| `ajvErrorObject` | `Object` | | [ajv error object](https://github.com/epoberezkin/ajv#error-objects) | -| `itemsLen` | `Number` | | How many data items there are. 1-based. | -| `item` | `Number` | | Which item this is. 0-based. | -| `newFormattedMessages` | `any` | | The function returns the updated formatted messages. | - -`error.errors` will, by default, contain an array of error messages. By default the message will look like - -```js -[ - '\'in row 1 of 3, first\' should match format "startWithJo"', - "in row 1 of 3, should have required property 'last'", - '\'in row 2 of 3, first\' should match format "startWithJo"', - "in row 3 of 3, should have required property 'last'" -]; -``` - -> You could, for example, return `{ name1: message, name2: message }` which might be more suitable for a UI. - -- **Internationalization of Messages** - - You can consider using [ajv-i18n](https://github.com/epoberezkin/ajv-i18n), together with ajv's `messages` option, to internationalize your error messages. - - You can also consider copying `addNewErrorDflt`, the default error message formatter, modifying it for your needs, and using that as `newFormattedMessages`. - -## when - -An alias for [iff](#iff). diff --git a/docs/hooks/HookDirectory.vue b/docs/hooks/HookDirectory.vue new file mode 100644 index 00000000..27bb9717 --- /dev/null +++ b/docs/hooks/HookDirectory.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/docs/hooks/[slug].md b/docs/hooks/[slug].md new file mode 100644 index 00000000..d9dc0004 --- /dev/null +++ b/docs/hooks/[slug].md @@ -0,0 +1,4 @@ +--- +--- + + diff --git a/docs/hooks/[slug].paths.ts b/docs/hooks/[slug].paths.ts new file mode 100644 index 00000000..5e2b9bb3 --- /dev/null +++ b/docs/hooks/[slug].paths.ts @@ -0,0 +1,15 @@ +import path from 'node:path' +import { discoverUtilities } from '../.vitepress/utilities' +import { defineRoutes } from 'vitepress' + +export default defineRoutes({ + async paths() { + const utilities = (await discoverUtilities()).filter(utility => utility.category === 'hooks') + + return utilities.map(utility => ({ + params: { slug: utility.slug }, + content: utility.content, + })) + }, + watch: [path.resolve(import.meta.dirname, '../../src/hooks/**/*.md')], +}) diff --git a/docs/hooks/index.data.ts b/docs/hooks/index.data.ts new file mode 100644 index 00000000..37a1f563 --- /dev/null +++ b/docs/hooks/index.data.ts @@ -0,0 +1,8 @@ +import { defineLoader } from 'vitepress' +import { discoverUtilities } from '../.vitepress/utilities' + +export default defineLoader({ + async load() { + return (await discoverUtilities()).filter(utility => utility.category === 'hooks') + }, +}) diff --git a/docs/hooks/index.md b/docs/hooks/index.md new file mode 100644 index 00000000..d5f97f60 --- /dev/null +++ b/docs/hooks/index.md @@ -0,0 +1,11 @@ +--- +--- + + + +# Hooks + + diff --git a/docs/index.md b/docs/index.md index b5599cb5..fa42fba0 100755 --- a/docs/index.md +++ b/docs/index.md @@ -2,10 +2,10 @@ layout: home hero: - name: feathers-hooks-common + name: feathers-commons image: src: /feathers-hooks-common-logo.png - alt: feathers-hooks-common + alt: feathers-commons tagline: Common hooks and utils for FeathersJS apps actions: - theme: brand diff --git a/docs/migrating.md b/docs/migrating.md index 812547be..78c310af 100644 --- a/docs/migrating.md +++ b/docs/migrating.md @@ -1,45 +1 @@ # Migrating - -Version 5.0.0 of `feathers-hooks-common` is compatible with Feathers v4 and up. - -## Deprecations - -The following hooks and utilities have been deprecated and replaced with different named alternatives, Feathers v4 or Lodash functionality: - -### Hooks - -- `callback-to-promise` - Use `async/await`, native Promises or NodeJS [utils.promisify](https://nodejs.org/api/util.html#util_util_promisify_original) -- `client` - Use [paramsFromClient](hooks#paramsfromclient) instead -- `disable` - Use [disallow](hooks#disallow) instead -- `disable-multi-item-change` - Use the database adapter `multi` option instead. See the [Feathers v4 migration guide](https://docs.feathersjs.com/guides/migrating.html) for more information. -- disable-multi-item-create - Use the database adapter `multi` option instead. See the [Feathers v4 migration guide](https://docs.feathersjs.com/guides/migrating.html) for more information. -- `pluck` - Use `iff(isProvider('external'), keep(...fieldNames))` instead -- `pluckQuery` - Use [keepQuery](hooks#keepquery) instead -- promiseToCallback - No longer necessary since callbacks have been deprecated in Feathers v3 and later -- `removeQuery` - Use [discardQuery](hooks#discardquery) instead -- `setCreatedAt` - Use [setNow](hooks#setnow) instead -- `setUpdatedAt` - Use [setNow](hooks#setnow) instead -- `skipRemainingHooks` - Use conditional hook chains with [iff](hooks#iff) instead -- `skipRemainingHooksOnFlag` - Use conditional hook chains with [iff](hooks#iff) instead -- `softDelete2` - Use Feathers v4 database adapters and the new [softDelete](hooks#softdelete) instead - -### Utilities - -Several utility methods have been replaced by [Lodash](https://lodash.com) methods which are thoroughly tested and performance optimized in many different environments. - -- `existsByDot` - Use [\_.has()](https://lodash.com/docs/latest#has) -- `deleteByDot` - Use [\_.omit](https://lodash.com/docs/latest#omit) -- `getByDot` - Use [\_.get()](https://lodash.com/docs/latest#get) -- `setByDot` - Use [\_.set()](https://lodash.com/docs/latest#set) - -## Safe mutations - -Most hooks have been updated to safely delete or add properties by replacing the object on the context with a new object instead of mutating it. This should prevent difficult to debug situations where e.g. `params` or `params.query` get changes in nested hooks when passed along. - -## stashBefore - -## softDelete - -## setField - -Moved to [feathers-authentication-hooks](https://github.com/feathersjs-ecosystem/feathers-authentication-hooks#setfield) diff --git a/docs/overview.md b/docs/overview.md index b5ee34b8..8f0a0b45 100644 --- a/docs/overview.md +++ b/docs/overview.md @@ -4,13 +4,8 @@ This documentation has several parts: -- [Hooks API](./hooks.md) - The API for the available hooks -- [Utilities API](./utilities.md) - The API for the available utility methods +- [Hooks API](./hooks/index.md) - The API for the available hooks +- [Utilities API](./utils/index.md) - The API for the available utility methods +- [Predicates](./predicates/index.md)- The API for the available predicates - [Migrating](./migrating.md) - Information on how to migrate to the latest version of `feathers-hooks-common` - [Guides](./guides.md) - More in-depth guides for some of the available hooks - -## Notable Changes - -### 6.1.0 - -- **new hook `setField`**: The `setField` hook allows to set a field on the hook context based on the value of another field on the hook context. [see docs](./hooks.md#setfield) diff --git a/docs/predicates/PredicateDirectory.vue b/docs/predicates/PredicateDirectory.vue new file mode 100644 index 00000000..45aaebd5 --- /dev/null +++ b/docs/predicates/PredicateDirectory.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/docs/predicates/[slug].md b/docs/predicates/[slug].md new file mode 100644 index 00000000..d9dc0004 --- /dev/null +++ b/docs/predicates/[slug].md @@ -0,0 +1,4 @@ +--- +--- + + diff --git a/docs/predicates/[slug].paths.ts b/docs/predicates/[slug].paths.ts new file mode 100644 index 00000000..557d2fe8 --- /dev/null +++ b/docs/predicates/[slug].paths.ts @@ -0,0 +1,16 @@ +import { discoverUtilities } from '../.vitepress/utilities' +import { defineRoutes } from 'vitepress' + +export default defineRoutes({ + async paths() { + const utilities = (await discoverUtilities()).filter( + utility => utility.category === 'predicates', + ) + + return utilities.map(utility => ({ + params: { slug: utility.slug }, + content: utility.content, + })) + }, + watch: ['../src/predicates/**/*.md'], +}) diff --git a/docs/predicates/index.data.ts b/docs/predicates/index.data.ts new file mode 100644 index 00000000..97a368b4 --- /dev/null +++ b/docs/predicates/index.data.ts @@ -0,0 +1,8 @@ +import { defineLoader } from 'vitepress' +import { discoverUtilities } from '../.vitepress/utilities' + +export default defineLoader({ + async load() { + return (await discoverUtilities()).filter(utility => utility.category === 'predicates') + }, +}) diff --git a/docs/predicates/index.md b/docs/predicates/index.md new file mode 100644 index 00000000..25748d77 --- /dev/null +++ b/docs/predicates/index.md @@ -0,0 +1,11 @@ +--- +--- + + + +# Predicates + + diff --git a/docs/utilities.md b/docs/utilities.md index ce4609ba..75aeb144 100644 --- a/docs/utilities.md +++ b/docs/utilities.md @@ -1,5 +1,4 @@ # Utilities @@ -8,9 +7,9 @@ import HookTable from './components/HookTable.vue' Build `params` for a service call. -- **Arguments** +## Arguments - - `{Object} options` +- `{Object} options` | Argument | Type | Default | Description | | --------- | :------: | ------- | ----------------------------------------- | @@ -28,7 +27,7 @@ Build `params` for a service call. - `{Function}` - - **Arguments** + ## Arguments - `{Object} context` @@ -44,317 +43,74 @@ Build `params` for a service call. | ----------- | :------: | -------------------------------- | | `newParams` | `Object` | The params for the service call. | -- **Example** - - ```js - const { callingParams, callingParamsDefaults } = require('feathers-hooks-common'); - // Authentication props to always copy. Suitable for feathers-authentication-management. - callingParamsDefaults(['provider', 'authenticated', 'user', 'isVerified']); - - async function myCustomHook(context) { - // ... - const result = await service.find(callingParams({ - query: { { id: { $in: [1, 2, 3] } } }, - propNames: ['customProp'], - newProps: { mongoose: ... }, - hooksToDisable: 'populate' - }))(context); - // ... - } - ``` +## Example + +```js +const { callingParams, callingParamsDefaults } = require('feathers-hooks-common/index.js'); +// Authentication props to always copy. Suitable for feathers-authentication-management. +callingParamsDefaults(['provider', 'authenticated', 'user', 'isVerified']); + +async function myCustomHook(context) { + // ... + const result = await service.find(callingParams({ + query: { { id: { $in: [1, 2, 3] } } }, + propNames: ['customProp'], + newProps: { mongoose: ... }, + hooksToDisable: 'populate' + }))(context); + // ... +} +``` -- **Details** +## Details - When calling another service within a hook, [consideration must be given](https://auk.docs.feathersjs.com/guides/step-by-step/basic-feathers/writing-hooks.html#calling-a-service) to what the `params` should be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create that `params`. +When calling another service within a hook, [consideration must be given](https://auk.docs.feathersjs.com/guides/step-by-step/basic-feathers/writing-hooks.html#calling-a-service) to what the `params` should be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create that `params`. - The properties `provider`, `authenticated` and `user` are the standard authentication properties used by Feathers. They are copied automatically. +The properties `provider`, `authenticated` and `user` are the standard authentication properties used by Feathers. They are copied automatically. - These defaults and others can be changed app-wide by calling the `callingParamsDefaults` utility. +These defaults and others can be changed app-wide by calling the `callingParamsDefaults` utility. ## callingParamsDefaults Set defaults for building `params` for service calls with callingParams. -- **Arguments** +## Arguments - - `{Array< String >} propNames` - - `{Object} newProps` +- `{Array< String >} propNames` +- `{Object} newProps` | Argument | Type | Default | Description | | ----------- | :---------------: | ------- | -------------------------------------------------------------------------------------- | | `propNames` | `Array< String >` | | The names of the props in `context.params` to automatically include in the new params. | | `newProps` | `Object` | | Additional props to add to the new params. | -- **Example** - - ```js - const { callingParams, callingParamsDefaults } = require('feathers-hooks-common'); - // Authentication props to always copy. Suitable for feathers-authentication-management. - // Only hooks will be calling `callingParams`. Set a flag so other hooks recognize such a call. - callingParamsDefaults(['provider', 'authenticated', 'user', 'isVerified'], { _calledByHook: true }); - - async function myCustomHook(context) { - // ... - const result = await service.find(callingParams({ - query: { { id: { $in: [1, 2, 3] } } }, - propNames: ['customProp'], - newProps: { mongoose: ... }, - hooksToDisable: 'populate' - }), context); - // ... - } - ``` - -- **Details** - - When calling another service within a hook, [consideration must be given](https://auk.docs.feathersjs.com/guides/step-by-step/basic-feathers/writing-hooks.html#calling-a-service) to what the `params` should be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create that `params`. - - The properties `provider`, `authenticated` and `user` are the standard authentication properties used by Feathers. They are copied automatically. - - These defaults and others can be changed app-wide by calling the `callingParamsDefaults` utility. - -## checkContext - -Restrict a hook to run for certain methods and method types. - -- **Arguments** - - `{Object} context` - - `{String | Array< String >} [ type ]` - - `{String | Array< String >} [ methods ]` - - `{String} [ label ]` - -| Argument | Type | Default | Description | -| --------- | :------: | ---------------- | --------------------------------- | --------------------------------------------------------------- | -| `context` | `Object` | | The hook context. | -| `type` | `String | Array< String >` | all types | The service type allowed - before, after, error. | -| `methods` | `String | Array< String >` | all methods | The service methods allowed - find, get, update, patch, remove. | -| `label` | `String` | `'anonymous'` | Name of hook to use with `throw`. | - -- **Example** - - ```js - const { checkContext } = require('feathers-hooks-common'); - - function myHook(context) { - checkContext(context, 'after', ['create', 'remove']); - ... - } - - module.exports = { before: { - create: [ myHook ] // throws - } }; - - // checkContext(hook, 'before', ['update', 'patch'], 'hookName'); - // checkContext(hook, null, ['update', 'patch']); - // checkContext(hook, 'before', null, 'hookName'); - // checkContext(hook, 'before'); - ``` - -- **Details** - - Its important to ensure the hook is being used as intended. `checkContext` let's you restrict the hook to a hook type and a set of service methods. - -## combine - -Sequentially execute multiple sync or async hooks. - - - -- **Arguments** - - `{Array< Function >} hookFuncs` - -| Argument | Type | Default | Description | -| ----------- | :----------------: | ------- | --------------------------------------------------- | -| `hookFuncs` | `Array` | | Hooks, used the same way as when you register them. | - -- **Example** - - ```js - const { combine, createdAt, updatedAt } = require('feathers-hooks-common'); - - async function myCustomHook(context) { - const newContext = await combine(setNow('createdAt'), setNow('updatedAt')).call(this, context); - return newContext; - } - ``` - -- **Details** - - `combine` has the signature of a hook, but is primarily intended to be used within your custom hooks, not when registering hooks. - -The following is a better technique to use when registering hooks. +## Example ```js -const workflow = [createdAt(), updatedAt(), ...]; - -module.exports = { before: { - update: [...workflow], - patch: [...workflow], -} }; +const { callingParams, callingParamsDefaults } = require('feathers-hooks-common/index.js'); +// Authentication props to always copy. Suitable for feathers-authentication-management. +// Only hooks will be calling `callingParams`. Set a flag so other hooks recognize such a call. +callingParamsDefaults(['provider', 'authenticated', 'user', 'isVerified'], { _calledByHook: true }); + +async function myCustomHook(context) { + // ... + const result = await service.find(callingParams({ + query: { { id: { $in: [1, 2, 3] } } }, + propNames: ['customProp'], + newProps: { mongoose: ... }, + hooksToDisable: 'populate' + }), context); + // ... +} ``` -## every - -Return the and of a series of sync or async predicate functions. - - - -- **Arguments** - - `{Array< Function >} predicates` - -| Argument | Type | Default | Description | -| ------------ | :-----------------: | ------- | ----------------------------------------------------------------------------- | -| `predicates` | `Array< Function >` | | Functions which take the current hook as a param and return a boolean result. | - -**Returns** - -- `{Boolean} result` - -| Name | Type | Description | -| ------ | ------- | ----------------------------- | -| result | Boolean | The logical and of predicates | - -- **Example** - - ```js - const { iff, every } = require('feathers-hooks-common'); - - module.exports = { before: { - create: iff(every(hook1, hook2, ...), hookA, hookB, ...) - } }; - ``` - -- **Details** - - `every` is a predicate function for use in conditional hooks. The predicate functions are run in parallel, and `true` is returned if every predicate returns a truthy value. - -## getItems - -Get the records in `context.data` or `context.result` - -- **Arguments** - - `{Object} context` - -| Argument | Type | Default | Description | -| --------- | :------: | ------- | ----------------- | -| `context` | `Object` | | The hook context. | - -**Returns** - -- `{Array< Object > | Object | undefined} records` - -| Name | Type | Description | -| ------- | --------------- | ----------- | --------- | ------------ | -| records | Array< Object > | Object | undefined | The records. | - -- **Example** - - ```js - const { getItems, replaceItems } = require('feathers-hooks-common'); - - const insertCode = code => context => { - const items = getItems(context); - if (Array.isArray(items)) { - items.forEach(item => { - item.code = code; - }); - } else { - items.code = code; - } - replaceItems(context, items); - }; +## Details - module.exports = { - before: { - create: insertCode('a') - } - }; - ``` +When calling another service within a hook, [consideration must be given](https://auk.docs.feathersjs.com/guides/step-by-step/basic-feathers/writing-hooks.html#calling-a-service) to what the `params` should be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create that `params`. -- **Details** +The properties `provider`, `authenticated` and `user` are the standard authentication properties used by Feathers. They are copied automatically. - `getItems` gets the records from the hook context: `context.data` (before hook) or `context.result[.data]` (after hook). - -## isNot - -Negate a sync or async predicate function. - - - -- **Arguments** - - - `{Function | Boolean} predicate` - -| Argument | Type | Default | Description | -| ----------- | :------------------: | ------- | --------------------------------------------------------------------------------------------- | -| `predicate` | `Function` `Boolean` | | A sync or async function which take the current hook as a param and returns a boolean result. | - -**Returns** - -- `{Boolean} result` - -| Name | Type | Description | -| ------ | ------- | -------------------- | -| result | Boolean | The not of predicate | - -- **Example** - - ```js - const { iff, isNot, isProvider, discard } = require('feathers-hooks-common'); - const isRequestor = () => context => new Promise(resolve, reject) => ... ); - - module.exports = { after: { - create: iff(isNot(isRequestor()), discard('password')) - } }; - ``` - -- **Details** - - `isNot` is a predicate function for use in conditional hooks. - -## isProvider - -Check which transport provided the service call. - - - -- **Arguments** - - `{Array< String >} transports` - -| Name | Type | Default | Description | -| ------------ | :---------------: | ------- | --------------------------------- | -| `transports` | `Array< String >` | | The transports you want to allow. | - -| `transports` | Value | Description | -| ------------ | :---------------------------------: | ----------- | -| `socketio` | Allow calls by Socket.IO transport. | -| `rest` | Allow calls by REST transport. | -| `external` | Allow calls other than from server. | -| `server` | Allow calls from server. | - -**Returns** - -- `{Boolean} result` - -| Name | Type | Description | -| ------ | ------- | ---------------------------------------------- | -| result | Boolean | If the call was made by one of the transports. | - -- **Example** - - ```js - const { iff, isProvider, discard } = require('feathers-hooks-common'); - - module.exports = { - after: { - create: iff(isProvider('external'), discard('password')) - } - }; - ``` - -- **Details** - - `isProvider` is a predicate function for use in conditional hooks. Its determines which transport provided the service call by checking `context.params.provider`. +These defaults and others can be changed app-wide by calling the `callingParamsDefaults` utility. ## makeCallingParams @@ -362,12 +118,12 @@ Build context.params for service calls. > **Tip:** You should prefer using the `callingParams` utility to `makeCallingParams`. -- **Arguments** +## Arguments - - `{Object} context` - - `{Object} [ query ]` - - `{Array< String > | String} [ include ]` - - `{Object} [ inject ]` +- `{Object} context` +- `{Object} [ query ]` +- `{Array< String > | String} [ include ]` +- `{Object} [ inject ]` | Argument | Type | Default | Description | | --------- | :---------------: | ------- | ------------------------------------------------------------------ | @@ -384,74 +140,69 @@ Build context.params for service calls. | ------------ | :------: | ------- | ------------------------ | | `newContext` | `Object` | | The new context created. | -- **Example** - - ```js - const { makeCallingParams } = require('feathers-hooks-common'); +## Example - async function myCustomHook(context) { - // ... - const result = await service.find(makeCallingParams( - context, { id: { $in: [1, 2, 3] } }, 'user', - { _populate: false, mongoose: ... } - )); - // ... - } - ``` +```js +const { makeCallingParams } = require('feathers-hooks-common/index.js'); + +async function myCustomHook(context) { + // ... + const result = await service.find(makeCallingParams( + context, { id: { $in: [1, 2, 3] } }, 'user', + { _populate: false, mongoose: ... } + )); + // ... +} +``` -- **Details** +## Details - When calling another service within a hook, [consideration must be given](https://auk.feathersjs.com/guides/step-by-step/basic-feathers/writing-hooks.html#calling-a-service) to what the `context.params` should be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create that `context.params`. +When calling another service within a hook, [consideration must be given](https://auk.feathersjs.com/guides/step-by-step/basic-feathers/writing-hooks.html#calling-a-service) to what the `context.params` should be for the called service. For example, should the called service see that a client is making the call, or the server? What authentication and authorization information should be provided? You can use this convenience function to help create that `context.params`. - The value `context.params._populate: 'skip'` is automatically added to skip any `fastJoin` or `populate` hooks registered on the called service. Set it to `false`, like in the example above, to make those hooks run. +The value `context.params._populate: 'skip'` is automatically added to skip any `fastJoin` or `populate` hooks registered on the called service. Set it to `false`, like in the example above, to make those hooks run. ## paramsForServer Pass an explicit context.params from client to server. Client-side. -- **Arguments** - - `{Object} params` - - `{Array< String >} [ whitelist ]` +## Arguments + +- `{Object} params` +- `{Array< String >} [ whitelist ]` | Argument | Type | Default | Description | | ----------- | :----------: | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `params` | `Object` | | The `context.params` to use for the service call, including any query object. | | `whitelist` | dot notation | all props in `context.params` | Names of the props in `context.params` to transfer to the server. This is a security feature. All props are transferred if no `whitelist` is provided. | -- **Example** +## Example - ```js - // client - const { paramsForServer } = require('feathers-hooks-common'); +```js +// client +const { paramsForServer } = require('feathers-hooks-common/index.js'); - service.update( - id, - data, - paramsForServer({ - query: { dept: 'a' }, - populate: 'po-1', - serialize: 'po-mgr' - }) - ); +service.update( + id, + data, + paramsForServer({ query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' }), +); - // server - const { paramsFromClient } = require('feathers-hooks-common'); +// server +const { paramsFromClient } = require('feathers-hooks-common/index.js'); - module.exports = { - before: { - all: [paramsFromClient('populate', 'serialize', 'otherProp'), myHook] - } - }; +module.exports = { + before: { all: [paramsFromClient('populate', 'serialize', 'otherProp'), myHook] }, +}; - // myHook's `context.params` will now be - // { query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' } } - ``` +// myHook's `context.params` will now be +// { query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' } } +``` -- **Details** +## Details - By default, only the `context.params.query` object is transferred from a Feathers client to the server, for security among other reasons. However you can explicitly transfer other `context.params` props with the client utility function `paramsForServer` in conjunction with the `paramsFromClient` hook on the server. +By default, only the `context.params.query` object is transferred from a Feathers client to the server, for security among other reasons. However you can explicitly transfer other `context.params` props with the client utility function `paramsForServer` in conjunction with the `paramsFromClient` hook on the server. - This technique also works for service calls made on the server. +This technique also works for service calls made on the server.

The data is transfered using `context.params.query.$client`. If that field already exists, it must be an Object.

@@ -459,164 +210,118 @@ Pass an explicit context.params from client to server. Client-side. Replace the records in context.data or context.result[.data]. -- **Arguments** +## Arguments - - `{Object} context` - - `{Array< Object > | Object} records` +- `{Object} context` +- `{Array< Object > | Object} records` | Argument | Type | Default | Description | | --------- | :------------------------: | ------- | ----------------- | | `context` | `Object` | | The hook context. | | `records` | `Array< Object >` `Object` | | The new records. | -- **Example** - - ```js - const { getItems, replaceItems } = require('feathers-hooks-common'); +## Example - const insertCode = code => context { - const items = getItems(context); - if (Array.isArray(items)) { - items.forEach(item => { item.code = code; }); - } else { - items.code = code; - } - replaceItems(context, items); - }; +```js +const { getItems, replaceItems } = require('feathers-hooks-common/index.js'); + +const insertCode = code => context { + const items = getItems(context); + if (Array.isArray(items)) { + items.forEach(item => { item.code = code; }); + } else { + items.code = code; + } + replaceItems(context, items); +}; - module.exports = { before: { - create: insertCode('a') - } }; - ``` +module.exports = { before: { + create: insertCode('a') +} }; +``` -- **Details** +## Details - `replaceItems` replaces the records in the hook context: `context.data` (before hook) or `context.result[.data]` (after hook). +`replaceItems` replaces the records in the hook context: `context.data` (before hook) or `context.result[.data]` (after hook). ## runHook Let's you call a hook right after the service call. -- **Arguments** - - `{Object} [ hookContext ]` - - `{Function} hookFunc` +## Arguments + +- `{Object} [ hookContext ]` +- `{Function} hookFunc` | Argument | Type | Default | Description | | ------------- | :--------: | ------- | ----------------------------- | | `hookContext` | `Object` | `{}` | The `context` for `hookFunc`. | | `hookFunc` | `Function` | | The hook to run. | -- **Example** - - ```js - const { keep, runHook } = require('feathers-hooks-common'); - - user.get(...) - .then( runHook()(keep('name', 'address.state')) ) - .then(data => ...); // [{ name: 'Marshall', address: { state: 'UT' }}] - - const data = await user.get(...); - const result = await runHook()(data)(keep('name', 'address.state')); - ``` - - ```js - const { fastJoin, runHook } = require('feathers-hooks-common'); - const runHookFinds = runHook({ app: app, method: 'find' }); - - const paymentsRecords = [ - { _id: 101, amount: 100, patientId: 1 }, - { _id: 102, amount: 105, patientId: 1 }, - { _id: 103, amount: 110, patientId: 1 }, - { _id: 104, amount: 115, patientId: 2 }, - { _id: 105, amount: 120, patientId: 3 }, - { _id: 106, amount: 125, patientId: 3 } - ]; - await payments.create(paymentsRecords); - - const patientsRecords = [ - { _id: 1, name: 'John' }, - { _id: 2, name: 'Marshall' }, - { _id: 3, name: 'David' } - ]; - await patients.create(patientsRecords); - - const paymentResolvers = { - joins: { - patient: () => async payment => { - payment.patient = ( - await patients.find({ - query: { - id: payment.patientId - } - }) - )[0]; - } - } - }; - - await payments - .find() - .then(runHookFinds(fastJoin(paymentResolvers))) - .then(data => console.log(data)); - - // log - [ - { _id: 101, amount: 100, patientId: 1, patient: { _id: 1, name: 'John' } }, - { _id: 102, amount: 105, patientId: 1, patient: { _id: 1, name: 'John' } }, - { _id: 103, amount: 110, patientId: 1, patient: { _id: 1, name: 'John' } }, - { - _id: 104, - amount: 115, - patientId: 2, - patient: { _id: 2, name: 'Marshall' } - }, - { _id: 105, amount: 120, patientId: 3, patient: { _id: 3, name: 'David' } }, - { _id: 106, amount: 125, patientId: 3, patient: { _id: 3, name: 'David' } } - ]; - ``` - -- **Details** - - Hooks are normally registered for a service, e.g. in `project/src/services` `/posts/posts.hooks.js`. This is nice and simple when, for example, all the `find` hooks have to run for every `find` call. - - The [conditional hooks](#tag-Conditionals) can be used when hooks have to be conditionally run based on the current environment. For example, we can discard the `password` field when the call is made by a client. - - However things are not always so straightforward. There can be that one call for which we want to join specific records. We could add a conditional hook that runs just for that one call, however we may soon find ourselves with a second and a third special case. - - `runHook` is designed for such cases. Instead of having to register a conditioned hook, it allows us to run the hook in a `.then()` right after the service call. - -## some - -Return the or of a series of sync or async predicate functions. - - +## Example -- **Arguments** - - - `{Array< Function >} predicates` - -| Argument | Type | Default | Description | -| ------------ | :-----------------: | ------- | ----------------------------------------------------------------------------- | -| `predicates` | `Array< Function >` | | Functions which take the current hook as a param and return a boolean result. | +```js +const { keep, runHook } = require('feathers-hooks-common/index.js'); -**Returns** +user.get(...) + .then( runHook()(keep('name', 'address.state')) ) + .then(data => ...); // [{ name: 'Marshall', address: { state: 'UT' }}] -- `{Boolean} result` +const data = await user.get(...); +const result = await runHook()(data)(keep('name', 'address.state')); +``` -| Name | Type | Description | -| ------ | ------- | ---------------------------- | -| result | Boolean | The logical or of predicates | +```js +const { fastJoin, runHook } = require('feathers-hooks-common/index.js'); +const runHookFinds = runHook({ app: app, method: 'find' }); + +const paymentsRecords = [ + { _id: 101, amount: 100, patientId: 1 }, + { _id: 102, amount: 105, patientId: 1 }, + { _id: 103, amount: 110, patientId: 1 }, + { _id: 104, amount: 115, patientId: 2 }, + { _id: 105, amount: 120, patientId: 3 }, + { _id: 106, amount: 125, patientId: 3 }, +]; +await payments.create(paymentsRecords); + +const patientsRecords = [ + { _id: 1, name: 'John' }, + { _id: 2, name: 'Marshall' }, + { _id: 3, name: 'David' }, +]; +await patients.create(patientsRecords); + +const paymentResolvers = { + joins: { + patient: () => async payment => { + payment.patient = (await patients.find({ query: { id: payment.patientId } }))[0]; + }, + }, +}; + +await payments + .find() + .then(runHookFinds(fastJoin(paymentResolvers))) + .then(data => console.log(data)); + +// log +[ + { _id: 101, amount: 100, patientId: 1, patient: { _id: 1, name: 'John' } }, + { _id: 102, amount: 105, patientId: 1, patient: { _id: 1, name: 'John' } }, + { _id: 103, amount: 110, patientId: 1, patient: { _id: 1, name: 'John' } }, + { _id: 104, amount: 115, patientId: 2, patient: { _id: 2, name: 'Marshall' } }, + { _id: 105, amount: 120, patientId: 3, patient: { _id: 3, name: 'David' } }, + { _id: 106, amount: 125, patientId: 3, patient: { _id: 3, name: 'David' } }, +]; +``` -- **Example** +## Details - ```js - const { iff, some } = require('feathers-hooks-common'); +Hooks are normally registered for a service, e.g. in `project/src/services` `/posts/posts.hooks.js`. This is nice and simple when, for example, all the `find` hooks have to run for every `find` call. - module.exports = { before: { - create: iff(some(hook1, hook2, ...), hookA, hookB, ...) - } }; - ``` +The [conditional hooks](#tag-Conditionals) can be used when hooks have to be conditionally run based on the current environment. For example, we can discard the `password` field when the call is made by a client. -- **Details** +However things are not always so straightforward. There can be that one call for which we want to join specific records. We could add a conditional hook that runs just for that one call, however we may soon find ourselves with a second and a third special case. - `some` is a predicate function for use in conditional hooks. The predicate functions are run in parallel, and `true` is returned if any predicate returns a truthy value. +`runHook` is designed for such cases. Instead of having to register a conditioned hook, it allows us to run the hook in a `.then()` right after the service call. diff --git a/docs/utils/UtilDirectory.vue b/docs/utils/UtilDirectory.vue new file mode 100644 index 00000000..1d62075c --- /dev/null +++ b/docs/utils/UtilDirectory.vue @@ -0,0 +1,17 @@ + + + \ No newline at end of file diff --git a/docs/utils/[slug].md b/docs/utils/[slug].md new file mode 100644 index 00000000..d9dc0004 --- /dev/null +++ b/docs/utils/[slug].md @@ -0,0 +1,4 @@ +--- +--- + + diff --git a/docs/utils/[slug].paths.ts b/docs/utils/[slug].paths.ts new file mode 100644 index 00000000..bfef7467 --- /dev/null +++ b/docs/utils/[slug].paths.ts @@ -0,0 +1,15 @@ +import path from 'node:path' +import { discoverUtilities } from '../.vitepress/utilities' +import { defineRoutes } from 'vitepress' + +export default defineRoutes({ + async paths() { + const utilities = (await discoverUtilities()).filter(utility => utility.category === 'utils') + + return utilities.map(utility => ({ + params: { slug: utility.slug }, + content: utility.content, + })) + }, + watch: [path.resolve(import.meta.dirname, '../../src/utils/**/*.md')], +}) diff --git a/docs/utils/index.data.ts b/docs/utils/index.data.ts new file mode 100644 index 00000000..97a368b4 --- /dev/null +++ b/docs/utils/index.data.ts @@ -0,0 +1,8 @@ +import { defineLoader } from 'vitepress' +import { discoverUtilities } from '../.vitepress/utilities' + +export default defineLoader({ + async load() { + return (await discoverUtilities()).filter(utility => utility.category === 'predicates') + }, +}) diff --git a/docs/utils/index.md b/docs/utils/index.md new file mode 100644 index 00000000..a76a8cf4 --- /dev/null +++ b/docs/utils/index.md @@ -0,0 +1,11 @@ +--- +--- + + + +# Utils + + diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..87ee06fb --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,3 @@ +import config from '@feathers-community/eslint-config' + +export default config({ tsconfig: { path: './tsconfig.eslint.json' } }) diff --git a/package-lock.json b/package-lock.json index 7c6eda80..cc825c2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "feathers-hooks-common", "version": "8.2.1", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -9,93 +9,78 @@ "version": "8.2.1", "license": "MIT", "dependencies": { - "@feathersjs/errors": "^5.0.29", - "ajv": "^6.12.6", - "debug": "^4.3.5", - "graphql": "^16.9.0", + "@feathersjs/errors": "^5.0.31", + "fast-copy": "^3.0.2", "lodash": "^4.17.21", - "neotraverse": "^0.6.14" + "neotraverse": "^0.6.18" }, "devDependencies": { - "@feathers-plus/batch-loader": "^0.3.6", + "@feathers-community/eslint-config": "^0.0.7", "@feathers-plus/cache": "^1.4.0", - "@feathers-plus/graphql": "^1.10.0", - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/authentication-local": "^5.0.29", - "@feathersjs/client": "^5.0.29", - "@feathersjs/express": "^5.0.29", - "@feathersjs/memory": "^5.0.29", - "@feathersjs/socketio": "^5.0.29", - "@feathersjs/socketio-client": "^5.0.29", - "@types/debug": "^4.1.12", - "@types/lodash": "^4.17.7", - "@types/node": "^20.14.11", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", - "@vitest/coverage-v8": "^1.6.0", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-prefer-arrow": "^1.2.3", - "eslint-plugin-prettier": "^5.2.1", - "mongodb": "^5.9.2", - "npm-check-updates": "^16.14.20", - "prettier": "^3.3.3", + "@feathersjs/authentication": "^5.0.31", + "@feathersjs/authentication-local": "^5.0.31", + "@feathersjs/client": "^5.0.31", + "@feathersjs/express": "^5.0.31", + "@feathersjs/memory": "^5.0.31", + "@feathersjs/socketio": "^5.0.31", + "@feathersjs/socketio-client": "^5.0.31", + "@shikijs/vitepress-twoslash": "^3.6.0", + "@tailwindcss/vite": "^4.1.10", + "@tsconfig/node22": "^22.0.2", + "@types/lodash": "^4.17.14", + "@types/node": "^22.10.7", + "@vitest/coverage-v8": "^3.0.3", + "dedent": "^1.6.0", + "eslint": "^9.18.0", + "glob": "^11.0.2", + "gray-matter": "^4.0.3", + "npm-check-updates": "^17.1.14", + "prettier": "^3.4.2", "shx": "^0.3.4", "sift": "^17.1.3", - "tsup": "^8.1.2", - "typescript": "^5.5.3", - "vitepress": "^1.3.1", - "vitest": "^1.6.0" - }, - "engines": { - "node": ">= 18" + "tailwindcss": "^4.1.10", + "tsdown": "^0.12.7", + "typescript": "^5.7.3", + "unplugin-unused": "^0.5.0", + "vitepress": "^2.0.0-alpha.6", + "vitest": "^3.0.3" }, "peerDependencies": { "@feathersjs/feathers": "^5.0.0" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@algolia/autocomplete-core": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", - "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.9.tgz", + "integrity": "sha512-O7BxrpLDPJWWHv/DLA9DRFWs+iY1uOJZkqUwjS5HSZAGcl0hIVCQ97LTLewiZmZ402JYUrun+8NqFP+hCknlbQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", - "@algolia/autocomplete-shared": "1.9.3" + "@algolia/autocomplete-plugin-algolia-insights": "1.17.9", + "@algolia/autocomplete-shared": "1.17.9" } }, "node_modules/@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", - "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.9.tgz", + "integrity": "sha512-u1fEHkCbWF92DBeB/KHeMacsjsoI0wFhjZtlCq2ddZbAehshbZST6Hs0Avkc0s+4UyBGbMDnSuXHLuvRWK5iDQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.9.3" + "@algolia/autocomplete-shared": "1.17.9" }, "peerDependencies": { "search-insights": ">= 1 < 3" } }, "node_modules/@algolia/autocomplete-preset-algolia": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", - "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.9.tgz", + "integrity": "sha512-Na1OuceSJeg8j7ZWn5ssMu/Ax3amtOwk76u4h5J4eK2Nx2KB5qt0Z4cOapCsxot9VcEN11ADV5aUSlQF4RhGjQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/autocomplete-shared": "1.9.3" + "@algolia/autocomplete-shared": "1.17.9" }, "peerDependencies": { "@algolia/client-search": ">= 4.9.1 < 6", @@ -103,9 +88,9 @@ } }, "node_modules/@algolia/autocomplete-shared": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", - "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.9.tgz", + "integrity": "sha512-iDf05JDQ7I0b7JEA/9IektxN/80a2MZ1ToohfmNS3rfeuQnIKI3IJlIafD0xu4StbtQTghx9T3Maa97ytkXenQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -113,206 +98,266 @@ "algoliasearch": ">= 4.9.1 < 6" } }, - "node_modules/@algolia/cache-browser-local-storage": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", - "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==", + "node_modules/@algolia/client-abtesting": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.27.0.tgz", + "integrity": "sha512-SITU5umoknxETtw67TxJu9njyMkWiH8pM+Bvw4dzfuIrIAT6Y1rmwV4y0A0didWoT+6xVuammIykbtBMolBcmg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/cache-common": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/cache-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz", - "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@algolia/cache-in-memory": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz", - "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==", + "node_modules/@algolia/client-analytics": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.27.0.tgz", + "integrity": "sha512-go1b9qIZK5vYEQ7jD2bsfhhhVsoh9cFxQ5xF8TzTsg2WOCZR3O92oXCkq15SOK0ngJfqDU6a/k0oZ4KuEnih1Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/cache-common": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/client-account": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz", - "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==", + "node_modules/@algolia/client-common": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.27.0.tgz", + "integrity": "sha512-tnFOzdNuMzsz93kOClj3fKfuYoF3oYaEB5bggULSj075GJ7HUNedBEm7a6ScrjtnOaOtipbnT7veUpHA4o4wEQ==", "dev": true, "license": "MIT", - "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/transporter": "4.24.0" + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/client-analytics": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz", - "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==", + "node_modules/@algolia/client-insights": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.27.0.tgz", + "integrity": "sha512-y1qgw39qZijjQBXrqZTiwK1cWgWGRiLpJNWBv9w36nVMKfl9kInrfsYmdBAfmlhVgF/+Woe0y1jQ7pa4HyShAw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", + "node_modules/@algolia/client-personalization": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.27.0.tgz", + "integrity": "sha512-XluG9qPZKEbiLoIfXTKbABsWDNOMPx0t6T2ImJTTeuX+U/zBdmfcqqgcgkqXp+vbXof/XX/4of9Eqo1JaqEmKw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/client-personalization": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz", - "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==", + "node_modules/@algolia/client-query-suggestions": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.27.0.tgz", + "integrity": "sha512-V8/To+SsAl2sdw2AAjeLJuCW1L+xpz+LAGerJK7HKqHzE5yQhWmIWZTzqYQcojkii4iBMYn0y3+uReWqT8XVSQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", - "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.27.0.tgz", + "integrity": "sha512-EJJ7WmvmUXZdchueKFCK8UZFyLqy4Hz64snNp0cTc7c0MKaSeDGYEDxVsIJKp15r7ORaoGxSyS4y6BGZMXYuCg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/logger-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz", - "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==", + "node_modules/@algolia/ingestion": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.27.0.tgz", + "integrity": "sha512-xNCyWeqpmEo4EdmpG57Fs1fJIQcPwt5NnJ6MBdXnUdMVXF4f5PHgza+HQWQQcYpCsune96jfmR0v7us6gRIlCw==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" + } }, - "node_modules/@algolia/logger-console": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz", - "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==", + "node_modules/@algolia/monitoring": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.27.0.tgz", + "integrity": "sha512-P0NDiEFyt9UYQLBI0IQocIT7xHpjMpoFN3UDeerbztlkH9HdqT0GGh1SHYmNWpbMWIGWhSJTtz6kSIWvFu4+pw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/logger-common": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz", - "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.27.0.tgz", + "integrity": "sha512-cqfTMF1d1cc7hg0vITNAFxJZas7MJ4Obc36WwkKpY23NOtGb+4tH9X7UKlQa2PmTgbXIANoJ/DAQTeiVlD2I4Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/cache-browser-local-storage": "4.24.0", - "@algolia/cache-common": "4.24.0", - "@algolia/cache-in-memory": "4.24.0", - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/logger-console": "4.24.0", - "@algolia/requester-browser-xhr": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/requester-node-http": "4.24.0", - "@algolia/transporter": "4.24.0" + "@algolia/client-common": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", - "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.27.0.tgz", + "integrity": "sha512-ErenYTcXl16wYXtf0pxLl9KLVxIztuehqXHfW9nNsD8mz9OX42HbXuPzT7y6JcPiWJpc/UU/LY5wBTB65vsEUg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/requester-common": "4.24.0" + "@algolia/client-common": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/requester-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz", - "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@algolia/requester-node-http": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", - "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", + "node_modules/@algolia/requester-fetch": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.27.0.tgz", + "integrity": "sha512-CNOvmXsVi+IvT7z1d+6X7FveVkgEQwTNgipjQCHTIbF9KSMfZR7tUsJC+NpELrm10ALdOMauah84ybs9rw1cKQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/requester-common": "4.24.0" + "@algolia/client-common": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/@algolia/transporter": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz", - "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==", + "node_modules/@algolia/requester-node-http": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.27.0.tgz", + "integrity": "sha512-Nx9EdLYZDsaYFTthqmc0XcVvsx6jqeEX8fNiYOB5i2HboQwl8pJPj1jFhGqoGd0KG7KFR+sdPO5/e0EDDAru2Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/cache-common": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/requester-common": "4.24.0" + "@algolia/client-common": "5.27.0" + }, + "engines": { + "node": ">= 14.0.0" } }, + "node_modules/@altano/repository-tools": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@altano/repository-tools/-/repository-tools-0.1.1.tgz", + "integrity": "sha512-5vbUs2A98CC3g1AlOBdkBE0BMukkLjLIsMHAtuxg6Pt9dQXxYWdLKOf66v6c/vIqtNcgTMv0oGtddLdMuH9X6w==", + "dev": true, + "license": "ISC" + }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, + "node_modules/@babel/generator": { + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.5.tgz", + "integrity": "sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.27.5", + "@babel/types": "^7.27.3", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "version": "7.27.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.5.tgz", + "integrity": "sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -321,82 +366,73 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.6.tgz", + "integrity": "sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==", "dev": true, "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "version": "7.27.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.6.tgz", + "integrity": "sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", "dev": true, - "optional": true, + "license": "MIT", "engines": { - "node": ">=0.1.90" + "node": ">=18" } }, "node_modules/@docsearch/css": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.1.tgz", - "integrity": "sha512-VtVb5DS+0hRIprU2CO6ZQjK2Zg4QU5HrDM1+ix6rT0umsYvFvatMAnf97NHZlVWDaaLlx7GRfR/7FikANiM2Fg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.9.0.tgz", + "integrity": "sha512-cQbnVbq0rrBwNAKegIac/t6a8nWoUAn8frnkLFW6YARaRmAQr5/Eoe6Ln2fqkUCZ40KpdrKbpSAmgrkviOxuWA==", "dev": true, "license": "MIT" }, "node_modules/@docsearch/js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.6.1.tgz", - "integrity": "sha512-erI3RRZurDr1xES5hvYJ3Imp7jtrXj6f1xYIzDzxiS7nNBufYWPbJwrmMqWC5g9y165PmxEmN9pklGCdLi0Iqg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.9.0.tgz", + "integrity": "sha512-4bKHcye6EkLgRE8ze0vcdshmEqxeiJM77M0JXjef7lrYZfSlMunrDOCqyLjiZyo1+c0BhUqA2QpFartIjuHIjw==", "dev": true, "license": "MIT", "dependencies": { - "@docsearch/react": "3.6.1", + "@docsearch/react": "3.9.0", "preact": "^10.0.0" } }, "node_modules/@docsearch/react": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.1.tgz", - "integrity": "sha512-qXZkEPvybVhSXj0K7U3bXc233tk5e8PfhoZ6MhPOiik/qUQxYC+Dn9DnoS7CxHQQhHfCvTiN0eY9M12oRghEXw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.9.0.tgz", + "integrity": "sha512-mb5FOZYZIkRQ6s/NWnM98k879vu5pscWqTLubLFBO87igYYT4VzVazh4h5o/zCvTIZgEt3PvsCOMOswOUo9yHQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/autocomplete-core": "1.9.3", - "@algolia/autocomplete-preset-algolia": "1.9.3", - "@docsearch/css": "3.6.1", - "algoliasearch": "^4.19.1" + "@algolia/autocomplete-core": "1.17.9", + "@algolia/autocomplete-preset-algolia": "1.17.9", + "@docsearch/css": "3.9.0", + "algoliasearch": "^5.14.2" }, "peerDependencies": { - "@types/react": ">= 16.8.0 < 19.0.0", - "react": ">= 16.8.0 < 19.0.0", - "react-dom": ">= 16.8.0 < 19.0.0", + "@types/react": ">= 16.8.0 < 20.0.0", + "react": ">= 16.8.0 < 20.0.0", + "react-dom": ">= 16.8.0 < 20.0.0", "search-insights": ">= 1 < 3" }, "peerDependenciesMeta": { @@ -414,10 +450,44 @@ } } }, + "node_modules/@emnapi/core": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", + "integrity": "sha512-4m62DuCE07lw01soJwPiBGC0nAww0Q+RY70VZ+n49yDIO13yyinhbWCeNnaob0lakDtWQzSdtNWzJeOJt2ma+g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.2.tgz", + "integrity": "sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], @@ -428,13 +498,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], @@ -445,13 +515,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], @@ -462,13 +532,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], @@ -479,13 +549,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], @@ -496,13 +566,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], @@ -513,13 +583,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], @@ -530,13 +600,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], @@ -547,13 +617,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], @@ -564,13 +634,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], @@ -581,13 +651,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], @@ -598,13 +668,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], @@ -615,13 +685,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], @@ -632,13 +702,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], @@ -649,13 +719,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], @@ -666,13 +736,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], @@ -683,13 +753,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], @@ -700,13 +770,30 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], @@ -717,13 +804,13 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", "cpu": [ "arm64" ], @@ -738,9 +825,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], @@ -751,13 +838,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", "cpu": [ "x64" ], @@ -768,13 +855,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], @@ -785,13 +872,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], @@ -802,13 +889,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], @@ -819,266 +906,279 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "node_modules/@eslint-community/regexpp": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.7.0.tgz", - "integrity": "sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@feathers-plus/batch-loader": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.6.tgz", - "integrity": "sha512-r+n31iZ/B5Rl1mLkC9/S20UI445MdkZvE3VBmjupep2t8OuyTYHPkFEgR25HY6khH+RothK1VL3B5eumk9N2QQ==", - "dev": true, - "engines": { - "node": ">= 6.0.0" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@feathers-plus/cache": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/cache/-/cache-1.4.0.tgz", - "integrity": "sha512-jkUCfrYX/aBrIZ3hKGnJGUELtSYTGVZFBo2MJvVeonW9BXCHTKwzY6HkmVbzMhzSRMAdeo98nvpsz1d2QbURdw==", + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "lru-cache": "4.1.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 6.0.0" + "node": "*" } }, - "node_modules/@feathers-plus/common": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/common/-/common-0.1.0.tgz", - "integrity": "sha512-rK4zNVObmw8UKP7nwTwsCVn0g2Zl92r2rpXMfVdFo8FmYfYY4HECAcGB4Aq38EI6NZnvla51CdDjtY9WxW1OHQ==", + "node_modules/@eslint/config-helpers": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.2.tgz", + "integrity": "sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==", "dev": true, - "dependencies": { - "short-hash": "1.0.0", - "sort-keys": "2.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">= 6.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@feathers-plus/graphql": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/graphql/-/graphql-1.10.0.tgz", - "integrity": "sha512-ausYkHTRRxIQbNKVvQ7dHj/bkNsghsjGGKw9PO+w9XOCs6OJouO/cj1nj6RjfUDxUbZtFcc4y5QluYzDulEmEQ==", - "deprecated": "This module is no longer maintained", + "node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@feathers-plus/batch-loader": "0.3.0", - "@feathers-plus/cache": "1.3.1", - "@feathers-plus/common": "0.1.0", - "@feathersjs/errors": "3.2.0", - "debug": "3.1.0", - "feathers-hooks-common": "4.5.6", - "graphql": "0.11.7", - "graphql-resolvers-ast": "1.4.0", - "graphql-tools": "2.0.0", - "graphql-type-json": "0.1.4", - "join-monster": "2.0.15", - "join-monster-graphql-tools-adapter": "0.0.2", - "lodash.merge": "4.6.1", - "mongo-sql": "4.0.2", - "traverse": "0.6.6" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/@feathers-plus/graphql/node_modules/@feathers-plus/batch-loader": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.0.tgz", - "integrity": "sha512-buElwyOZKVI34kD7jHt+czIDv1brjXLBPJ+7is+RC98JK+TyqWIUuBJ4E0ZMjPxwwkAJIN6IATyPgvhSXhkaxw==", - "dev": true, - "engines": { - "node": ">= 6.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@feathers-plus/graphql/node_modules/@feathers-plus/cache": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@feathers-plus/cache/-/cache-1.3.1.tgz", - "integrity": "sha512-zFpwVutKiOcPW6Gnm73uit4EwnaawYZEt6pIKP+GkYQz/wVkfNMMwZ28THCNhZvFcR1Cn3WwyUBXcASoApHpvA==", + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "4.1.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">= 6.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@feathers-plus/graphql/node_modules/@feathersjs/errors": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-3.2.0.tgz", - "integrity": "sha512-4xsE7OyzxGvs2hyG19nf2qb4rV2nWoWbQ6/FnDIYrNHi7M9kOy+deLwNhKnXa4r/hg3xf+AVpC8kBjUQjWYWHA==", + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^3.1.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "engines": { - "node": ">= 6" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@feathers-plus/graphql/node_modules/debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@feathers-plus/graphql/node_modules/graphql": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.11.7.tgz", - "integrity": "sha512-x7uDjyz8Jx+QPbpCFCMQ8lltnQa4p4vSYHx6ADe8rVYRTdsyhCJbvSty5DAsLVmU6cGakl+r8HQYolKHxk/tiw==", + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, - "dependencies": { - "iterall": "1.1.3" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@feathers-plus/graphql/node_modules/graphql-relay": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/graphql-relay/-/graphql-relay-0.5.5.tgz", - "integrity": "sha512-CTsapMI0MZc0antZp+9ZcVcNiVoaXncc2xALCxe2Md25quAUxTjH2135xPRNb6BMOoTiY54HtglfxxUCDTUEbA==", + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, - "peerDependencies": { - "graphql": "^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0-b || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0" + "license": "MIT", + "engines": { + "node": ">= 4" } }, - "node_modules/@feathers-plus/graphql/node_modules/graphql-tools": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-2.0.0.tgz", - "integrity": "sha512-5cUflK/kECqge0feZxTG/cF05EHlGMvdK47I+xQtDm67KrW8rlfmLTUWHYcyFTOXT+Yl4Sb/6WTJZwnKX+Ofmg==", - "deprecated": "This package has been deprecated and now it only exports makeExecutableSchema.\\nAnd it will no longer receive updates.\\nWe recommend you to migrate to scoped packages such as @graphql-tools/schema, @graphql-tools/utils and etc.\\nCheck out https://www.graphql-tools.com to learn what package you should use instead", + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "deprecated-decorator": "^0.1.6", - "uuid": "^3.1.0" + "brace-expansion": "^1.1.7" }, - "optionalDependencies": { - "@types/graphql": "^0.11.4" + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.28.0.tgz", + "integrity": "sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependencies": { - "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0" + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@feathers-plus/graphql/node_modules/join-monster": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/join-monster/-/join-monster-2.0.15.tgz", - "integrity": "sha512-4ZZd0grGtamGsevMP4iCF+dZ5jyeuvbvEgF5LgPp9Gz1VNUTaL79/ZNfc0Hs/uSNJAVj1vbaUGK/wsnopyYLkA==", + "node_modules/@eslint/plugin-kit": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.1.tgz", + "integrity": "sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@stem/nesthydrationjs": "0.4.0", - "debug": "^3.0.1", - "deprecate": "^1.0.0", - "generatorics": "^1.0.8", - "graphql-relay": "^0.5.0", - "lodash": "^4.13.1" + "@eslint/core": "^0.14.0", + "levn": "^0.4.1" }, "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "graphql": "0.6 || 0.7 || 0.8 || 0.9 || 0.10 || 0.11" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@feathers-plus/graphql/node_modules/join-monster-graphql-tools-adapter": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/join-monster-graphql-tools-adapter/-/join-monster-graphql-tools-adapter-0.0.2.tgz", - "integrity": "sha512-Q2DaeL/L6yY7Rh30YvkysB48QdPwbMBElo72gXelDOczymw0DzP1jmrvLuClyxeL5FJs5tt28CHKIKEgYwFAbA==", + "node_modules/@feathers-community/eslint-config": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@feathers-community/eslint-config/-/eslint-config-0.0.7.tgz", + "integrity": "sha512-HhZ08KT5SKzRvDQ3ZCoepc5ZOhrYTBbAsjnq1oBQ8qe4jWwGlfT8AFMFzQsqE/7mJq0dVYfLnj8Jx0+Tntee2Q==", "dev": true, + "license": "MIT", + "dependencies": { + "@eslint/js": "^9.28.0", + "@typescript-eslint/eslint-plugin": "^8.33.1", + "@typescript-eslint/parser": "^8.33.1", + "eslint-config-prettier": "^10.1.5", + "eslint-import-resolver-typescript": "^4.4.2", + "eslint-plugin-import-x": "^4.15.1", + "eslint-plugin-package-json": "^0.33.2", + "eslint-plugin-prettier": "^5.4.1", + "eslint-plugin-unicorn": "^59.0.1", + "eslint-plugin-unused-imports": "^4.1.4", + "globals": "^16.2.0", + "typescript-eslint": "^8.33.1" + }, "peerDependencies": { - "graphql-tools": "^0.4.0", - "join-monster": "*" + "eslint": "^9.0.0" } }, - "node_modules/@feathers-plus/graphql/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/@feathers-plus/graphql/node_modules/traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==", - "dev": true - }, - "node_modules/@feathers-plus/graphql/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "node_modules/@feathers-plus/cache": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@feathers-plus/cache/-/cache-1.4.0.tgz", + "integrity": "sha512-jkUCfrYX/aBrIZ3hKGnJGUELtSYTGVZFBo2MJvVeonW9BXCHTKwzY6HkmVbzMhzSRMAdeo98nvpsz1d2QbURdw==", "dev": true, - "bin": { - "uuid": "bin/uuid" + "license": "MIT", + "dependencies": { + "lru-cache": "4.1.1" + }, + "engines": { + "node": ">= 6.0.0" } }, "node_modules/@feathersjs/adapter-commons": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-5.0.29.tgz", - "integrity": "sha512-9D0He+VqkUoYaSbfav4Rg0DMCVXtGmPNNxRO5QDJqbJ7U4deozCru3+qWMIVAYRXc5jiX0x2iFbSVOoMoFf78Q==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-5.0.34.tgz", + "integrity": "sha512-wc0HAZ0uov68p1ytBR5npyAePdNbFrRqr1fINSpLvIkrUkKDEcC6I/lOpk1TBpoI8so5IO/seZhkl25pqKM43A==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29" + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34" }, "engines": { "node": ">= 12" @@ -1089,23 +1189,23 @@ } }, "node_modules/@feathersjs/authentication": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication/-/authentication-5.0.29.tgz", - "integrity": "sha512-kYC1x1etmZ9Q9EZXd6bbMlk1myaHS5TsW3kOty0m6amG9BDcFdEyh9ij/JgVuL0EJ+7KOHweOypdJ3bIpiinqQ==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication/-/authentication-5.0.34.tgz", + "integrity": "sha512-JnOoYJKx60SQDCj/JJAH9wzAL0EFFMaOjBN5Vh8JVTj1L4IrxUfy7uGathBumQc5vB2BqtyCy4BG8+/L49oQbA==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", "@feathersjs/hooks": "^0.9.0", - "@feathersjs/schema": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29", - "@types/jsonwebtoken": "^9.0.6", + "@feathersjs/schema": "^5.0.34", + "@feathersjs/transport-commons": "^5.0.34", + "@types/jsonwebtoken": "^9.0.9", "jsonwebtoken": "^9.0.2", "lodash": "^4.17.21", "long-timeout": "^0.1.1", - "uuid": "^10.0.0" + "uuid": "^11.1.0" }, "engines": { "node": ">= 12" @@ -1116,16 +1216,16 @@ } }, "node_modules/@feathersjs/authentication-client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication-client/-/authentication-client-5.0.29.tgz", - "integrity": "sha512-F0aIJPYLSvDJOnPBqhXOT1UUD/IAxJ2u8xdKGDY+sWGpqCIDMl32PDqImilqC8+G+/BmKJ8Rjhe81oXEbbhOBw==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication-client/-/authentication-client-5.0.34.tgz", + "integrity": "sha512-j+p88bnyZmOHelpiL3AbTee0gsEDF5G3/vyJm0x157Q3Y3vXsI4LU7n7Go3cbrjNkCpdqV0pn8CiaxFgQ2lteA==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29" + "@feathersjs/authentication": "^5.0.34", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34" }, "engines": { "node": ">= 12" @@ -1136,17 +1236,17 @@ } }, "node_modules/@feathersjs/authentication-local": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication-local/-/authentication-local-5.0.29.tgz", - "integrity": "sha512-Xkv1oCxn4eZGFWM61Wgo0ghabJIHg0xhkr5zy3glTDZFzqmS8xsoRyQufBnzEd8zMQlw09AK/YbFRNWUc8lNIQ==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/authentication-local/-/authentication-local-5.0.34.tgz", + "integrity": "sha512-3swHyoz/kW3lTAoGRNT1Y49PXy+wx1/bgw5AQpExLanLuXipevuKHapLvlDUh914bz8vw6FmC/5TnFwxrx8OOQ==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "bcryptjs": "^2.4.3", + "@feathersjs/authentication": "^5.0.34", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", + "bcryptjs": "^3.0.2", "lodash": "^4.17.21" }, "engines": { @@ -1158,17 +1258,17 @@ } }, "node_modules/@feathersjs/client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/client/-/client-5.0.29.tgz", - "integrity": "sha512-JzzmuBwHR//NhFBGZsadelpMPz0U3UX/FbOrveUiFrACYdk2MkkUwaIJFlWhFIU8gQJrSDDbGIgnMjEwV9XrXA==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/client/-/client-5.0.34.tgz", + "integrity": "sha512-6ZFnETydjXH4wHwSB6TwiYUQ2qHhKhcw8finyA7A845yVSbQQYns5pTPNCHFG2GPpZpb43I6RZuP//HRfN5AIw==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/authentication-client": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/rest-client": "^5.0.29", - "@feathersjs/socketio-client": "^5.0.29" + "@feathersjs/authentication-client": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", + "@feathersjs/rest-client": "^5.0.34", + "@feathersjs/socketio-client": "^5.0.34" }, "engines": { "node": ">= 12" @@ -1179,9 +1279,9 @@ } }, "node_modules/@feathersjs/commons": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-5.0.29.tgz", - "integrity": "sha512-Gr2c0XxBTQ/+SoH8bAxJO1rUzBrFExQmK7Wdasp9g/xwS0InCNLPHhrrNc2KwTVSx8kbsN+GZRBkzytmxgWM0w==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-5.0.34.tgz", + "integrity": "sha512-UfHzq7taVJx++TXxX5pmDSR72xRp+h5nler4xcUlcJWLLykCOYo8YCeW03S7T1p1NuFdy0qBmU+B+G89bjyGmg==", "license": "MIT", "engines": { "node": ">= 12" @@ -1192,33 +1292,33 @@ } }, "node_modules/@feathersjs/errors": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-5.0.29.tgz", - "integrity": "sha512-SLpvC36V84XKxucAtDC70GXkqmsvTE5SO4uSZXuTpK68VqeefbmSY+KSid2DY9dM0upZN7orwVBB5YciUMCIIg==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-5.0.34.tgz", + "integrity": "sha512-C0t+pONnMvwlDW6iczcYmxaHzGvaGn3+BLhwlySEVYRciWOURIO8Eo5JVdN7cSM3Z7AxS3Dpk4DEhyFU/D2w6w==", "license": "MIT", "engines": { "node": ">= 12" } }, "node_modules/@feathersjs/express": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/express/-/express-5.0.29.tgz", - "integrity": "sha512-PvbzAuolHZEL2VBQRyuMVhsa9LVM7HuN6nXyGFv7IqSr7t61i3v5BuWbn4SQ6EO88NVHDnb7DZT7ojDVhU6YFw==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/express/-/express-5.0.34.tgz", + "integrity": "sha512-TNy8vEIYnjB9eEwancP07C5wYnv5i1vXctKH9HhtIfa1xJ7KnGgIDT9LNO4gX0OeURzDcE+zFEB9Xnto6zKh4g==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29", + "@feathersjs/authentication": "^5.0.34", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", + "@feathersjs/transport-commons": "^5.0.34", "@types/compression": "^1.7.5", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/express-serve-static-core": "^4.19.5", - "compression": "^1.7.4", + "compression": "^1.8.0", "cors": "^2.8.5", - "express": "^4.19.2" + "express": "^4.21.2" }, "engines": { "node": ">= 12" @@ -1229,12 +1329,12 @@ } }, "node_modules/@feathersjs/feathers": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-5.0.29.tgz", - "integrity": "sha512-ERY0W0FfZUysIksdwbBhXZot1F1EuLtlhJA27o9VN9EWIh6IHlT30McyqQqdqTiqVhsOS+KJPLTeGPH60REg+Q==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-5.0.34.tgz", + "integrity": "sha512-jgeqKq/Uhsfeld42F8uimqzPv/uhtohkenpaWeD+NudJp2YZNYfA6gDZAL5UTpAvrTJFmK3QR1q1CnuL1mJdHg==", "license": "MIT", "dependencies": { - "@feathersjs/commons": "^5.0.29", + "@feathersjs/commons": "^5.0.34", "@feathersjs/hooks": "^0.9.0", "events": "^3.3.0" }, @@ -1256,15 +1356,15 @@ } }, "node_modules/@feathersjs/memory": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/memory/-/memory-5.0.29.tgz", - "integrity": "sha512-szi/4WcvwxX8OEi3A/7qUozUzx1ZVIPHX3IEOU9bDnNsDMGWfVlHGOOW3HdSMAOVZWhGR56oMsvXvrAcgdCVRw==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/memory/-/memory-5.0.34.tgz", + "integrity": "sha512-VU9cMdUPNL89FogvkiVPH70cHnDwIBU8mJWz0HMxeehycN3iUIjqmVIUO8Qg6HH4O17oiU/nKqvXgEOdr+L9AQ==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/adapter-commons": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", + "@feathersjs/adapter-commons": "^5.0.34", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", "sift": "^17.1.3" }, "engines": { @@ -1272,17 +1372,17 @@ } }, "node_modules/@feathersjs/rest-client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/rest-client/-/rest-client-5.0.29.tgz", - "integrity": "sha512-fqqZOb4yEZe2Gyrd1/+OyZQkYEwNiwYe4OXd2bVkT60bRBa8zpDUKZrMSTKARvPXzxPKttdrMuOeTmCogHq0KA==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/rest-client/-/rest-client-5.0.34.tgz", + "integrity": "sha512-rWn47ZVLJ6igqbJeKyy6QleZceEjfPtmjR/DI+S1Ph7CAep0Ax2rqkwhSIWIoRnp4A7jFay1M3Jy3tA3Eyk7MQ==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@types/superagent": "^8.1.7", - "qs": "^6.12.3" + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", + "@types/superagent": "^8.1.9", + "qs": "^6.14.0" }, "engines": { "node": ">= 12" @@ -1293,21 +1393,21 @@ } }, "node_modules/@feathersjs/schema": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/schema/-/schema-5.0.29.tgz", - "integrity": "sha512-Eq1wSYyfczJlD7/4mcD5AtNTq3HdjjS191NCJWEurNIKm6MlIssvZXIjMOjnna2A1Vw/80vPIapat65uebEKPg==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/schema/-/schema-5.0.34.tgz", + "integrity": "sha512-BpQxp46Vp0tH7l9jW4HIAGQerql7aJBeRXRggCVhBuqK48KoD1UhvYCWBmWwEouaYUnZ77HjQIMn9c1fK+dF2w==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/adapter-commons": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", + "@feathersjs/adapter-commons": "^5.0.34", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", "@feathersjs/hooks": "^0.9.0", "@types/json-schema": "^7.0.15", - "ajv": "^8.16.0", + "ajv": "^8.17.1", "ajv-formats": "^3.0.1", - "json-schema-to-ts": "^3.1.0" + "json-schema-to-ts": "^3.1.1" }, "engines": { "node": ">= 12" @@ -1317,44 +1417,20 @@ "url": "https://github.com/sponsors/daffl" }, "peerDependencies": { - "typescript": ">=5.5" - } - }, - "node_modules/@feathersjs/schema/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "typescript": ">=5.8" } }, - "node_modules/@feathersjs/schema/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, "node_modules/@feathersjs/socketio": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/socketio/-/socketio-5.0.29.tgz", - "integrity": "sha512-xtHtWAoEgOEgTYmiEKyqEC10DLbZ51U3mMluQPknsGgH1W2+GgI7WwCAVyM3ZPcVFlUwmVa62/GsIznOs33Hjg==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/socketio/-/socketio-5.0.34.tgz", + "integrity": "sha512-uT94CeSRcnhOIThjiFg/wU30koVPoPrJUHyiQia3Q9sSB5wcaoWaJAIUcOEIZmGrgW2FNLPRw9THpAUTIgd4/w==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29", - "socket.io": "^4.7.5" + "@feathersjs/commons": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", + "@feathersjs/transport-commons": "^5.0.34", + "socket.io": "^4.8.1" }, "engines": { "node": ">= 12" @@ -1365,14 +1441,14 @@ } }, "node_modules/@feathersjs/socketio-client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/socketio-client/-/socketio-client-5.0.29.tgz", - "integrity": "sha512-6jw4YCTZ35dwBT1DEvI9CkB99lND02Wk8WfU6xf2Ss1ZBU1oNl1zqVZTECHiuvYp4akPRMS9HIZFm1DK8qLEOQ==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/socketio-client/-/socketio-client-5.0.34.tgz", + "integrity": "sha512-7mejzCX/lotsKFZaRrL1KA/lIuI/m1iPxy+5I7Fb+PLpRQUWAdNcCJPk/TutyXm+ksFNliPe2hB6qiXpKeqg3Q==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29" + "@feathersjs/feathers": "^5.0.34", + "@feathersjs/transport-commons": "^5.0.34" }, "engines": { "node": ">= 12" @@ -1383,15 +1459,15 @@ } }, "node_modules/@feathersjs/transport-commons": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/transport-commons/-/transport-commons-5.0.29.tgz", - "integrity": "sha512-Xy7J9h/t9vLqjPnyn3RnNtcS9wBDp/VfdVYulC0hnpEBFKwDtyjx055rUgrNn8r1B4w0y8CyX02MNSupABgOiQ==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@feathersjs/transport-commons/-/transport-commons-5.0.34.tgz", + "integrity": "sha512-l+oQm1oIvfrxNUlidcqCtKfdWdKn1zHXGhEa13xIKiU5m2LFz1EYeMuq5vh/1pU0iECq3Oi+KdW53YnGl446cw==", "dev": true, "license": "MIT", "dependencies": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", + "@feathersjs/commons": "^5.0.34", + "@feathersjs/errors": "^5.0.34", + "@feathersjs/feathers": "^5.0.34", "encodeurl": "^2.0.0", "lodash": "^4.17.21" }, @@ -1403,18 +1479,69 @@ "url": "https://github.com/sponsors/daffl" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@floating-ui/core": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.1.tgz", + "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", "dev": true, + "license": "MIT", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.1.1.tgz", + "integrity": "sha512-TpIO93+DIujg3g7SykEAGZMDtbJRrmnYRCNYSjJlvIbGhBjRSNTLVbNeDQBrzy9qDgUbiWdc7KA0uZHZ2tJmiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.1.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -1422,6 +1549,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -1430,17 +1558,43 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.38", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.38.tgz", + "integrity": "sha512-mvMeFQgVjoHanQE9Q7ihmriEXAorjLZW+crUgQspDjFpzWuQp2RZMTppl1MN6TQztMVTsNFgF6LDKsp+v1RYRg==", + "dev": true, + "license": "CC0-1.0", + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1454,10 +1608,11 @@ } }, "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -1465,17 +1620,32 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1493,6 +1663,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1503,65 +1674,88 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@sinclair/typebox": "^0.27.8" + "minipass": "^7.0.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", @@ -1574,14 +1768,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.10.tgz", + "integrity": "sha512-bCsCyeZEwVErsGmyPNSzwfwFn4OdxBj0mmv6hOFucB/k81Ojdu68RbZdxYsRQUPc9l6SU5F/cG+bXgWs3oUgsQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { - "sparse-bitfield": "^3.0.3" + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.9.0" } }, "node_modules/@nodelib/fs.scandir": { @@ -1589,6 +1786,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1602,6 +1800,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1611,6 +1810,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1619,196 +1819,248 @@ "node": ">= 8" } }, - "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "node_modules/@oxc-project/runtime": { + "version": "0.72.2", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.72.2.tgz", + "integrity": "sha512-J2lsPDen2mFs3cOA1gIBd0wsHEhum2vTnuKIRwmj3HJJcIz/XgeNdzvgSOioIXOJgURIpcDaK05jwaDG1rhDwg==", "dev": true, - "dependencies": { - "semver": "^7.3.5" - }, + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=6.9.0" } }, - "node_modules/@npmcli/git": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", - "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "node_modules/@oxc-project/types": { + "version": "0.72.2", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.72.2.tgz", + "integrity": "sha512-il5RF8AP85XC0CMjHF4cnVT9nT/v/ocm6qlZQpSiAR9qBbQMGkFKloBZwm7PcnOdiUX97yHgsKM7uDCCWCu3tg==", "dev": true, - "dependencies": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@npmcli/git/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", + "optional": true, "engines": { - "node": ">=12" + "node": ">=14" } }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/@pkgr/core": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.7.tgz", + "integrity": "sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "node_modules/@quansync/fs": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@quansync/fs/-/fs-0.1.3.tgz", + "integrity": "sha512-G0OnZbMWEs5LhDyqy2UL17vGhSVHkQIfVojMtEWVenvj0V5S84VBgy86kJIuNsGDp2p7sTKlpSIpBUWdC35OKg==", "dev": true, + "license": "MIT", "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "bin": { - "installed-package-contents": "lib/index.js" + "quansync": "^0.2.10" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-Hlt/h+lOJ+ksC2wED2M9Hku/9CA2Hr17ENK82gNMmi3OqwcZLdZFqJDpASTli65wIOeT4p9rIUMdkfshCoJpYA==", + "cpu": [ + "arm64" + ], "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@npmcli/promise-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", - "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-Bnst+HBwhW2YrNybEiNf9TJkI1myDgXmiPBVIOS0apzrLCmByzei6PilTClOpTpNFYB+UviL3Ox2gKUmcgUjGw==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-3jAxVmYDPc8vMZZOfZI1aokGB9cP6VNeU9XNCx0UJ6ShlSPK3qkAa0sWgueMhaQkgBVf8MOfGpjo47ohGd7QrA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] }, - "node_modules/@npmcli/run-script": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", - "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-TpUltUdvcsAf2WvXXD8AVc3BozvhgazJ2gJLXp4DVV2V82m26QelI373Bzx8d/4hB167EEIg4wWW/7GXB/ltoQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@npmcli/run-script/node_modules/which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-eGvHnYQSdbdhsTdjdp/+83LrN81/7X9HD6y3jg7mEmdsicxEMEIt6CsP7tvYS/jn4489jgO/6mLxW/7Vg+B8pw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-0NJZWXJls83FpBRzkTbGBsXXstaQLsfodnyeOghxbnNdsjn+B4dcNPpMK5V3QDsjC0pNjDLaDdzB2jWKlZbP/Q==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", "optional": true, - "engines": { - "node": ">=14" - } + "os": [ + "linux" + ] }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-9vXnu27r4zgS/BHP6RCLBOrJoV2xxtLYHT68IVpSOdCkBHGpf1oOJt6blv1y5NRRJBEfAFCvj5NmwSMhETF96w==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@pnpm/network.ca-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", - "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-e6tvsZbtHt4kzl82oCajOUxwIN8uMfjhuQ0qxIVRzPekRRjKEzyH9agYPW6toN0cnHpkhPsu51tyZKJOdUl7jg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "graceful-fs": "4.2.10" - }, - "engines": { - "node": ">=12.22.0" - } + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@pnpm/npm-conf": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", - "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-nBQVizPoUQiViANhWrOyihXNf2booP2iq3S396bI1tmHftdgUXWKa6yAoleJBgP0oF0idXpTPU82ciaROUcjpg==", + "cpu": [ + "wasm32" + ], "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" + "@napi-rs/wasm-runtime": "^0.2.10" }, "engines": { - "node": ">=12" + "node": ">=14.21.3" } }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-Rey/ECXKI/UEykrKfJX3oVAPXDH2k1p2BKzYGza0z3S2X5I3sTDOeBn2I0IQgyyf7U3+DCBhYjkDFnmSePrU/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/binding-win32-ia32-msvc": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-LtuMKJe6iFH4iV55dy+gDwZ9v23Tfxx5cd7ZAxvhYFGoVNSvarxAgl844BvFGReERCnLTGRvo85FUR6fDHQX+A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-YY8UYfBm4dbWa4psgEPPD9T9X0nAvlYu0BOsQC5vDfCwzzU7IHT4jAfetvlQq+4+M6qWHSTr6v+/WX5EmlM1WA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-TAqMYehvpauLKz7v4TZOTUQNjxa5bUQWw2+51/+Zk3ItclBxgoSWhnZ31sXjdoX6le6OXdK2vZfV3KoyW/O/GA==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", - "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", "cpu": [ "arm" ], @@ -1820,9 +2072,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", - "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", "cpu": [ "arm64" ], @@ -1834,9 +2086,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", - "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", "cpu": [ "arm64" ], @@ -1848,9 +2100,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", - "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", "cpu": [ "x64" ], @@ -1861,10 +2113,38 @@ "darwin" ] }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", - "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", "cpu": [ "arm" ], @@ -1876,9 +2156,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", - "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", "cpu": [ "arm" ], @@ -1890,9 +2170,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", - "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", "cpu": [ "arm64" ], @@ -1904,9 +2184,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", - "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", "cpu": [ "arm64" ], @@ -1917,10 +2197,24 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", - "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", "cpu": [ "ppc64" ], @@ -1932,9 +2226,23 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", - "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", "cpu": [ "riscv64" ], @@ -1946,9 +2254,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", - "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", "cpu": [ "s390x" ], @@ -1960,9 +2268,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", - "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", + "integrity": "sha512-cWBOvayNvA+SyeQMp79BHPK8ws6sHSsYnK5zDcsC3Hsxr1dgTABKjMnMslPq1DvZIp6uO7kIWhiGwaTdR4Og9A==", "cpu": [ "x64" ], @@ -1974,9 +2282,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", - "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.41.1.tgz", + "integrity": "sha512-y5CbN44M+pUCdGDlZFzGGBSKCA4A/J2ZH4edTYSSxFg7ce1Xt3GtydbVKWLlzL+INfFIZAEg1ZV6hh9+QQf9YQ==", "cpu": [ "x64" ], @@ -1988,9 +2296,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", - "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", "cpu": [ "arm64" ], @@ -2002,9 +2310,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", - "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", "cpu": [ "ia32" ], @@ -2016,9 +2324,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz", - "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", "cpu": [ "x64" ], @@ -2030,92 +2338,123 @@ ] }, "node_modules/@shikijs/core": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.10.3.tgz", - "integrity": "sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.6.0.tgz", + "integrity": "sha512-9By7Xb3olEX0o6UeJyPLI1PE1scC4d3wcVepvtv2xbuN9/IThYN4Wcwh24rcFeASzPam11MCq8yQpwwzCgSBRw==", "dev": true, "license": "MIT", "dependencies": { - "@types/hast": "^3.0.4" + "@shikijs/types": "3.6.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" } }, - "node_modules/@shikijs/transformers": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.10.3.tgz", - "integrity": "sha512-MNjsyye2WHVdxfZUSr5frS97sLGe6G1T+1P41QjyBFJehZphMcr4aBlRLmq6OSPBslYe9byQPVvt/LJCOfxw8Q==", + "node_modules/@shikijs/engine-javascript": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.6.0.tgz", + "integrity": "sha512-7YnLhZG/TU05IHMG14QaLvTW/9WiK8SEYafceccHUSXs2Qr5vJibUwsDfXDLmRi0zHdzsxrGKpSX6hnqe0k8nA==", "dev": true, "license": "MIT", "dependencies": { - "shiki": "1.10.3" + "@shikijs/types": "3.6.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.3" } }, - "node_modules/@sigstore/bundle": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", - "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.6.0.tgz", + "integrity": "sha512-nmOhIZ9yT3Grd+2plmW/d8+vZ2pcQmo/UnVwXMUXAKTXdi+LK0S08Ancrz5tQQPkxvjBalpMW2aKvwXfelauvA==", "dev": true, + "license": "MIT", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "@shikijs/types": "3.6.0", + "@shikijs/vscode-textmate": "^10.0.2" } }, - "node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", + "node_modules/@shikijs/langs": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.6.0.tgz", + "integrity": "sha512-IdZkQJaLBu1LCYCwkr30hNuSDfllOT8RWYVZK1tD2J03DkiagYKRxj/pDSl8Didml3xxuyzUjgtioInwEQM/TA==", "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.6.0" } }, - "node_modules/@sigstore/sign": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", - "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", + "node_modules/@shikijs/themes": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.6.0.tgz", + "integrity": "sha512-Fq2j4nWr1DF4drvmhqKq8x5vVQ27VncF8XZMBuHuQMZvUSS3NBgpqfwz/FoGe36+W6PvniZ1yDlg2d4kmYDU6w==", "dev": true, + "license": "MIT", "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "make-fetch-happen": "^11.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "@shikijs/types": "3.6.0" } }, - "node_modules/@sigstore/tuf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", - "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", + "node_modules/@shikijs/transformers": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-3.6.0.tgz", + "integrity": "sha512-PYkU54lYV0RCaUG8n2FNTF+YWiU3uPhcjLGq2x/C8lIrUX9GVnRb3bK+R5xtdFHbuctntATKm7ondp/H/dux9Q==", "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/core": "3.6.0", + "@shikijs/types": "3.6.0" + } + }, + "node_modules/@shikijs/twoslash": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/twoslash/-/twoslash-3.6.0.tgz", + "integrity": "sha512-AxRxLWtmrVftwxN/2hSL6Hym+bannS+zuUEXpbNuo6BpG4jHTM0KEkICEH3B3Gm5ZNzGdI74NdDiAqAZ6WPJuQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.0", - "tuf-js": "^1.1.7" + "@shikijs/core": "3.6.0", + "@shikijs/types": "3.6.0", + "twoslash": "^0.3.1" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "peerDependencies": { + "typescript": ">=5.5.0" } }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "node_modules/@shikijs/types": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.6.0.tgz", + "integrity": "sha512-cLWFiToxYu0aAzJqhXTQsFiJRTFDAGl93IrMSBNaGSzs7ixkLfdG6pH11HipuWFGW5vyx4X47W8HDQ7eSrmBUg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } }, - "node_modules/@sindresorhus/is": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", - "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==", + "node_modules/@shikijs/vitepress-twoslash": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@shikijs/vitepress-twoslash/-/vitepress-twoslash-3.6.0.tgz", + "integrity": "sha512-pUoRj98UDV41CxfxPysrBryc1/1WdUL93ogcD/s156i4XcujnCfJJc+y5vR3W5Nc1R31VUacwWsI8HhaRRS/uA==", "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "license": "MIT", + "dependencies": { + "@shikijs/twoslash": "", + "floating-vue": "^5.2.2", + "mdast-util-from-markdown": "^2.0.2", + "mdast-util-gfm": "^3.1.0", + "mdast-util-to-hast": "^13.2.0", + "shiki": "3.6.0", + "twoslash": "^0.3.1", + "twoslash-vue": "^0.3.1", + "vue": "^3.5.16" } }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", @@ -2123,86 +2462,299 @@ "dev": true, "license": "MIT" }, - "node_modules/@stem/nesthydrationjs": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@stem/nesthydrationjs/-/nesthydrationjs-0.4.0.tgz", - "integrity": "sha512-hnoLv6W7CmhWXCEp6MBiZv4CdqI48aYmxM+Lo5T3qogP+x+MBR0DOyt7XdppI/X8McqHisCbSNvAOC4fgPhUiw==", + "node_modules/@tailwindcss/node": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.10.tgz", + "integrity": "sha512-2ACf1znY5fpRBwRhMgj9ZXvb2XZW8qs+oTfotJ2C5xR0/WNL7UHZ7zXl6s+rUqedL1mNi+0O+WQr5awGowS3PQ==", "dev": true, + "license": "MIT", "dependencies": { - "lodash": "4.13.1" + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.10" } }, - "node_modules/@stem/nesthydrationjs/node_modules/lodash": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz", - "integrity": "sha512-j/GRONYpkXt1aB1bQHzkq0Th7zhv/syoDVrzCDA3FDMntIin0b7TjXi62q9juDC+QfhRs9COr0LFW38vQSH9Tg==", - "dev": true - }, - "node_modules/@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "node_modules/@tailwindcss/oxide": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.10.tgz", + "integrity": "sha512-v0C43s7Pjw+B9w21htrQwuFObSkio2aV/qPx/mhrRldbqxbWJK6KizM+q7BF1/1CmuLqZqX3CeYF7s7P9fbA8Q==", "dev": true, + "hasInstallScript": true, + "license": "MIT", "dependencies": { - "defer-to-connect": "^2.0.1" + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.10", + "@tailwindcss/oxide-darwin-arm64": "4.1.10", + "@tailwindcss/oxide-darwin-x64": "4.1.10", + "@tailwindcss/oxide-freebsd-x64": "4.1.10", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.10", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.10", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.10", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.10", + "@tailwindcss/oxide-linux-x64-musl": "4.1.10", + "@tailwindcss/oxide-wasm32-wasi": "4.1.10", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.10", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.10" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.10.tgz", + "integrity": "sha512-VGLazCoRQ7rtsCzThaI1UyDu/XRYVyH4/EWiaSX6tFglE+xZB5cvtC5Omt0OQ+FfiIVP98su16jDVHDEIuH4iQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14.16" + "node": ">= 10" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.10.tgz", + "integrity": "sha512-ZIFqvR1irX2yNjWJzKCqTCcHZbgkSkSkZKbRM3BPzhDL/18idA8uWCoopYA2CSDdSGFlDAxYdU2yBHwAwx8euQ==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": ">= 10" } }, - "node_modules/@tufjs/canonical-json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", - "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.10.tgz", + "integrity": "sha512-eCA4zbIhWUFDXoamNztmS0MjXHSEJYlvATzWnRiTqJkcUteSjO94PoRHJy1Xbwp9bptjeIxxBHh+zBWFhttbrQ==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10" } }, - "node_modules/@tufjs/models": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", - "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.10.tgz", + "integrity": "sha512-8/392Xu12R0cc93DpiJvNpJ4wYVSiciUlkiOHOSOQNH3adq9Gi/dtySK7dVQjXIOzlpSHjeCL89RUUI8/GTI6g==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10" } }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.10.tgz", + "integrity": "sha512-t9rhmLT6EqeuPT+MXhWhlRYIMSfh5LZ6kBrC4FS6/+M1yXwfCtp24UumgCWOAJVyjQwG+lYva6wWZxrfvB+NhQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.10.tgz", + "integrity": "sha512-3oWrlNlxLRxXejQ8zImzrVLuZ/9Z2SeKoLhtCu0hpo38hTO2iL86eFOu4sVR8cZc6n3z7eRXXqtHJECa6mFOvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.10.tgz", + "integrity": "sha512-saScU0cmWvg/Ez4gUmQWr9pvY9Kssxt+Xenfx1LG7LmqjcrvBnw4r9VjkFcqmbBb7GCBwYNcZi9X3/oMda9sqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.10.tgz", + "integrity": "sha512-/G3ao/ybV9YEEgAXeEg28dyH6gs1QG8tvdN9c2MNZdUXYBaIY/Gx0N6RlJzfLy/7Nkdok4kaxKPHKJUlAaoTdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.10.tgz", + "integrity": "sha512-LNr7X8fTiKGRtQGOerSayc2pWJp/9ptRYAa4G+U+cjw9kJZvkopav1AQc5HHD+U364f71tZv6XamaHKgrIoVzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.10.tgz", + "integrity": "sha512-d6ekQpopFQJAcIK2i7ZzWOYGZ+A6NzzvQ3ozBvWFdeyqfOZdYHU66g5yr+/HC4ipP1ZgWsqa80+ISNILk+ae/Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], "dev": true, + "license": "MIT", + "optional": true, "dependencies": { - "brace-expansion": "^2.0.1" + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.10", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.10.tgz", + "integrity": "sha512-i1Iwg9gRbwNVOCYmnigWCCgow8nDWSFmeTUU5nbNx3rqbe4p0kRbEqLwLJbYZKmSSp23g4N6rCDmm7OuPBXhDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.10.tgz", + "integrity": "sha512-sGiJTjcBSfGq2DVRtaSljq5ZgZS2SDHSIfhOylkBvHVjwOsodBhnb3HdmiKkVuUGKD0I7G63abMOVaskj1KpOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.10.tgz", + "integrity": "sha512-QWnD5HDY2IADv+vYR82lOhqOlS1jSCUUAmfem52cXAhRTKxpDh3ARX8TTXJTCCO7Rv7cD2Nlekabv02bwP3a2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.10", + "@tailwindcss/oxide": "4.1.10", + "tailwindcss": "4.1.10" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@tsconfig/node22": { + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node22/-/node22-22.0.2.tgz", + "integrity": "sha512-Kmwj4u8sDRDrMYRoN9FDEcXD8UpBSaPQQ24Gz+Gamqfm7xxn+GBR7ge/Z7pK8OXNGyUzbSwJj+TH6B+DS/epyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", + "integrity": "sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" } }, "node_modules/@types/body-parser": { @@ -2210,18 +2762,31 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" } }, + "node_modules/@types/chai": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.2.tgz", + "integrity": "sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, "node_modules/@types/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-g4vmPIwbTii9dX1HVioHbOolubEaf4re4vDxuzpKrzz9uI7uarBExi9begX0cXyIB85jXZ5X2A/v8rsHZxSAPw==", "dev": true, + "license": "MIT", "dependencies": { - "@types/express": "*" + "@types/express": "*", + "@types/node": "*" } }, "node_modules/@types/connect": { @@ -2229,17 +2794,11 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/cookiejar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", @@ -2248,10 +2807,11 @@ "license": "MIT" }, "node_modules/@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "version": "2.8.18", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.18.tgz", + "integrity": "sha512-nX3d0sxJW41CqQvfOzVG1NCTXfFDrDWIghCZncpHeWlVFd81zxB/DLhg7avFg6eHLCRX7ckBmoIIcqa++upvJA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -2261,21 +2821,31 @@ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "version": "4.17.22", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.22.tgz", + "integrity": "sha512-eZUmSnhRX9YRSkplpz0N+k6NljUUn5l3EWZIKZvYzhvMphEuNiyyy1viH/ejgt66JWgALwC/gtSUAeQKtSwW/w==", "dev": true, + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -2284,9 +2854,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", "dev": true, "license": "MIT", "dependencies": { @@ -2296,13 +2866,6 @@ "@types/send": "*" } }, - "node_modules/@types/graphql": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.8.tgz", - "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", - "dev": true, - "optional": true - }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -2317,7 +2880,8 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", @@ -2326,54 +2890,34 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", - "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.9.tgz", + "integrity": "sha512-uoe+GxEuHbvy12OUQct2X9JenKM3qAscquYymuQN4fMWG9DBQtykrQEFcAbVACF7qaLw9BePSodUL0kquqBJpQ==", "dev": true, "license": "MIT", "dependencies": { + "@types/ms": "*", "@types/node": "*" } }, - "node_modules/@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/lodash": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", - "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", + "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", "dev": true, "license": "MIT" }, - "node_modules/@types/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", "dev": true, "license": "MIT", "dependencies": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" + "@types/unist": "*" } }, - "node_modules/@types/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/methods": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", @@ -2385,47 +2929,37 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", + "version": "22.15.30", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.30.tgz", + "integrity": "sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.21.0" } }, "node_modules/@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", - "dev": true + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/semver-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/semver-utils/-/semver-utils-1.1.3.tgz", - "integrity": "sha512-T+YwkslhsM+CeuhYUxyAjWm7mJ5am/K10UX40RuA6k6Lc7eGtq8iY2xOzy7Vq0GOqhl/xZl5l2FwURZMTPTUww==", "dev": true, "license": "MIT" }, @@ -2434,183 +2968,195 @@ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, + "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/superagent": { - "version": "8.1.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.7.tgz", - "integrity": "sha512-NmIsd0Yj4DDhftfWvvAku482PZum4DBW7U51OvS8gvOkDDY0WT1jsVyDV3hK+vplrsYw8oDwi9QxOM7U68iwww==", + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.9.tgz", + "integrity": "sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ==", "dev": true, "license": "MIT", "dependencies": { "@types/cookiejar": "^2.1.5", "@types/methods": "^1.1.4", - "@types/node": "*" + "@types/node": "*", + "form-data": "^4.0.0" } }, "node_modules/@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", "dev": true, "license": "MIT" }, "node_modules/@types/web-bluetooth": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", - "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", "dev": true, "license": "MIT" }, - "node_modules/@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "dev": true - }, - "node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz", + "integrity": "sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.33.1", + "@typescript-eslint/type-utils": "8.33.1", + "@typescript-eslint/utils": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^7.0.0", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.33.1", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.33.1.tgz", + "integrity": "sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/scope-manager": "8.33.1", + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/typescript-estree": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.33.1.tgz", + "integrity": "sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.33.1", + "@typescript-eslint/types": "^8.33.1", + "debug": "^4.3.4" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz", + "integrity": "sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz", + "integrity": "sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz", + "integrity": "sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/typescript-estree": "8.33.1", + "@typescript-eslint/utils": "8.33.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.33.1.tgz", + "integrity": "sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==", "dev": true, "license": "MIT", "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2618,267 +3164,541 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz", + "integrity": "sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", + "@typescript-eslint/project-service": "8.33.1", + "@typescript-eslint/tsconfig-utils": "8.33.1", + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/visitor-keys": "8.33.1", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/@typescript-eslint/utils": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.33.1.tgz", + "integrity": "sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.33.1", + "@typescript-eslint/types": "8.33.1", + "@typescript-eslint/typescript-estree": "8.33.1" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz", + "integrity": "sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" + "@typescript-eslint/types": "8.33.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript/vfs": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@typescript/vfs/-/vfs-1.6.1.tgz", + "integrity": "sha512-JwoxboBh7Oz1v38tPbkrZ62ZXNHAk9bJ7c9x0eI5zBfBnBYGhURdbnh7Z4smN/MV48Y5OCcZb58n972UtbazsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "typescript": "*" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.7.11.tgz", + "integrity": "sha512-i3/wlWjQJXMh1uiGtiv7k1EYvrrS3L1hdwmWJJiz1D8jWy726YFYPIxQWbEIVPVAgrfRR0XNlLrTQwq17cuCGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.7.11.tgz", + "integrity": "sha512-8XXyFvc6w6kmMmi6VYchZhjd5CDcp+Lv6Cn1YmUme0ypsZ/0Kzd+9ESrWtDrWibKPTgSteDTxp75cvBOY64FQQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.7.11.tgz", + "integrity": "sha512-0qJBYzP8Qk24CZ05RSWDQUjdiQUeIJGfqMMzbtXgCKl/a5xa6thfC0MQkGIr55LCLd6YmMyO640ifYUa53lybQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.7.11.tgz", + "integrity": "sha512-1sGwpgvx+WZf0GFT6vkkOm6UJ+mlsVnjw+Yv9esK71idWeRAG3bbpkf3AoY8KIqKqmnzJExi0uKxXpakQ5Pcbg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.7.11.tgz", + "integrity": "sha512-D/1F/2lTe+XAl3ohkYj51NjniVly8sIqkA/n1aOND3ZMO418nl2JNU95iVa1/RtpzaKcWEsNTtHRogykrUflJg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.7.11.tgz", + "integrity": "sha512-7vFWHLCCNFLEQlmwKQfVy066ohLLArZl+AV/AdmrD1/pD1FlmqM+FKbtnONnIwbHtgetFUCV/SRi1q4D49aTlw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.7.11.tgz", + "integrity": "sha512-tYkGIx8hjWPh4zcn17jLEHU8YMmdP2obRTGkdaB3BguGHh31VCS3ywqC4QjTODjmhhNyZYkj/1Dz/+0kKvg9YA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.7.11.tgz", + "integrity": "sha512-6F328QIUev29vcZeRX6v6oqKxfUoGwIIAhWGD8wSysnBYFY0nivp25jdWmAb1GildbCCaQvOKEhCok7YfWkj4Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.7.11.tgz", + "integrity": "sha512-NqhWmiGJGdzbZbeucPZIG9Iav4lyYLCarEnxAceguMx9qlpeEF7ENqYKOwB8Zqk7/CeuYMEcLYMaW2li6HyDzQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.7.11.tgz", + "integrity": "sha512-J2RPIFKMdTrLtBdfR1cUMKl8Gcy05nlQ+bEs/6al7EdWLk9cs3tnDREHZ7mV9uGbeghpjo4i8neNZNx3PYUY9w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.7.11.tgz", + "integrity": "sha512-bDpGRerHvvHdhun7MmFUNDpMiYcJSqWckwAVVRTJf8F+RyqYJOp/mx04PDc7DhpNPeWdnTMu91oZRMV+gGaVcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.11.tgz", + "integrity": "sha512-G9U7bVmylzRLma3cK39RBm3guoD1HOvY4o0NS4JNm37AD0lS7/xyMt7kn0JejYyc0Im8J+rH69/dXGM9DAJcSQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.11.tgz", + "integrity": "sha512-7qL20SBKomekSunm7M9Fe5L93bFbn+FbHiGJbfTlp0RKhPVoJDP73vOxf1QrmJHyDPECsGWPFnKa/f8fO2FsHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.7.11.tgz", + "integrity": "sha512-jisvIva8MidjI+B1lFRZZMfCPaCISePgTyR60wNT1MeQvIh5Ksa0G3gvI+Iqyj3jqYbvOHByenpa5eDGcSdoSg==", + "cpu": [ + "wasm32" + ], "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" + "@napi-rs/wasm-runtime": "^0.2.10" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=14.0.0" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.7.11.tgz", + "integrity": "sha512-G+H5nQZ8sRZ8ebMY6mRGBBvTEzMYEcgVauLsNHpvTUavZoCCRVP1zWkCZgOju2dW3O22+8seTHniTdl1/uLz3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.7.11.tgz", + "integrity": "sha512-Hfy46DBfFzyv0wgR0MMOwFFib2W2+Btc8oE5h4XlPhpelnSyA6nFxkVIyTgIXYGTdFaLoZFNn62fmqx3rjEg3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.7.11.tgz", + "integrity": "sha512-7L8NdsQlCJ8T106Gbz/AjzM4QKWVsoQbKpB9bMBGcIZswUuAnJMHpvbqGW3RBqLHCIwX4XZ5fxSBHEFcK2h9wA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] }, "node_modules/@vitejs/plugin-vue": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.5.tgz", - "integrity": "sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" }, "peerDependencies": { - "vite": "^5.0.0", + "vite": "^5.0.0 || ^6.0.0", "vue": "^3.2.25" } }, "node_modules/@vitest/coverage-v8": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", - "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.2.2.tgz", + "integrity": "sha512-RVAi5xnqedSKvaoQyCTWvncMk8eYZcTTOsLK7XmnfOEvdGP/O/upA0/MA8Ss+Qs++mj0GcSRi/whR0S5iBPpTQ==", "dev": true, "license": "MIT", "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@bcoe/v8-coverage": "^0.2.3", - "debug": "^4.3.4", + "@ampproject/remapping": "^2.3.0", + "@bcoe/v8-coverage": "^1.0.2", + "ast-v8-to-istanbul": "^0.3.3", + "debug": "^4.4.1", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.4", - "istanbul-reports": "^3.1.6", - "magic-string": "^0.30.5", - "magicast": "^0.3.3", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "test-exclude": "^6.0.0" + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.1.7", + "magic-string": "^0.30.17", + "magicast": "^0.3.5", + "std-env": "^3.9.0", + "test-exclude": "^7.0.1", + "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.6.0" + "@vitest/browser": "3.2.2", + "vitest": "3.2.2" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } } }, "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.2.tgz", + "integrity": "sha512-ipHw0z669vEMjzz3xQE8nJX1s0rQIb7oEl4jjl35qWTwm/KIHERIg/p/zORrjAaZKXfsv7IybcNGHwhOOAPMwQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "chai": "^4.3.10" + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.2", + "@vitest/utils": "3.2.2", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", - "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "node_modules/@vitest/mocker": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.2.tgz", + "integrity": "sha512-jKojcaRyIYpDEf+s7/dD3LJt53c0dPfp5zCPXz9H/kcGrSlovU/t1yEaNzM9oFME3dcd4ULwRI/x0Po1Zf+LTw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "1.6.0", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" + "@vitest/spy": "3.2.2", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" }, "funding": { "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", + "node_modules/@vitest/pretty-format": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.2.tgz", + "integrity": "sha512-FY4o4U1UDhO9KMd2Wee5vumwcaHw7Vg4V7yR4Oq6uK34nhEJOmdRYrk3ClburPRUA09lXD/oXWZ8y/Sdma0aUQ==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" + "tinyrainbow": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", + "node_modules/@vitest/runner": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.2.tgz", + "integrity": "sha512-GYcHcaS3ejGRZYed2GAkvsjBeXIEerDKdX3orQrBJqLRiea4NSS9qvn9Nxmuy1IwIB+EjFOaxXnX79l8HFaBwg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=12.20" + "dependencies": { + "@vitest/utils": "3.2.2", + "pathe": "^2.0.3" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", - "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.2.tgz", + "integrity": "sha512-aMEI2XFlR1aNECbBs5C5IZopfi5Lb8QJZGGpzS8ZUHML5La5wCbrbhLOVSME68qwpT05ROEEOAZPRXFpxZV2wA==", "dev": true, "license": "MIT", "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" + "@vitest/pretty-format": "3.2.2", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.2.tgz", + "integrity": "sha512-6Utxlx3o7pcTxvp0u8kUiXtRFScMrUg28KjB3R2hon7w4YqOFAEA9QwzPVVS1QNL3smo4xRNOpNZClRVfpMcYg==", "dev": true, "license": "MIT", "dependencies": { - "tinyspy": "^2.2.0" + "tinyspy": "^4.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.2.tgz", + "integrity": "sha512-qJYMllrWpF/OYfWHP32T31QCaLa3BAzT/n/8mNGhPdVcjY+JYazQFO1nsJvXU12Kp1xMpNY4AGuljPTNjQve6A==", "dev": true, "license": "MIT", "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" + "@vitest/pretty-format": "3.2.2", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, + "node_modules/@volar/language-core": { + "version": "2.4.14", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.14.tgz", + "integrity": "sha512-X6beusV0DvuVseaOEy7GoagS4rYHgDHnTrdOj5jeUb49fW5ceQyP9Ej5rBhqgz2wJggl+2fDbbojq1XKaxDi6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.14" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.14", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.14.tgz", + "integrity": "sha512-5TeKKMh7Sfxo8021cJfmBzcjfY1SsXsPMMjMvjY7ivesdnybqqS+GxGAoXHAOUawQTwtdUxgP65Im+dEmvWtYQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@vue/compiler-core": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.32.tgz", - "integrity": "sha512-8tCVWkkLe/QCWIsrIvExUGnhYCAOroUs5dzhSoKL5w4MJS8uIYiou+pOPSVIOALOQ80B0jBs+Ri+kd5+MBnCDw==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.16.tgz", + "integrity": "sha512-AOQS2eaQOaaZQoL1u+2rCJIKDruNXVBZSiUD3chnUrsoX5ZTQMaCvXlWNIfxBJuU15r1o7+mpo5223KVtIhAgQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.32", + "@babel/parser": "^7.27.2", + "@vue/shared": "3.5.16", "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" + "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-core/node_modules/estree-walker": { @@ -2889,32 +3709,32 @@ "license": "MIT" }, "node_modules/@vue/compiler-dom": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.32.tgz", - "integrity": "sha512-PbSgt9KuYo4fyb90dynuPc0XFTfFPs3sCTbPLOLlo+PrUESW1gn/NjSsUvhR+mI2AmmEzexwYMxbHDldxSOr2A==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.16.tgz", + "integrity": "sha512-SSJIhBr/teipXiXjmWOVWLnxjNGo65Oj/8wTEQz0nqwQeP75jWZ0n4sF24Zxoht1cuJoWopwj0J0exYwCJ0dCQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.4.32", - "@vue/shared": "3.4.32" + "@vue/compiler-core": "3.5.16", + "@vue/shared": "3.5.16" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.32.tgz", - "integrity": "sha512-STy9im/WHfaguJnfKjjVpMHukxHUrOKjm2vVCxiojQJyo3Sb6Os8SMXBr/MI+ekpstEGkDONfqAQoSbZhspLYw==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.16.tgz", + "integrity": "sha512-rQR6VSFNpiinDy/DVUE0vHoIDUF++6p910cgcZoaAUm3POxgNOOdS/xgoll3rNdKYTYPnnbARDCZOyZ+QSe6Pw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.32", - "@vue/compiler-dom": "3.4.32", - "@vue/compiler-ssr": "3.4.32", - "@vue/shared": "3.4.32", + "@babel/parser": "^7.27.2", + "@vue/compiler-core": "3.5.16", + "@vue/compiler-dom": "3.5.16", + "@vue/compiler-ssr": "3.5.16", + "@vue/shared": "3.5.16", "estree-walker": "^2.0.2", - "magic-string": "^0.30.10", - "postcss": "^8.4.39", - "source-map-js": "^1.2.0" + "magic-string": "^0.30.17", + "postcss": "^8.5.3", + "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { @@ -2925,160 +3745,170 @@ "license": "MIT" }, "node_modules/@vue/compiler-ssr": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.32.tgz", - "integrity": "sha512-nyu/txTecF6DrxLrpLcI34xutrvZPtHPBj9yRoPxstIquxeeyywXpYZrQMsIeDfBhlw1abJb9CbbyZvDw2kjdg==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.16.tgz", + "integrity": "sha512-d2V7kfxbdsjrDSGlJE7my1ZzCXViEcqN6w14DOsDrUCHEA6vbnVCpRFfrc4ryCP/lCKzX2eS1YtnLE/BuC9f/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.16", + "@vue/shared": "3.5.16" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.4.32", - "@vue/shared": "3.4.32" + "de-indent": "^1.0.2", + "he": "^1.2.0" } }, "node_modules/@vue/devtools-api": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.3.6.tgz", - "integrity": "sha512-z6cKyxdXrIGgA++eyGBfquj6dCplRdgjt+I18fJx8hjWTXDTIyeQvryyEBMchnfZVyvUTjK3QjGjDpLCnJxPjw==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.6.tgz", + "integrity": "sha512-b2Xx0KvXZObePpXPYHvBRRJLDQn5nhKjXh7vUhMEtWxz1AYNFOVIsh5+HLP8xDGL7sy+Q7hXeUxPHB/KgbtsPw==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^7.3.6" + "@vue/devtools-kit": "^7.7.6" } }, "node_modules/@vue/devtools-kit": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.3.6.tgz", - "integrity": "sha512-5Ym9V3fkJenEoptqKoo+cgY5RTVwrSssFdzRsuyIgaeiskCT+rRJeQdwoo81tyrQ1mfS7Er1rYZlSzr3Y3L/ew==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.6.tgz", + "integrity": "sha512-geu7ds7tem2Y7Wz+WgbnbZ6T5eadOvozHZ23Atk/8tksHMFOFylKi1xgGlQlVn0wlkEf4hu+vd5ctj1G4kFtwA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^7.3.6", - "birpc": "^0.2.17", + "@vue/devtools-shared": "^7.7.6", + "birpc": "^2.3.0", "hookable": "^5.5.3", "mitt": "^3.0.1", "perfect-debounce": "^1.0.0", "speakingurl": "^14.0.1", - "superjson": "^2.2.1" + "superjson": "^2.2.2" } }, "node_modules/@vue/devtools-shared": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.3.6.tgz", - "integrity": "sha512-R/FOmdJV+hhuwcNoxp6e87RRkEeDMVhWH+nOsnHUrwjjsyeXJ2W1475Ozmw+cbZhejWQzftkHVKO28Fuo1yqCw==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.6.tgz", + "integrity": "sha512-yFEgJZ/WblEsojQQceuyK6FzpFDx4kqrz2ohInxNj5/DnhoX023upTv4OD6lNPLAA5LLkbwPVb10o/7b+Y4FVA==", "dev": true, "license": "MIT", "dependencies": { "rfdc": "^1.4.1" } }, + "node_modules/@vue/language-core": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.4.tgz", + "integrity": "sha512-eGGdw7eWUwdIn9Fy/irJ7uavCGfgemuHQABgJ/hU1UgZFnbTg9VWeXvHQdhY+2SPQZWJqWXvRWIg67t4iWEa+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^1.0.3", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/@vue/reactivity": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.32.tgz", - "integrity": "sha512-1P7QvghAzhSIWmiNmh4MNkLVjr2QTNDcFv2sKmytEWhR6t7BZzNicgm5ENER4uU++wbWxgRh/pSEYgdI3MDcvg==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.16.tgz", + "integrity": "sha512-FG5Q5ee/kxhIm1p2bykPpPwqiUBV3kFySsHEQha5BJvjXdZTUfmya7wP7zC39dFuZAcf/PD5S4Lni55vGLMhvA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/shared": "3.4.32" + "@vue/shared": "3.5.16" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.32.tgz", - "integrity": "sha512-FxT2dTHUs1Hki8Ui/B1Hu339mx4H5kRJooqrNM32tGUHBPStJxwMzLIRbeGO/B1NMplU4Pg9fwOqrJtrOzkdfA==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.16.tgz", + "integrity": "sha512-bw5Ykq6+JFHYxrQa7Tjr+VSzw7Dj4ldR/udyBZbq73fCdJmyy5MPIFR9IX/M5Qs+TtTjuyUTCnmK3lWWwpAcFQ==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.4.32", - "@vue/shared": "3.4.32" + "@vue/reactivity": "3.5.16", + "@vue/shared": "3.5.16" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.32.tgz", - "integrity": "sha512-Xz9G+ZViRyPFQtRBCPFkhMzKn454ihCPMKUiacNaUhuTIXvyfkAq8l89IZ/kegFVyw/7KkJGRGqYdEZrf27Xsg==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.16.tgz", + "integrity": "sha512-T1qqYJsG2xMGhImRUV9y/RseB9d0eCYZQ4CWca9ztCuiPj/XWNNN+lkNBuzVbia5z4/cgxdL28NoQCvC0Xcfww==", "dev": true, "license": "MIT", "dependencies": { - "@vue/reactivity": "3.4.32", - "@vue/runtime-core": "3.4.32", - "@vue/shared": "3.4.32", + "@vue/reactivity": "3.5.16", + "@vue/runtime-core": "3.5.16", + "@vue/shared": "3.5.16", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.32.tgz", - "integrity": "sha512-3c4rd0522Ao8hKjzgmUAbcjv2mBnvnw0Ld2f8HOMCuWJZjYie/p8cpIoYJbeP0VV2JYmrJJMwGQDO5RH4iQ30A==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.16.tgz", + "integrity": "sha512-BrX0qLiv/WugguGsnQUJiYOE0Fe5mZTwi6b7X/ybGB0vfrPH9z0gD/Y6WOR1sGCgX4gc25L1RYS5eYQKDMoNIg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.4.32", - "@vue/shared": "3.4.32" + "@vue/compiler-ssr": "3.5.16", + "@vue/shared": "3.5.16" }, "peerDependencies": { - "vue": "3.4.32" + "vue": "3.5.16" } }, "node_modules/@vue/shared": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.32.tgz", - "integrity": "sha512-ep4mF1IVnX/pYaNwxwOpJHyBtOMKWoKZMbnUyd+z0udqIxLUh7YCCd/JfDna8aUrmnG9SFORyIq2HzEATRrQsg==", + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.16.tgz", + "integrity": "sha512-c/0fWy3Jw6Z8L9FmTyYfkpM5zklnqqa9+a6dz3DvONRKW2NEbh46BP0FHuLFSWi2TnQEtp91Z6zOWNrU6QiyPg==", "dev": true, "license": "MIT" }, "node_modules/@vueuse/core": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.0.tgz", - "integrity": "sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.3.0.tgz", + "integrity": "sha512-uYRz5oEfebHCoRhK4moXFM3NSCd5vu2XMLOq/Riz5FdqZMy2RvBtazdtL3gEcmDyqkztDe9ZP/zymObMIbiYSg==", "dev": true, "license": "MIT", "dependencies": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "10.11.0", - "@vueuse/shared": "10.11.0", - "vue-demi": ">=0.14.8" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", - "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "13.3.0", + "@vueuse/shared": "13.3.0" }, "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "vue": "^3.5.0" } }, "node_modules/@vueuse/integrations": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-10.11.0.tgz", - "integrity": "sha512-Pp6MtWEIr+NDOccWd8j59Kpjy5YDXogXI61Kb1JxvSfVBO8NzFQkmrKmSZz47i+ZqHnIzxaT38L358yDHTncZg==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-13.3.0.tgz", + "integrity": "sha512-h5mGRYPbiTZTFP/AKELLPGnUDBly7z7Qd1pgEQlT3ItQ0NlZM0vB+8SOQycpSBOBlgg72Zgw+mi2r+4O/G8RuQ==", "dev": true, "license": "MIT", "dependencies": { - "@vueuse/core": "10.11.0", - "@vueuse/shared": "10.11.0", - "vue-demi": ">=0.14.8" + "@vueuse/core": "13.3.0", + "@vueuse/shared": "13.3.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -3086,16 +3916,17 @@ "peerDependencies": { "async-validator": "^4", "axios": "^1", - "change-case": "^4", - "drauu": "^0.3", + "change-case": "^5", + "drauu": "^0.4", "focus-trap": "^7", - "fuse.js": "^6", + "fuse.js": "^7", "idb-keyval": "^6", - "jwt-decode": "^3", + "jwt-decode": "^4", "nprogress": "^0.2", "qrcode": "^1.5", "sortablejs": "^1", - "universal-cookie": "^6" + "universal-cookie": "^7", + "vue": "^3.5.0" }, "peerDependenciesMeta": { "async-validator": { @@ -3136,37 +3967,10 @@ } } }, - "node_modules/@vueuse/integrations/node_modules/vue-demi": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", - "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - }, - "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } - } - }, "node_modules/@vueuse/metadata": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.0.tgz", - "integrity": "sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.3.0.tgz", + "integrity": "sha512-42IzJIOYCKIb0Yjv1JfaKpx8JlCiTmtCWrPxt7Ja6Wzoq0h79+YVXmBV03N966KEmDEESTbp5R/qO3AB5BDnGw==", "dev": true, "license": "MIT", "funding": { @@ -3174,56 +3978,24 @@ } }, "node_modules/@vueuse/shared": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.0.tgz", - "integrity": "sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "vue-demi": ">=0.14.8" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", - "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.3.0.tgz", + "integrity": "sha512-L1QKsF0Eg9tiZSFXTgodYnu0Rsa2P0En2LuLrIs/jgrkyiDuJSsPZK+tx+wU0mMsYHUYEjNsuE41uqqkuR8VhA==", "dev": true, - "hasInstallScript": true, "license": "MIT", - "bin": { - "vue-demi-fix": "bin/vue-demi-fix.js", - "vue-demi-switch": "bin/vue-demi-switch.js" - }, - "engines": { - "node": ">=12" - }, "funding": { "url": "https://github.com/sponsors/antfu" }, "peerDependencies": { - "@vue/composition-api": "^1.0.0-rc.1", - "vue": "^3.0.0-0 || ^2.6.0" - }, - "peerDependenciesMeta": { - "@vue/composition-api": { - "optional": true - } + "vue": "^3.5.0" } }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -3232,11 +4004,22 @@ "node": ">= 0.6" } }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3249,65 +4032,22 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dev": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -3332,68 +4072,44 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "node_modules/algoliasearch": { + "version": "5.27.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.27.0.tgz", + "integrity": "sha512-2PvAgvxxJzA3+dB+ERfS2JPdvUsxNf89Cc2GF5iCcFupTULOwmbfinvqrC4Qj9nHJJDNf494NqEN/1f9177ZTQ==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "@algolia/client-abtesting": "5.27.0", + "@algolia/client-analytics": "5.27.0", + "@algolia/client-common": "5.27.0", + "@algolia/client-insights": "5.27.0", + "@algolia/client-personalization": "5.27.0", + "@algolia/client-query-suggestions": "5.27.0", + "@algolia/client-search": "5.27.0", + "@algolia/ingestion": "1.27.0", + "@algolia/monitoring": "1.27.0", + "@algolia/recommend": "5.27.0", + "@algolia/requester-browser-xhr": "5.27.0", + "@algolia/requester-fetch": "5.27.0", + "@algolia/requester-node-http": "5.27.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "engines": { + "node": ">= 14.0.0" } }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/alien-signals": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-1.0.13.tgz", + "integrity": "sha512-OGj9yyTnJEttvzhTUWuscOvtqxq5vrhF7vL9oS0xJ2mK0ItPYP1/y+vCFebfxoEyAz0++1AIwJ5CMr+Fk3nDmg==", "dev": true, "license": "MIT" }, - "node_modules/algoliasearch": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", - "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@algolia/cache-browser-local-storage": "4.24.0", - "@algolia/cache-common": "4.24.0", - "@algolia/cache-in-memory": "4.24.0", - "@algolia/client-account": "4.24.0", - "@algolia/client-analytics": "4.24.0", - "@algolia/client-common": "4.24.0", - "@algolia/client-personalization": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/logger-console": "4.24.0", - "@algolia/recommend": "4.24.0", - "@algolia/requester-browser-xhr": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/requester-node-http": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "dependencies": { - "string-width": "^4.1.0" - } - }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3403,6 +4119,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3413,64 +4130,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/ansis": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz", + "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==", "dev": true, "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=14" } }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "Python-2.0" }, "node_modules/array-flatten": { "version": "1.1.1", @@ -3479,171 +4154,83 @@ "dev": true, "license": "MIT" }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=12" } }, - "node_modules/array-union": { + "node_modules/ast-kit": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", + "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.1.0.tgz", + "integrity": "sha512-ROM2LlXbZBZVk97crfw8PGDOBzzsJvN2uJCmwswvPUNyfH14eg90mSN3xNqsri1JS1G9cz0VzeDUhxJkTrr4Ew==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" + "@babel/parser": "^7.27.3", + "pathe": "^2.0.3" }, "engines": { - "node": ">= 0.4" + "node": ">=20.18.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.3.tgz", + "integrity": "sha512-MuXMrSLVVoA6sYN/6Hke18vMzrT4TZNbZIj/hvh0fnYFpO+/kFXcLIaiPwXXWaQUPg4yJD8fj+lfJ7/1EBconw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "@jridgewell/trace-mapping": "^0.3.25", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" } }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/arraybuffer.prototype.slice": { + "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": "^4.5.0 || >= 5.9" } }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "node_modules/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^4.5.0 || >= 5.9" - } - }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" } }, "node_modules/birpc": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.17.tgz", - "integrity": "sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.3.0.tgz", + "integrity": "sha512-ijbtkn/F3Pvzb6jHypHRyve2QApOCZDR25D/VnkY2G/lBNcXCTsnsCxgY4k4PkVB7zfwzYbY3O9Lcqe3xufS5g==", "dev": true, "license": "MIT", "funding": { @@ -3651,9 +4238,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { @@ -3665,7 +4252,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -3675,16 +4262,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/body-parser/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3703,13 +4280,13 @@ "license": "MIT" }, "node_modules/body-parser/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -3718,175 +4295,88 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/boxen": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", - "dev": true, - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/boxen/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/boxen/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/boxen/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/boxen/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/boxen/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, - "node_modules/bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "node_modules/browserslist": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, "engines": { - "node": ">=14.20.1" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", "dev": true, - "dependencies": { - "semver": "^7.0.0" - } + "license": "BSD-3-Clause" }, - "node_modules/bundle-require": { + "node_modules/builtin-modules": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.0.0.tgz", - "integrity": "sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", + "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==", "dev": true, "license": "MIT", - "dependencies": { - "load-tsconfig": "^0.2.3" - }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18.20" }, - "peerDependencies": { - "esbuild": ">=0.18" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3896,135 +4386,34 @@ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/cacache": { - "version": "17.1.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", - "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", - "dev": true, - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^7.7.1", - "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "10.3.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", - "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/cacheable-lookup": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", - "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.1.2.tgz", - "integrity": "sha512-N7F4os5ZI+8mWHSbeJmxn+qimf5uK3WU53FD1b298XLGtOLPpSA/1xAchfP4NJlDwqgaviZ0SQfxTQD0K6lr9w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, + "license": "MIT", "dependencies": { - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.0", - "keyv": "^4.5.0", - "mimic-response": "^4.0.0", - "normalize-url": "^7.1.0", - "responselike": "^3.0.0" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" }, "engines": { - "node": ">=14.16" + "node": ">= 0.4" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" @@ -4038,39 +4427,58 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", + "node_modules/caniuse-lite": { + "version": "1.0.30001721", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz", + "integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==", "dev": true, - "engines": { - "node": ">=14.16" - }, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "license": "MIT", "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=12" } }, "node_modules/chalk": { @@ -4078,6 +4486,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4089,116 +4498,127 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", "dev": true, "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "dev": true, "license": "MIT", - "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" - }, - "engines": { - "node": ">= 8.10.0" - }, "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 6" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=10" + "node": ">=18" } }, "node_modules/ci-info": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", - "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", - "dev": true - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", + "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=4" } }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "node_modules/clean-regexp/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, + "license": "MIT", "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" + "node": ">=0.8.0" } }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" + "node": ">=12" } }, "node_modules/color-convert": { @@ -4206,6 +4626,7 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -4217,24 +4638,41 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, - "bin": { - "color-support": "bin.js" + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" } }, - "node_modules/commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=14" + "node": ">= 12.0.0" } }, "node_modules/compressible": { @@ -4242,6 +4680,7 @@ "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -4250,17 +4689,18 @@ } }, "node_modules/compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz", + "integrity": "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA==", "dev": true, + "license": "MIT", "dependencies": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", + "bytes": "3.1.2", + "compressible": "~2.0.18", "debug": "2.6.9", + "negotiator": "~0.6.4", "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", + "safe-buffer": "5.2.1", "vary": "~1.1.2" }, "engines": { @@ -4272,6 +4712,7 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4280,77 +4721,22 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/compression/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", "dev": true, "license": "MIT" }, - "node_modules/config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "dependencies": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "node_modules/config-chain/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/configstore": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", - "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", - "dev": true, - "dependencies": { - "dot-prop": "^6.0.1", - "graceful-fs": "^4.2.6", - "unique-string": "^3.0.0", - "write-file-atomic": "^3.0.3", - "xdg-basedir": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/yeoman/configstore?sponsor=1" - } - }, - "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", + "node_modules/confbox": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz", + "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==", "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true + "license": "MIT" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -4376,9 +4762,9 @@ } }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "dev": true, "license": "MIT", "engines": { @@ -4408,11 +4794,26 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/core-js-compat": { + "version": "3.42.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.42.0.tgz", + "integrity": "sha512-bQasjMfyDGyaeWKBIu33lHh9qlSR0MFE/Nmc6nMjf/iU9b3rSMdAYz1Baxrv4lPdGUsTqZudHA4jIGSJy0SWZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", "dev": true, + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -4422,10 +4823,11 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4435,33 +4837,6 @@ "node": ">= 8" } }, - "node_modules/crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "dependencies": { - "type-fest": "^1.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/crypto-random-string/node_modules/type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4469,13 +4844,21 @@ "dev": true, "license": "MIT" }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4486,111 +4869,69 @@ } } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "node_modules/decode-named-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", + "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" + "character-entities": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "node_modules/dedent": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.6.0.tgz", + "integrity": "sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } } }, "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, "engines": { "node": ">=6" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", "dev": true, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.4.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -4601,17 +4942,15 @@ "node": ">= 0.8" } }, - "node_modules/deprecate": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deprecate/-/deprecate-1.1.1.tgz", - "integrity": "sha512-ZGDXefq1xknT292LnorMY5s8UVU08/WKdzDZCUT6t9JzsiMSP4uzUhgpqugffNVcT5WC6wMBiSQ+LFjlv3v7iQ==", - "dev": true - }, - "node_modules/deprecated-decorator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", - "integrity": "sha512-MHidOOnCHGlZDKsI21+mbIIhf4Fff+hhCTB7gtVg4uoIqjcrTZc5v6M+GS2zVI0sV7PqK415rb8XaOSQsQkHOw==", - "dev": true + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, "node_modules/destroy": { "version": "1.2.0", @@ -4624,66 +4963,109 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, "license": "MIT", "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, + "license": "Apache-2.0", "engines": { "node": ">=8" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "dev": true, + "license": "MIT", "dependencies": { - "is-obj": "^2.0.0" - }, - "engines": { - "node": ">=10" + "dequal": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dts-resolver": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/dts-resolver/-/dts-resolver-2.1.1.tgz", + "integrity": "sha512-3BiGFhB6mj5Kv+W2vdJseQUYW+SKVzAFJL6YNP6ursbrwy1fXHRotfHi3xLNxe4wZl/K8qbAFeCDjZLjzqxxRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + }, + "peerDependencies": { + "oxc-resolver": ">=11.0.0" + }, + "peerDependenciesMeta": { + "oxc-resolver": { + "optional": true + } + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" } @@ -4695,11 +5077,29 @@ "dev": true, "license": "MIT" }, + "node_modules/electron-to-chromium": { + "version": "1.5.165", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.165.tgz", + "integrity": "sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==", + "dev": true, + "license": "ISC" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/empathic": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-1.1.0.tgz", + "integrity": "sha512-rsPft6CK3eHtrlp9Y5ALBb+hfK+DWnA4WFebbazxjWyx8vSm3rZeoM3z9irsjcqO3PYRzlfv27XIB4tz2DV7RA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } }, "node_modules/encodeurl": { "version": "2.0.0", @@ -4711,42 +5111,18 @@ "node": ">= 0.8" } }, - "node_modules/encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", "dev": true, "license": "MIT", "dependencies": { - "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", @@ -4767,105 +5143,66 @@ } }, "node_modules/engine.io/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" } }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, "engines": { - "node": ">=0.12" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, "engines": { - "node": ">=6" + "node": ">=10.13.0" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -4880,50 +5217,46 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" + "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4931,44 +5264,44 @@ "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escape-goat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", - "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, "node_modules/escape-html": { @@ -4983,6 +5316,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -4991,198 +5325,232 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.28.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.28.0.tgz", + "integrity": "sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.28.0", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@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", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, "peerDependencies": { "eslint": ">=7.0.0" } }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-fix-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/eslint-fix-utils/-/eslint-fix-utils-0.2.1.tgz", + "integrity": "sha512-vHvLGmqdgPhZgH+cymlAlAqVuV22auB+uk/mgFdg5zotEtMHAHcOzNzhr5XOrDzyKGEQY2uQHoT+tS8P36/2CQ==", "dev": true, - "dependencies": { - "ms": "^2.1.1" + "license": "MIT", + "engines": { + "node": ">=18.3.0" + }, + "peerDependencies": { + "@types/estree": ">=1", + "eslint": ">=8" + }, + "peerDependenciesMeta": { + "@types/estree": { + "optional": true + } } }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "node_modules/eslint-import-context": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.8.tgz", + "integrity": "sha512-bq+F7nyc65sKpZGT09dY0S0QrOnQtuDVIfyTGQ8uuvtMIF7oHp6CEP3mouN0rrnYF3Jqo6Ke0BfU/5wASZue1w==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^3.2.7" + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.1.1" }, "engines": { - "node": ">=4" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" }, "peerDependenciesMeta": { - "eslint": { + "unrs-resolver": { "optional": true } } }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/eslint-import-resolver-typescript": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.3.tgz", + "integrity": "sha512-elVDn1eWKFrWlzxlWl9xMt8LltjKl161Ix50JFC50tHXI5/TRP32SNEqlJ/bo/HV+g7Rou/tlPQU2AcRtIhrOg==", "dev": true, + "license": "ISC", "dependencies": { - "ms": "^2.1.1" + "debug": "^4.4.1", + "eslint-import-context": "^0.1.8", + "get-tsconfig": "^4.10.1", + "is-bun-module": "^2.0.0", + "stable-hash-x": "^0.1.1", + "tinyglobby": "^0.2.14", + "unrs-resolver": "^1.7.11" + }, + "engines": { + "node": "^16.17.0 || >=18.6.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } } }, - "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "node_modules/eslint-plugin-import-x": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.15.1.tgz", + "integrity": "sha512-JfVpNg1qMkPD66iaSgmMoSYeUCGS8UFSm3GwHV0IbuV3Knar/SyK5qqCct9+AxoMIzaM+KSO7KK5pOeOkC/3GQ==", "dev": true, + "license": "MIT", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "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.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "@typescript-eslint/types": "^8.33.1", + "comment-parser": "^1.4.1", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.7", "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" + "minimatch": "^9.0.3 || ^10.0.1", + "semver": "^7.7.2", + "stable-hash-x": "^0.1.1", + "unrs-resolver": "^1.7.10" }, "engines": { - "node": ">=4" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-import-x" }, "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" + "@typescript-eslint/utils": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "eslint-import-resolver-node": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/utils": { + "optional": true + }, + "eslint-import-resolver-node": { + "optional": true + } } }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "node_modules/eslint-plugin-package-json": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-package-json/-/eslint-plugin-package-json-0.33.2.tgz", + "integrity": "sha512-YhWRNeiR44jLCLHDsG2W0mcuHflF9lKG2fSSaN+UDt4lYPCWUzTkQrrKxapabUIobMN+OnM4zsgnPKX97l/N0g==", "dev": true, + "license": "MIT", "dependencies": { - "esutils": "^2.0.2" + "@altano/repository-tools": "^0.1.1", + "detect-indent": "6.1.0", + "detect-newline": "3.1.0", + "eslint-fix-utils": "^0.2.0", + "package-json-validator": "^0.10.0", + "semver": "^7.5.4", + "sort-object-keys": "^1.1.3", + "sort-package-json": "^3.0.0", + "validate-npm-package-name": "^6.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", - "dev": true, + "node": ">=18" + }, "peerDependencies": { - "eslint": ">=2.0.0" + "eslint": ">=8.0.0", + "jsonc-eslint-parser": "^2.0.0" } }, "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz", + "integrity": "sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==", "dev": true, "license": "MIT", "dependencies": { "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" + "synckit": "^0.11.7" }, "engines": { "node": "^14.18.0 || >=16.0.0" @@ -5193,7 +5561,7 @@ "peerDependencies": { "@types/eslint": ">=8.0.0", "eslint": ">=8.0.0", - "eslint-config-prettier": "*", + "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", "prettier": ">=3.0.0" }, "peerDependenciesMeta": { @@ -5205,17 +5573,96 @@ } } }, + "node_modules/eslint-plugin-unicorn": { + "version": "59.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-59.0.1.tgz", + "integrity": "sha512-EtNXYuWPUmkgSU2E7Ttn57LbRREQesIP1BiLn7OZLKodopKfDXfBUkC/0j6mpw2JExwf43Uf3qLSvrSvppgy8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "@eslint-community/eslint-utils": "^4.5.1", + "@eslint/plugin-kit": "^0.2.7", + "ci-info": "^4.2.0", + "clean-regexp": "^1.0.0", + "core-js-compat": "^3.41.0", + "esquery": "^1.6.0", + "find-up-simple": "^1.0.1", + "globals": "^16.0.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.12.0", + "semver": "^7.7.1", + "strip-indent": "^4.0.0" + }, + "engines": { + "node": "^18.20.0 || ^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=9.22.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-plugin-unused-imports": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz", + "integrity": "sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^8.0.0-0 || ^7.0.0 || ^6.0.0 || ^5.0.0", + "eslint": "^9.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@typescript-eslint/eslint-plugin": { + "optional": true + } + } + }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5226,6 +5673,7 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5233,34 +5681,128 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/esquery": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", - "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -5273,6 +5815,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -5285,6 +5828,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -5304,6 +5848,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -5322,72 +5867,54 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", "engines": { "node": ">=0.8.x" } }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "node_modules/expect-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", + "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">=12.0.0" } }, - "node_modules/exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -5396,6 +5923,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/debug": { @@ -5408,16 +5939,6 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -5426,13 +5947,13 @@ "license": "MIT" }, "node_modules/express/node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -5441,28 +5962,58 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/exsolve": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.5.tgz", + "integrity": "sha512-pz5dvkYYKQ1AHVrgOzBKWeP4u4FRb3a6DNK2ucr0OoNwYIU4QWsJ+NM36LLzORT+z845MzKHHhpXiUF5nvQoJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" }, "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -5473,6 +6024,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -5483,151 +6035,63 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fast-memoize": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", - "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", - "dev": true - }, - "node_modules/fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", "dev": true, "license": "MIT" }, - "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/feathers-hooks-common": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/feathers-hooks-common/-/feathers-hooks-common-4.5.6.tgz", - "integrity": "sha512-z0KZP/igmHvEJX46x0f6UC/pSYFXUt/2OfgMwumElGqxwFYU4JrAnK8FbGwCo8MYowMDfpMk72ju+axbq9MV1Q==", - "dev": true, - "dependencies": { - "@feathers-plus/batch-loader": "0.3.0", - "@feathersjs/commons": "^1.2.0", - "@feathersjs/errors": "^3.0.0", - "ajv": "^5.2.0", - "debug": "^3.0.0", - "process": "0.11.10", - "traverse": "^0.6.6" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/feathers-hooks-common/node_modules/@feathers-plus/batch-loader": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.0.tgz", - "integrity": "sha512-buElwyOZKVI34kD7jHt+czIDv1brjXLBPJ+7is+RC98JK+TyqWIUuBJ4E0ZMjPxwwkAJIN6IATyPgvhSXhkaxw==", - "dev": true, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/feathers-hooks-common/node_modules/@feathersjs/commons": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-1.4.4.tgz", - "integrity": "sha512-ZPpzyZA3CPfoa9AuFv3BJUI/ubzaaXixp8T/pqeMFPT6DOaU/6oF7lz1RxwimzfJNna4gy/HByt0EoLSI3BKWg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/feathers-hooks-common/node_modules/@feathersjs/errors": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-3.3.6.tgz", - "integrity": "sha512-VCohY/AQU13xYyZGl6rfdUgE+2bjaI76a4aEb6reIphHKgb4mnjYlg2PzS1/hcU1qUNi515kY9yQa5HsE7J1dQ==", - "dev": true, - "dependencies": { - "debug": "^4.0.0" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/feathers-hooks-common/node_modules/@feathersjs/errors/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/fast-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", + "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" } - } - }, - "node_modules/feathers-hooks-common/node_modules/ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", - "dev": true, - "dependencies": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } + ], + "license": "BSD-3-Clause" }, - "node_modules/feathers-hooks-common/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", "dev": true, + "license": "ISC", "dependencies": { - "ms": "^2.1.1" + "reusify": "^1.0.4" } }, - "node_modules/feathers-hooks-common/node_modules/fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==", - "dev": true - }, - "node_modules/feathers-hooks-common/node_modules/json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==", - "dev": true - }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -5636,14 +6100,14 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dev": true, "license": "MIT", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -5664,16 +6128,6 @@ "ms": "2.0.0" } }, - "node_modules/finalhandler/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -5686,6 +6140,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -5697,51 +6152,78 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, - "node_modules/focus-trap": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", - "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", + "node_modules/floating-vue": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/floating-vue/-/floating-vue-5.2.2.tgz", + "integrity": "sha512-afW+h2CFafo+7Y9Lvw/xsqjaQlKLdJV7h1fCHfcYQ1C4SVMlu7OAekqWgu5d4SgvkBVU0pVpLlVsrSTBURFRkg==", "dev": true, "license": "MIT", "dependencies": { - "tabbable": "^6.2.0" + "@floating-ui/dom": "~1.1.1", + "vue-resize": "^2.0.0-alpha.1" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.0", + "vue": "^3.2.0" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + } } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "node_modules/focus-trap": { + "version": "7.6.5", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.6.5.tgz", + "integrity": "sha512-7Ke1jyybbbPZyZXFxEftUtxFGLMpE2n6A+z//m4CRDlj0hW+o3iYSmh8nFlYMurOiJVDmJRilUQtJr08KfIxlg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "tabbable": "^6.2.0" } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, + "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -5751,25 +6233,21 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", "dev": true, - "engines": { - "node": ">=14" + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data-encoder": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.2.tgz", - "integrity": "sha512-FCaIOVTRA9E0siY6FeXid7D5yrCqpsErplUkE2a1BEiKj1BE9z6FbKB4ntDTwC4NVLie9p+4E9nX4mWwEOT05A==", - "dev": true, "engines": { - "node": ">= 14.17" + "node": ">= 6" } }, "node_modules/forwarded": { @@ -5782,15 +6260,6 @@ "node": ">= 0.6" } }, - "node_modules/fp-and-or": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/fp-and-or/-/fp-and-or-0.1.4.tgz", - "integrity": "sha512-+yRYRhpnFPWXSly/6V4Lw9IfOV26uu30kynGJ03PW+MnjOEQe45RZ141QcS0aJehYBYA50GfCDnsRbFJdhssRw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -5801,32 +6270,12 @@ "node": ">= 0.6" } }, - "node_modules/fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -5834,6 +6283,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -5847,87 +6297,38 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/generatorics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz", - "integrity": "sha512-LuYDCS1DbKQsvChP1xHmAzHnGdd0z0K1XMebmbNbFzGZI62KODnV2CXA7zOqebiDzlK2sxXrPGfwlDzSm9aP4g==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": "*" + "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "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", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5936,61 +6337,62 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 0.4" } }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "node_modules/git-hooks-list": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-4.1.1.tgz", + "integrity": "sha512-cmP497iLq54AZnv4YRAEMnEyQ1eIn4tGKbmswqwmFV4GBnAqE8NLtWxxdXa++AalfgL5EBH4IxTPyquEuGY/jA==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fisker/git-hooks-list?sponsor=1" } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.2.tgz", + "integrity": "sha512-YT7U7Vye+t5fZ/QMkBFrTJ7ZQxInIUjwyAjVj84CYXqgBdv30MFUPGnBR6sQaVq6Is15wYJUsnzTuWaGRBhBAQ==", "dev": true, + "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -6001,6 +6403,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -6008,154 +6411,143 @@ "node": ">=10.13.0" } }, - "node_modules/global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "node_modules/glob/node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "ini": "2.0.0" + "@isaacs/cliui": "^8.0.2" }, "engines": { - "node": ">=10" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/glob/node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "license": "ISC", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "20 || >=22" } }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", "dev": true, + "license": "ISC", "dependencies": { - "define-properties": "^1.1.3" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 0.4" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "node_modules/glob/node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=10" + "node": "20 || >=22" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "node_modules/globals": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz", + "integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/got": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/got/-/got-12.5.0.tgz", - "integrity": "sha512-/Bneo/L6bLN1wDyJCeRZ3CLoixvwb9v3rE3IHulFSfTHwP85xSr4QatA8K0c6GlL5+mc4IZ57BzluNZJiXvHIg==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^6.0.4", - "cacheable-request": "^10.1.2", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=14.16" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/graphql": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", - "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } + "dev": true, + "license": "MIT" }, - "node_modules/graphql-resolvers-ast": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphql-resolvers-ast/-/graphql-resolvers-ast-1.4.0.tgz", - "integrity": "sha512-L4BeMFgPV7rwyISIvJ+QOsnMfc5+STMsaF097cLzJ9t/kizekDB5dMWNC+jq2pUWq0WoqYZypWYKwFL5vH4dUQ==", + "node_modules/gray-matter": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz", + "integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==", "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^3.13.1", + "kind-of": "^6.0.2", + "section-matter": "^1.0.0", + "strip-bom-string": "^1.0.0" + }, "engines": { - "node": ">= 6.0.0" + "node": ">=6.0" } }, - "node_modules/graphql-type-json": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.1.4.tgz", - "integrity": "sha512-B1zeWRF50alRvW94s/hpkGbVqvRLTtJD0yEyMs6KAvDSlNyBzJCu/d51fLZalqrVntuJAVgXYh13GbUEqe9MrQ==", + "node_modules/gray-matter/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "peerDependencies": { - "graphql": ">=0.4.0" + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" } }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "node_modules/gray-matter/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/has-flag": { @@ -6163,28 +6555,17 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -6192,11 +6573,15 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, "engines": { "node": ">= 0.4" }, @@ -6204,55 +6589,65 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "node_modules/has-yarn": { + "node_modules/hast-util-whitespace": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", - "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/hash-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hash-string/-/hash-string-1.0.0.tgz", - "integrity": "sha512-dtNNyxXobzHavayZwOwRWhBTqS9GX4jDjIMsGc0fDyaN2A+4zMn5Ua9ODDCggN6w3Spma6mAHL3ImmW3BkWDmQ==", - "dev": true - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" + "license": "MIT", + "bin": { + "he": "bin/he" } }, "node_modules/hookable": { @@ -6262,38 +6657,23 @@ "dev": true, "license": "MIT" }, - "node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/hosted-git-info/node_modules/lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } }, "node_modules/http-errors": { "version": "2.0.0", @@ -6312,64 +6692,6 @@ "node": ">= 0.8" } }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http2-wrapper": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz", - "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -6384,55 +6706,21 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, - "node_modules/ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", - "dev": true, - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -6444,38 +6732,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -6485,46 +6771,19 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } + "license": "ISC" }, "node_modules/interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -6535,66 +6794,41 @@ "node": ">= 0.10" } }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" + "builtin-modules": "^5.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" + "engines": { + "node": ">=18.20" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", "dev": true, "license": "MIT", "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" + "semver": "^7.7.1" } }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" + "hasown": "^2.0.2" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -6602,43 +6836,14 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==", "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, "node_modules/is-extglob": { @@ -6646,6 +6851,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6655,6 +6861,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6664,6 +6871,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -6671,283 +6879,95 @@ "node": ">=0.10.0" } }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.12.0" } }, - "node_modules/is-npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", - "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "node_modules/is-what": { + "version": "4.1.16", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", + "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": ">= 0.4" + "node": ">=12.13" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/mesqueeb" } }, - "node_modules/is-obj": { + "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "ISC" }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-what": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", - "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.13" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, - "node_modules/is-yarn-global": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz", - "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -6956,23 +6976,15 @@ "node": ">=8" } }, - "node_modules/iterall": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz", - "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==", - "dev": true - }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -6980,25 +6992,20 @@ "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", "dev": true, - "engines": { - "node": ">=10" + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/js-tokens": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", - "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", "dev": true, "license": "MIT" }, @@ -7007,6 +7014,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -7014,34 +7022,30 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=6" } }, - "node_modules/json-parse-helpfulerror": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", - "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, - "dependencies": { - "jju": "^1.1.0" - } + "license": "MIT" }, "node_modules/json-schema-to-ts": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.0.tgz", - "integrity": "sha512-UeVN/ery4/JeXI8h4rM8yZPxsH+KqPi/84qFxHfTGHZnWnK9D0UU9ZGYO+6XAaJLqCWMiks+ARuFOKAiSxJCHA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", "dev": true, "license": "MIT", "dependencies": { @@ -7053,48 +7057,64 @@ } }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "node_modules/jsonc-eslint-parser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", + "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", "dev": true, - "bin": { - "json5": "lib/cli.js" + "license": "MIT", + "peer": true, + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">=6" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" } }, - "node_modules/jsonlines": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", - "integrity": "sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==", - "dev": true - }, - "node_modules/jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "node_modules/jsonc-eslint-parser/node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "engines": [ - "node >= 0.2.0" - ] + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", "dev": true, + "license": "MIT", "dependencies": { "jws": "^3.2.2", "lodash.includes": "^4.3.0", @@ -7113,12 +7133,13 @@ } }, "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "dev": true, + "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } @@ -7128,42 +7149,30 @@ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", "dev": true, + "license": "MIT", "dependencies": { "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, "node_modules/keyv": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", - "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "dependencies": { - "package-json": "^8.1.0" - }, + "license": "MIT", "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/levn": { @@ -7171,6 +7180,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -7179,51 +7189,243 @@ "node": ">= 0.8.0" } }, - "node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, "engines": { - "node": ">=14" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/local-pkg": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", - "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "mlly": "^1.4.2", - "pkg-types": "^1.0.3" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=14" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/locate-path": { @@ -7231,6 +7433,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -7244,119 +7447,121 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, "node_modules/lodash.includes": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.isinteger": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.isnumber": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.isstring": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/long-timeout": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", "dev": true, "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "license": "MIT" }, "node_modules/lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, + "license": "ISC", "dependencies": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" } }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/magicast": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.3.tgz", - "integrity": "sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", + "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", - "source-map-js": "^1.0.2" + "@babel/parser": "^7.25.4", + "@babel/types": "^7.25.4", + "source-map-js": "^1.2.0" } }, "node_modules/make-dir": { @@ -7364,6 +7569,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -7374,943 +7580,1016 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/mark.js": { "version": "8.11.1", "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 0.6" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "dev": true, - "optional": true - }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, - "license": "MIT" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", "dev": true, - "engines": { - "node": ">= 8" + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" }, - "engines": { - "node": ">=8.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", "dev": true, "license": "MIT", - "bin": { - "mime": "cli.js" + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", "dev": true, - "engines": { - "node": ">= 0.6" + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", "dev": true, + "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" }, - "engines": { - "node": ">= 0.6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", "dev": true, - "engines": { - "node": ">=6" + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" }, - "engines": { - "node": "*" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "node_modules/mdast-util-to-hast": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" }, - "engines": { - "node": ">= 8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", "dev": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minipass-collect/node_modules/yallist": { + "node_modules/mdast-util-to-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "@types/mdast": "^4.0.0" }, - "optionalDependencies": { - "encoding": "^0.1.13" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/minipass-fetch/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 0.6" } }, - "node_modules/minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "dev": true, - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, - "node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.6" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/minipass-json-stream/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/minisearch": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.0.1.tgz", - "integrity": "sha512-xLeX/AwTJLzgBF2/bdUI7MEePwXtzaLExkRwu8YFGfLDwSe06KYkplqPodLANsqvfc5Ks/r5ItFUSjIp7+9xtw==", + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", "dev": true, - "license": "MIT" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/mlly": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", - "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.1", - "ufo": "^1.5.3" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/mongo-sql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/mongo-sql/-/mongo-sql-4.0.2.tgz", - "integrity": "sha512-/S2uYugCpOx73dwvWRZWlTBIE0U2e6jhIWi9bcfUrM9QkKR4U1yYjP6wXiYt+kdWqhV1lICgTLMoaKR1VMdd6A==", - "dev": true - }, - "node_modules/mongodb": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", - "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", "dev": true, - "dependencies": { - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" - }, - "engines": { - "node": ">=14.20.1" - }, - "optionalDependencies": { - "@mongodb-js/saslprep": "^1.1.0" - }, - "peerDependencies": { - "@aws-sdk/credential-providers": "^3.188.0", - "@mongodb-js/zstd": "^1.0.0", - "kerberos": "^1.0.0 || ^2.0.0", - "mongodb-client-encryption": ">=2.3.0 <3", - "snappy": "^7.2.2" - }, - "peerDependenciesMeta": { - "@aws-sdk/credential-providers": { - "optional": true - }, - "@mongodb-js/zstd": { - "optional": true + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, - "kerberos": { - "optional": true + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, - "mongodb-client-encryption": { - "optional": true + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" }, - "snappy": { - "optional": true + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" } - } + ], + "license": "MIT" }, - "node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" + "micromark-util-types": "^2.0.0" } }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", "dev": true, - "engines": { - "node": ">= 0.6" + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" } }, - "node_modules/neotraverse": { - "version": "0.6.14", - "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.14.tgz", - "integrity": "sha512-co+mqQYo1wf3CRWRHWOT1ZgG7gsdNZSrrQkWxVnGAlD/UA/IZuPlE9UNkGZRwTLeml+dT5BytRW4ANqzPQeNLg==", + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 18" + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" } }, - "node_modules/node-gyp": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", - "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^11.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "braces": "^3.0.3", + "picomatch": "^2.3.1" }, "engines": { - "node": "^12.13 || ^14.13 || >=16" + "node": ">=8.6" } }, - "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "dependencies": { - "abbrev": "^1.0.0" - }, + "license": "MIT", "bin": { - "nopt": "bin/nopt.js" + "mime": "cli.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=4" } }, - "node_modules/normalize-package-data": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.6" } }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { - "lru-cache": "^7.5.1" + "mime-db": "1.52.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.6" } }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">= 0.6" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/normalize-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-7.1.0.tgz", - "integrity": "sha512-JgkdydFdLe1E5Q7DpLvKVyBZOOwXYGhIbMbOMm3lJ06XKzaiit+qo1HciO3z3IFklStfarzJHVQf9ZcNPTvZlw==", + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, "engines": { - "node": ">=12.20" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, - "dependencies": { - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/npm-check-updates": { - "version": "16.14.20", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.20.tgz", - "integrity": "sha512-sYbIhun4DrjO7NFOTdvs11nCar0etEhZTsEjL47eM0TuiGMhmYughRCxG2SpGRmGAQ7AkwN7bw2lWzoE7q6yOQ==", + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/semver-utils": "^1.1.1", - "chalk": "^5.3.0", - "cli-table3": "^0.6.3", - "commander": "^10.0.1", - "fast-memoize": "^2.5.2", - "find-up": "5.0.0", - "fp-and-or": "^0.1.4", - "get-stdin": "^8.0.0", - "globby": "^11.0.4", - "hosted-git-info": "^5.1.0", - "ini": "^4.1.1", - "js-yaml": "^4.1.0", - "json-parse-helpfulerror": "^1.0.3", - "jsonlines": "^0.1.1", - "lodash": "^4.17.21", - "make-fetch-happen": "^11.1.1", - "minimatch": "^9.0.3", - "p-map": "^4.0.0", - "pacote": "15.2.0", - "parse-github-url": "^1.0.2", - "progress": "^2.0.3", - "prompts-ncu": "^3.0.0", - "rc-config-loader": "^4.1.3", - "remote-git-tags": "^3.0.0", - "rimraf": "^5.0.5", - "semver": "^7.5.4", - "semver-utils": "^1.1.4", - "source-map-support": "^0.5.21", - "spawn-please": "^2.0.2", - "strip-ansi": "^7.1.0", - "strip-json-comments": "^5.0.1", - "untildify": "^4.0.0", - "update-notifier": "^6.0.2" - }, - "bin": { - "ncu": "build/src/bin/cli.js", - "npm-check-updates": "build/src/bin/cli.js" - }, + "license": "ISC", "engines": { - "node": ">=14.14" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/npm-check-updates/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/minisearch": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.1.2.tgz", + "integrity": "sha512-R1Pd9eF+MD5JYDDSPAp/q1ougKglm14uEkPMvQ/05RGmx6G9wvmLTrTI/Q5iPNJLYqNdsDQ7qTGIcNWR+FrHmA==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } + "license": "MIT" }, - "node_modules/npm-check-updates/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" } }, - "node_modules/npm-check-updates/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } + "license": "MIT" }, - "node_modules/npm-check-updates/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, + "license": "MIT", "bin": { - "glob": "dist/esm/bin.mjs" + "mkdirp": "dist/cjs/src/bin.js" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm-check-updates/node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/npm-check-updates/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/napi-postinstall": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.2.4.tgz", + "integrity": "sha512-ZEzHJwBhZ8qQSbknHqYcdtQVr8zUgGyM/q6h6qAyhtyVMNrSgDhrC4disf03dYW0e+czXyLnZINnCTEkWy0eJg==", "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://opencollective.com/napi-postinstall" } }, - "node_modules/npm-check-updates/node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", - "dev": true, - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm-check-updates/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm-check-updates/node_modules/strip-json-comments": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", - "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-install-checks": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.2.0.tgz", - "integrity": "sha512-744wat5wAAHsxa4590mWO0tJ8PKxR8ORZsH9wGpQc3nWTzozMAgBN/XyqYw7mg3yqLM8dLwEnwSfKMmXAjF69g==", - "dev": true, - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-package-arg/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm-packlist": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", - "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "dependencies": { - "ignore-walk": "^6.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT" }, - "node_modules/npm-pick-manifest": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz", - "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==", + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", "dev": true, - "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^10.0.0", - "semver": "^7.3.5" - }, + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.6" } }, - "node_modules/npm-registry-fetch": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", - "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", - "dev": true, - "dependencies": { - "make-fetch-happen": "^11.0.0", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^10.0.0", - "proc-log": "^3.0.0" - }, + "node_modules/neotraverse": { + "version": "0.6.18", + "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.18.tgz", + "integrity": "sha512-Z4SmBUweYa09+o6pG+eASabEpP6QkQ70yHj351pQoEXIs8uHbaU2DWVmzBANKgflPa47A50PtB2+NgRpQvr7vA==", + "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 10" } }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "node_modules/npm-check-updates": { + "version": "17.1.18", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.18.tgz", + "integrity": "sha512-bkUy2g4v1i+3FeUf5fXMLbxmV95eG4/sS7lYE32GrUeVgQRfQEk39gpskksFunyaxQgTIdrvYbnuNbO/pSUSqw==", "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" + "license": "Apache-2.0", + "bin": { + "ncu": "build/cli.js", + "npm-check-updates": "build/cli.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.18.0 || >=20.0.0", + "npm": ">=8.12.1" } }, "node_modules/object-assign": { @@ -8318,85 +8597,17 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8422,6 +8633,7 @@ "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8431,56 +8643,54 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "node_modules/oniguruma-parser": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/oniguruma-to-es": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.3.tgz", + "integrity": "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==", "dev": true, + "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "oniguruma-parser": "^0.12.1", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "dev": true, - "engines": { - "node": ">=12.20" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -8496,6 +8706,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -8506,76 +8717,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz", - "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==", - "dev": true, - "dependencies": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", "dev": true, "license": "BlueOak-1.0.0" }, - "node_modules/pacote": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", - "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", - "dev": true, - "dependencies": { - "@npmcli/git": "^4.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^6.0.1", - "@npmcli/run-script": "^6.0.0", - "cacache": "^17.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^5.0.0", - "npm-package-arg": "^10.0.0", - "npm-packlist": "^7.0.0", - "npm-pick-manifest": "^8.0.0", - "npm-registry-fetch": "^14.0.0", - "proc-log": "^3.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^6.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^1.3.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" + "node_modules/package-json-validator": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/package-json-validator/-/package-json-validator-0.10.2.tgz", + "integrity": "sha512-i8qx/xfHdkzOzP39bNOtK6VauRrLdJoQf7L1lVRG2/evpLAd3vrj3EGNlzB9QiztBerxWAx5QXZh5z+Jfi0IvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yargs": "~17.7.2" }, "bin": { - "pacote": "lib/bin.js" + "pjv": "lib/bin/pjv.mjs" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=18" } }, "node_modules/parent-module": { @@ -8583,6 +8745,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -8590,18 +8753,6 @@ "node": ">=6" } }, - "node_modules/parse-github-url": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", - "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", - "dev": true, - "bin": { - "parse-github-url": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -8612,11 +8763,19 @@ "node": ">= 0.8" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8626,6 +8785,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -8635,6 +8795,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8643,7 +8804,8 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", @@ -8669,46 +8831,28 @@ "dev": true, "license": "ISC" }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", - "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "dev": true, "license": "MIT" }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "license": "MIT", "engines": { - "node": "*" + "node": ">= 14.16" } }, "node_modules/perfect-debounce": { @@ -8719,9 +8863,9 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -8730,6 +8874,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -8737,32 +8882,32 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "node_modules/pkg-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.1.0.tgz", + "integrity": "sha512-wmJwA+8ihJixSoHKxZJRBQG1oY8Yr9pGLzRmSsNms0iNWyHHAlZCa7mmKiFR10YPZuz/2k169JiS/inOjBCZ2A==", "dev": true, "license": "MIT", - "engines": { - "node": ">= 6" + "dependencies": { + "confbox": "^0.2.1", + "exsolve": "^1.0.1", + "pathe": "^2.0.3" } }, - "node_modules/pkg-types": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", - "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, "license": "MIT", - "dependencies": { - "confbox": "^0.1.7", - "mlly": "^1.7.1", - "pathe": "^1.1.2" + "engines": { + "node": ">=4" } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz", + "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==", "dev": true, "funding": [ { @@ -8780,79 +8925,18 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss/node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/preact": { - "version": "10.22.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.22.1.tgz", - "integrity": "sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==", + "node_modules/preact": { + "version": "10.26.9", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.26.9.tgz", + "integrity": "sha512-SSjF9vcnF27mJK1XyFMNJzFd5u3pQiATFqoaDy03XuN00u4ziveVVEGt5RKJrDR8MHE/wJo9Nnad56RLzS2RMA==", "dev": true, "license": "MIT", "funding": { @@ -8865,14 +8949,15 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", "bin": { @@ -8890,6 +8975,7 @@ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, + "license": "MIT", "dependencies": { "fast-diff": "^1.1.2" }, @@ -8897,99 +8983,17 @@ "node": ">=6.0.0" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=10" - }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prompts-ncu": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/prompts-ncu/-/prompts-ncu-3.0.0.tgz", - "integrity": "sha512-qyz9UxZ5MlPKWVhWrCmSZ1ahm2GVYdjLb8og2sg0IPth1KRuhcggHGuijz0e41dkx35p1t1q3GRISGH7QGALFA==", - "dev": true, - "dependencies": { - "kleur": "^4.0.1", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 14" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -9008,39 +9012,27 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/pupa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", - "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", "dev": true, - "dependencies": { - "escape-goat": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, "node_modules/qs": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", - "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -9049,6 +9041,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/quansync": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", + "integrity": "sha512-t41VRkMYbkHyCYmOvx/6URnN80H7k4X0lLdBMGsz+maAwrJQYB1djpV6vHrQIBE0WBSGqhtEHrK9U3DWWH8v7A==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9067,19 +9076,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + ], + "license": "MIT" }, "node_modules/range-parser": { "version": "1.2.1", @@ -9107,343 +9105,252 @@ "node": ">= 0.8" } }, - "node_modules/raw-body/node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", "dev": true, "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "resolve": "^1.1.6" }, - "bin": { - "rc": "cli.js" + "engines": { + "node": ">= 0.10" } }, - "node_modules/rc-config-loader": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", - "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "node_modules/regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.3.4", - "js-yaml": "^4.1.0", - "json5": "^2.2.2", - "require-from-string": "^2.0.2" + "regex-utilities": "^2.3.0" } }, - "node_modules/rc/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "dev": true, - "engines": { - "node": ">=0.10.0" + "license": "MIT", + "dependencies": { + "regex-utilities": "^2.3.0" } }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", "dev": true, "license": "MIT" }, - "node_modules/read-package-json": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", - "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^5.0.0", - "npm-normalize-package-bin": "^3.0.0" + "jsesc": "~3.0.2" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/read-package-json-fast": { + "node_modules/regjsparser/node_modules/jsesc": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=6" } }, - "node_modules/read-package-json/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/read-package-json/node_modules/glob": { - "version": "10.3.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", - "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=4" } }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", "dev": true, "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, + "license": "MIT", "engines": { - "node": ">= 0.10" + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true, "license": "MIT" }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "node_modules/rolldown": { + "version": "1.0.0-beta.11-commit.f051675", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-beta.11-commit.f051675.tgz", + "integrity": "sha512-g8MCVkvg2GnrrG+j+WplOTx1nAmjSwYOMSOQI0qfxf8D4NmYZqJuG3f85yWK64XXQv6pKcXZsfMkOPs9B6B52A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" + "@oxc-project/runtime": "=0.72.2", + "@oxc-project/types": "=0.72.2", + "@rolldown/pluginutils": "1.0.0-beta.11-commit.f051675", + "ansis": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/registry-auth-token": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", - "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", - "dev": true, - "dependencies": { - "@pnpm/npm-conf": "^1.0.4" + "bin": { + "rolldown": "bin/cli.mjs" }, - "engines": { - "node": ">=14" + "optionalDependencies": { + "@rolldown/binding-darwin-arm64": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-darwin-x64": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-freebsd-x64": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-linux-arm64-musl": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-linux-x64-gnu": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-linux-x64-musl": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-wasm32-wasi": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-win32-ia32-msvc": "1.0.0-beta.11-commit.f051675", + "@rolldown/binding-win32-x64-msvc": "1.0.0-beta.11-commit.f051675" } }, - "node_modules/registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "node_modules/rolldown-plugin-dts": { + "version": "0.13.8", + "resolved": "https://registry.npmjs.org/rolldown-plugin-dts/-/rolldown-plugin-dts-0.13.8.tgz", + "integrity": "sha512-jib3ui3rgADoAXwyuCRid74yoi0ZGTLD0P/bQQXFeaVIdhh4ZXwU2RJ0eUmSFJX1fQVc+a3lfccrPEuV7vvRJg==", "dev": true, + "license": "MIT", "dependencies": { - "rc": "1.2.8" + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.5", + "@babel/types": "^7.27.3", + "ast-kit": "^2.1.0", + "birpc": "^2.3.0", + "debug": "^4.4.1", + "dts-resolver": "^2.1.1", + "get-tsconfig": "^4.10.1" }, "engines": { - "node": ">=12" + "node": ">=20.18.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/remote-git-tags": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", - "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dev": true, - "dependencies": { - "lowercase-keys": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" + "url": "https://github.com/sponsors/sxzz" }, - "bin": { - "rimraf": "bin.js" + "peerDependencies": { + "@typescript/native-preview": ">=7.0.0-dev.20250601.1", + "rolldown": "^1.0.0-beta.9", + "typescript": "^5.0.0", + "vue-tsc": "~2.2.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "peerDependenciesMeta": { + "@typescript/native-preview": { + "optional": true + }, + "typescript": { + "optional": true + }, + "vue-tsc": { + "optional": true + } } }, "node_modules/rollup": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz", - "integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==", + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.41.1.tgz", + "integrity": "sha512-cPmwD3FnFv8rKMBc1MxWCwVQFxwf1JEmSX3iQXrRVVG15zerAIXRjMFVWnd5Q5QvgKF7Aj+5ykXFhUl+QGnyOw==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -9453,25 +9360,36 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.1", - "@rollup/rollup-android-arm64": "4.18.1", - "@rollup/rollup-darwin-arm64": "4.18.1", - "@rollup/rollup-darwin-x64": "4.18.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.1", - "@rollup/rollup-linux-arm-musleabihf": "4.18.1", - "@rollup/rollup-linux-arm64-gnu": "4.18.1", - "@rollup/rollup-linux-arm64-musl": "4.18.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.1", - "@rollup/rollup-linux-riscv64-gnu": "4.18.1", - "@rollup/rollup-linux-s390x-gnu": "4.18.1", - "@rollup/rollup-linux-x64-gnu": "4.18.1", - "@rollup/rollup-linux-x64-musl": "4.18.1", - "@rollup/rollup-win32-arm64-msvc": "4.18.1", - "@rollup/rollup-win32-ia32-msvc": "4.18.1", - "@rollup/rollup-win32-x64-msvc": "4.18.1", + "@rollup/rollup-android-arm-eabi": "4.41.1", + "@rollup/rollup-android-arm64": "4.41.1", + "@rollup/rollup-darwin-arm64": "4.41.1", + "@rollup/rollup-darwin-x64": "4.41.1", + "@rollup/rollup-freebsd-arm64": "4.41.1", + "@rollup/rollup-freebsd-x64": "4.41.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.41.1", + "@rollup/rollup-linux-arm-musleabihf": "4.41.1", + "@rollup/rollup-linux-arm64-gnu": "4.41.1", + "@rollup/rollup-linux-arm64-musl": "4.41.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.41.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-gnu": "4.41.1", + "@rollup/rollup-linux-riscv64-musl": "4.41.1", + "@rollup/rollup-linux-s390x-gnu": "4.41.1", + "@rollup/rollup-linux-x64-gnu": "4.41.1", + "@rollup/rollup-linux-x64-musl": "4.41.1", + "@rollup/rollup-win32-arm64-msvc": "4.41.1", + "@rollup/rollup-win32-ia32-msvc": "4.41.1", + "@rollup/rollup-win32-x64-msvc": "4.41.1", "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -9491,28 +9409,11 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, - "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -9531,97 +9432,55 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", - "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/search-insights": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.15.0.tgz", - "integrity": "sha512-ch2sPCUDD4sbPQdknVl9ALSi9H7VyoeVbsxznYz6QV55jJ8CI3EtwpO1i84keN4+hF5IeHWIeGvc08530JkVXQ==", + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", "dev": true, "license": "MIT", "peer": true }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", - "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "node_modules/section-matter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz", + "integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==", "dev": true, + "license": "MIT", "dependencies": { - "semver": "^7.3.5" + "extend-shallow": "^2.0.1", + "kind-of": "^6.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/semver-utils": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/semver-utils/-/semver-utils-1.1.4.tgz", - "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", - "dev": true - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dev": true, "license": "MIT", "dependencies": { @@ -9670,77 +9529,22 @@ "node": ">= 0.8" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dev": true, "license": "MIT", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/serve-static/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "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" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -9753,6 +9557,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9765,6 +9570,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9774,6 +9580,7 @@ "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "glob": "^7.0.0", "interpret": "^1.0.0", @@ -9786,24 +9593,67 @@ "node": ">=4" } }, - "node_modules/shiki": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.10.3.tgz", - "integrity": "sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ==", + "node_modules/shelljs/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { - "@shikijs/core": "1.10.3", - "@types/hast": "^3.0.4" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/short-hash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/short-hash/-/short-hash-1.0.0.tgz", - "integrity": "sha512-qbUCD2Pkl4IXRyVqneEjGnUr0NGDGLzZnBUVGJngIQZf/FrhOL0yJhH+JQzak0t8xMmScIKpoX1SxOsPHdwa4w==", + "node_modules/shelljs/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shelljs/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/shiki": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.6.0.tgz", + "integrity": "sha512-tKn/Y0MGBTffQoklaATXmTqDU02zx8NYBGQ+F6gy87/YjKbizcLd+Cybh/0ZtOBX9r1NEnAy/GTRDKtOsc1L9w==", "dev": true, + "license": "MIT", "dependencies": { - "hash-string": "^1.0.0" + "@shikijs/core": "3.6.0", + "@shikijs/engine-javascript": "3.6.0", + "@shikijs/engine-oniguruma": "3.6.0", + "@shikijs/langs": "3.6.0", + "@shikijs/themes": "3.6.0", + "@shikijs/types": "3.6.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" } }, "node_modules/shx": { @@ -9811,6 +9661,7 @@ "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.3", "shelljs": "^0.8.5" @@ -9823,16 +9674,17 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -9841,74 +9693,93 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sift": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", - "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sigstore": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", - "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, + "license": "MIT", "dependencies": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "@sigstore/sign": "^1.0.0", - "@sigstore/tuf": "^1.0.3", - "make-fetch-happen": "^11.0.1" - }, - "bin": { - "sigstore": "bin/sigstore.js" + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, + "license": "MIT", + "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" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "node_modules/sift": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", + "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", "dev": true, "license": "MIT", "dependencies": { @@ -9916,7 +9787,7 @@ "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -9935,6 +9806,24 @@ "ws": "~8.17.1" } }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/socket.io-parser": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", @@ -9949,129 +9838,112 @@ "node": ">=10.0.0" } }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" + "ms": "^2.1.3" }, "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, + "license": "MIT", "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "ms": "^2.1.3" }, "engines": { - "node": ">= 10" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", + "node_modules/sort-object-keys": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz", + "integrity": "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sort-package-json": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/sort-package-json/-/sort-package-json-3.2.1.tgz", + "integrity": "sha512-rTfRdb20vuoAn7LDlEtCqOkYfl2X+Qze6cLbNOzcDpbmKEhJI30tTN44d5shbKJnXsvz24QQhlCm81Bag7EOKg==", "dev": true, + "license": "MIT", "dependencies": { - "is-plain-obj": "^1.0.0" + "detect-indent": "^7.0.1", + "detect-newline": "^4.0.1", + "git-hooks-list": "^4.0.0", + "is-plain-obj": "^4.1.0", + "semver": "^7.7.1", + "sort-object-keys": "^1.1.3", + "tinyglobby": "^0.2.12" }, + "bin": { + "sort-package-json": "cli.js" + } + }, + "node_modules/sort-package-json/node_modules/detect-indent": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-7.0.1.tgz", + "integrity": "sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=12.20" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "node_modules/sort-package-json/node_modules/detect-newline": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-4.0.1.tgz", + "integrity": "sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "dev": true, - "optional": true, - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/spawn-please": { + "node_modules/space-separated-tokens": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-2.0.2.tgz", - "integrity": "sha512-KM8coezO6ISQ89c1BzyWNtcn2V2kAVtwIXd3cN/V5a0xPYc1F/vydrRc01wsKFEQ/p+V1a4sw4z2yMITIXrgGw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", - "dev": true - }, "node_modules/speakingurl": { "version": "14.0.1", "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", @@ -10082,25 +9954,21 @@ "node": ">=0.10.0" } }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true, - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "BSD-3-Clause" }, - "node_modules/ssri/node_modules/minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", + "node_modules/stable-hash-x": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.1.1.tgz", + "integrity": "sha512-l0x1D6vhnsNUGPFVDx45eif0y6eedVC8nm5uACTrVFJFtl2mLRW17aWtVyxFCpn5t94VUPkjU8vSLwIuwwqtJQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=12.0.0" } }, "node_modules/stackback": { @@ -10121,26 +9989,18 @@ } }, "node_modules/std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", "dev": true, "license": "MIT" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10156,6 +10016,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10165,49 +10026,19 @@ "node": ">=8" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/strip-ansi": { @@ -10215,6 +10046,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10228,6 +10060,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10235,22 +10068,30 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "node_modules/strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "node_modules/strip-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.0.0.tgz", + "integrity": "sha512-mnVSV2l+Zv6BLpSD/8V87CW/y9EmmbYzGCIavsnsI6/nwn26DwffM/yztm30Z/I2DY9wdS3vXVCMnHDgZaVNoA==", "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.1" + }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { @@ -10258,6 +10099,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -10265,287 +10107,222 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/strip-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", - "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", + "node_modules/superjson": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz", + "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==", "dev": true, "license": "MIT", "dependencies": { - "js-tokens": "^9.0.0" + "copy-anything": "^3.0.2" }, - "funding": { - "url": "https://github.com/sponsors/antfu" + "engines": { + "node": ">=16" } }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" } }, - "node_modules/sucrase/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/synckit": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.8.tgz", + "integrity": "sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "@pkgr/core": "^0.2.4" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/synckit" } }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz", + "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=6" } }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "dev": true, "license": "ISC", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=18" } }, - "node_modules/sucrase/node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=18" } }, - "node_modules/sucrase/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", "dev": true, "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/superjson": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.1.tgz", - "integrity": "sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "copy-anything": "^3.0.2" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { - "has-flag": "^4.0.0" + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" }, "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, - "node_modules/synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", + "node_modules/test-exclude/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": "^14.18.0 || >=16.0.0" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { - "url": "https://opencollective.com/unts" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", "dev": true, "license": "MIT" }, - "node_modules/tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "node_modules/tinyexec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz", + "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==", "dev": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } + "license": "MIT" }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, + "license": "MIT", "dependencies": { - "minipass": "^3.0.0" + "fdir": "^6.4.4", + "picomatch": "^4.0.2" }, "engines": { - "node": ">= 8" - } - }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" + "node": ">=12.0.0" }, - "engines": { - "node": ">=8" + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.5", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.5.tgz", + "integrity": "sha512-4BG7puHpVsIYxZUbiUE3RqGloLaSSwzYie5jvasC4LWuBWzZawynvYouhjbQKw2JuIGYdm0DzIxl8iVidKlUEw==", "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" }, - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "node_modules/tinypool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.0.tgz", + "integrity": "sha512-7CotroY9a8DKsKprEy/a14aCCm8jYVmR7aFy4fpkZM8sdpNJbKkixuNjgM50yCmip2ezc8z4N7k3oe2+rfRJCQ==", "dev": true, "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, "engines": { - "node": ">=0.8" + "node": "^18.0.0 || >=20.0.0" } }, - "node_modules/tinybench": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", - "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, "license": "MIT", "engines": { @@ -10553,29 +10330,21 @@ } }, "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.3.tgz", + "integrity": "sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -10593,37 +10362,15 @@ "node": ">=0.6" } }, - "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/traverse": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", - "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "dev": true, - "engines": { - "node": ">= 0.4" - }, + "license": "MIT", "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, "node_modules/ts-algebra": { @@ -10634,965 +10381,531 @@ "license": "MIT" }, "node_modules/ts-api-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", - "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16.13.0" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" + "typescript": ">=4.8.4" } }, - "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsup": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.1.2.tgz", - "integrity": "sha512-Gzw/PXSX/z0aYMNmkcI54bKKFVFJQbLne+EqTJZeQ3lNT3QpumjtMU4rl+ZwTTp8oRF3ahMbEAxT2sZPJLFSrg==", + "node_modules/tsdown": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/tsdown/-/tsdown-0.12.7.tgz", + "integrity": "sha512-VJjVaqJfIQuQwtOoeuEJMOJUf3MPDrfX0X7OUNx3nq5pQeuIl3h58tmdbM1IZcu8Dn2j8NQjLh+5TXa0yPb9zg==", "dev": true, "license": "MIT", "dependencies": { - "bundle-require": "^5.0.0", + "ansis": "^4.1.0", "cac": "^6.7.14", - "chokidar": "^3.6.0", - "consola": "^3.2.3", - "debug": "^4.3.5", - "esbuild": "^0.23.0", - "execa": "^5.0.0", - "globby": "^11.0.3", - "joycon": "^3.1.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.18.1", - "source-map": "0.8.0-beta.0", - "sucrase": "^3.35.0", - "tree-kill": "^1.2.2" + "chokidar": "^4.0.3", + "debug": "^4.4.1", + "diff": "^8.0.2", + "empathic": "^1.1.0", + "hookable": "^5.5.3", + "rolldown": "1.0.0-beta.11-commit.f051675", + "rolldown-plugin-dts": "^0.13.8", + "semver": "^7.7.2", + "tinyexec": "^1.0.1", + "tinyglobby": "^0.2.14", + "unconfig": "^7.3.2" }, "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" + "tsdown": "dist/run.mjs" }, "engines": { - "node": ">=18" + "node": ">=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" }, "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" + "@arethetypeswrong/core": "^0.18.1", + "publint": "^0.3.0", + "typescript": "^5.0.0", + "unplugin-lightningcss": "^0.4.0", + "unplugin-unused": "^0.5.0" }, "peerDependenciesMeta": { - "@microsoft/api-extractor": { + "@arethetypeswrong/core": { "optional": true }, - "@swc/core": { + "publint": { "optional": true }, - "postcss": { + "typescript": { "optional": true }, - "typescript": { + "unplugin-lightningcss": { + "optional": true + }, + "unplugin-unused": { "optional": true } } }, - "node_modules/tsup/node_modules/@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", - "cpu": [ - "ppc64" - ], + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/twoslash": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/twoslash/-/twoslash-0.3.1.tgz", + "integrity": "sha512-OGqMTGvqXTcb92YQdwGfEdK0nZJA64Aj/ChLOelbl3TfYch2IoBST0Yx4C0LQ7Lzyqm9RpgcpgDxeXQIz4p2Kg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@typescript/vfs": "^1.6.1", + "twoslash-protocol": "0.3.1" + }, + "peerDependencies": { + "typescript": "^5.5.0" } }, - "node_modules/tsup/node_modules/@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", - "cpu": [ - "arm" - ], + "node_modules/twoslash-protocol": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/twoslash-protocol/-/twoslash-protocol-0.3.1.tgz", + "integrity": "sha512-BMePTL9OkuNISSyyMclBBhV2s9++DiOCyhhCoV5Kaht6eaWLwVjCCUJHY33eZJPsyKeZYS8Wzz0h+XI01VohVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/twoslash-vue": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/twoslash-vue/-/twoslash-vue-0.3.1.tgz", + "integrity": "sha512-9/PS0/iL2m8G6N2ILdI18sZ8l6ex+W2nN5jIaTpfFPlnY0MOX2G5UxEVs+AuNimM9SwEnwfiIuDY9ubDCIQpSQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@vue/language-core": "2.2.4", + "twoslash": "0.3.1", + "twoslash-protocol": "0.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "typescript": "^5.5.0" } }, - "node_modules/tsup/node_modules/@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", - "cpu": [ - "arm64" - ], + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "prelude-ls": "^1.2.1" + }, "engines": { - "node": ">=18" + "node": ">= 0.8.0" } }, - "node_modules/tsup/node_modules/@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, "engines": { - "node": ">=18" + "node": ">= 0.6" } }, - "node_modules/tsup/node_modules/@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", - "cpu": [ - "arm64" - ], + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">=18" + "node": ">=14.17" } }, - "node_modules/tsup/node_modules/@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", - "cpu": [ - "x64" - ], + "node_modules/typescript-eslint": { + "version": "8.33.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.33.1.tgz", + "integrity": "sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.33.1", + "@typescript-eslint/parser": "8.33.1", + "@typescript-eslint/utils": "8.33.1" + }, "engines": { - "node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, - "node_modules/tsup/node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", - "cpu": [ - "arm64" - ], + "node_modules/unconfig": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/unconfig/-/unconfig-7.3.2.tgz", + "integrity": "sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@quansync/fs": "^0.1.1", + "defu": "^6.1.4", + "jiti": "^2.4.2", + "quansync": "^0.2.8" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" } }, - "node_modules/tsup/node_modules/@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", - "cpu": [ - "x64" - ], + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/tsup/node_modules/@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", - "cpu": [ - "arm" - ], + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tsup/node_modules/@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", - "cpu": [ - "arm64" - ], + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tsup/node_modules/@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", - "cpu": [ - "ia32" - ], + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tsup/node_modules/@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", - "cpu": [ - "loong64" - ], + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tsup/node_modules/@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", - "cpu": [ - "mips64el" - ], + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/tsup/node_modules/@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", - "cpu": [ - "ppc64" - ], + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">= 0.8" } }, - "node_modules/tsup/node_modules/@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", - "cpu": [ - "riscv64" - ], + "node_modules/unplugin": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.5.tgz", + "integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "acorn": "^8.14.1", + "picomatch": "^4.0.2", + "webpack-virtual-modules": "^0.6.2" + }, "engines": { - "node": ">=18" + "node": ">=18.12.0" } }, - "node_modules/tsup/node_modules/@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", - "cpu": [ - "s390x" - ], + "node_modules/unplugin-unused": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/unplugin-unused/-/unplugin-unused-0.5.0.tgz", + "integrity": "sha512-czXny3h/P/Tl5ZOnV5tSf6kswAniHjgJF0slpzBPLkq0zGGKDYa1jgWMAdbWJNu7B1YSmBJY4zf3Q/v9w0+/cg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "js-tokens": "^9.0.1", + "picocolors": "^1.1.1", + "pkg-types": "^2.1.0", + "unplugin": "^2.3.2" + }, "engines": { - "node": ">=18" + "node": ">=20.18.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/tsup/node_modules/@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", - "cpu": [ - "x64" - ], + "node_modules/unplugin/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/tsup/node_modules/@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", - "cpu": [ - "x64" - ], + "node_modules/unrs-resolver": { + "version": "1.7.11", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.7.11.tgz", + "integrity": "sha512-OhuAzBImFPjKNgZ2JwHMfGFUA6NSbRegd1+BPjC1Y0E6X9Y/vJ4zKeGmIMqmlYboj6cMNEwKI+xQisrg4J0HaQ==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" + "dependencies": { + "napi-postinstall": "^0.2.2" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-darwin-arm64": "1.7.11", + "@unrs/resolver-binding-darwin-x64": "1.7.11", + "@unrs/resolver-binding-freebsd-x64": "1.7.11", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.7.11", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.7.11", + "@unrs/resolver-binding-linux-arm64-gnu": "1.7.11", + "@unrs/resolver-binding-linux-arm64-musl": "1.7.11", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.7.11", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.7.11", + "@unrs/resolver-binding-linux-riscv64-musl": "1.7.11", + "@unrs/resolver-binding-linux-s390x-gnu": "1.7.11", + "@unrs/resolver-binding-linux-x64-gnu": "1.7.11", + "@unrs/resolver-binding-linux-x64-musl": "1.7.11", + "@unrs/resolver-binding-wasm32-wasi": "1.7.11", + "@unrs/resolver-binding-win32-arm64-msvc": "1.7.11", + "@unrs/resolver-binding-win32-ia32-msvc": "1.7.11", + "@unrs/resolver-binding-win32-x64-msvc": "1.7.11" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], - "engines": { - "node": ">=18" + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/tsup/node_modules/@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", - "cpu": [ - "x64" - ], + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/tsup/node_modules/@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", - "cpu": [ - "x64" - ], + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], "engines": { - "node": ">=18" + "node": ">= 0.4.0" } }, - "node_modules/tsup/node_modules/@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsup/node_modules/@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsup/node_modules/@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", - "cpu": [ - "x64" - ], + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" ], - "engines": { - "node": ">=18" - } - }, - "node_modules/tsup/node_modules/esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", - "dev": true, - "hasInstallScript": true, "license": "MIT", "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" - } - }, - "node_modules/tsup/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/tsup/node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/tsup/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/tsup/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "node_modules/tsup/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/tuf-js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", - "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", - "dev": true, - "dependencies": { - "@tufjs/models": "1.0.4", - "debug": "^4.3.4", - "make-fetch-happen": "^11.1.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "uuid": "dist/esm/bin/uuid" } }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/validate-npm-package-name": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-6.0.1.tgz", + "integrity": "sha512-OaI//3H0J7ZkR1OqlhGA8cA+Cbk/2xFOQpJOt5+s27/ta9eZwpeervh4Mxh4w0im/kdgktowaqVNR7QOrUd7Yg==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, + "license": "ISC", "engines": { - "node": ">= 0.8.0" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, "license": "MIT", "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", "dev": true, "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", "dev": true, + "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, - "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", - "dev": true, - "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "dependencies": { - "crypto-random-string": "^4.0.0" + "vite": "bin/vite.js" }, "engines": { - "node": ">=12" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-notifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", - "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", - "dev": true, - "dependencies": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", - "configstore": "^6.0.0", - "has-yarn": "^3.0.0", - "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", - "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", - "pupa": "^3.1.0", - "semver": "^7.3.7", - "semver-diff": "^4.0.0", - "xdg-basedir": "^5.1.0" + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": ">=14.16" + "optionalDependencies": { + "fsevents": "~2.3.3" }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" - } - }, - "node_modules/update-notifier/node_modules/chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/vite": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.4.tgz", - "integrity": "sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -11602,6 +10915,9 @@ "sass": { "optional": true }, + "sass-embedded": { + "optional": true + }, "stylus": { "optional": true }, @@ -11610,9082 +10926,421 @@ }, "terser": { "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", - "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitepress": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.3.1.tgz", - "integrity": "sha512-soZDpg2rRVJNIM/IYMNDPPr+zTHDA5RbLDHAxacRu+Q9iZ2GwSR0QSUlLs+aEZTkG0SOX1dc8RmUYwyuxK8dfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@docsearch/css": "^3.6.0", - "@docsearch/js": "^3.6.0", - "@shikijs/core": "^1.10.3", - "@shikijs/transformers": "^1.10.3", - "@types/markdown-it": "^14.1.1", - "@vitejs/plugin-vue": "^5.0.5", - "@vue/devtools-api": "^7.3.5", - "@vue/shared": "^3.4.31", - "@vueuse/core": "^10.11.0", - "@vueuse/integrations": "^10.11.0", - "focus-trap": "^7.5.4", - "mark.js": "8.11.1", - "minisearch": "^7.0.0", - "shiki": "^1.10.3", - "vite": "^5.3.3", - "vue": "^3.4.31" - }, - "bin": { - "vitepress": "bin/vitepress.js" - }, - "peerDependencies": { - "markdown-it-mathjax3": "^4", - "postcss": "^8" - }, - "peerDependenciesMeta": { - "markdown-it-mathjax3": { - "optional": true - }, - "postcss": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.0", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.0", - "@vitest/ui": "1.6.0", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true }, - "jsdom": { + "tsx": { "optional": true - } - } - }, - "node_modules/vitest/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/vitest/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/vitest/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vitest/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/vitest/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/vue": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.32.tgz", - "integrity": "sha512-9mCGIAi/CAq7GtaLLLp2J92pEic+HArstG+pq6F+H7+/jB9a0Z7576n4Bh4k79/50L1cKMIhZC3MC0iGpl+1IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.4.32", - "@vue/compiler-sfc": "3.4.32", - "@vue/runtime-dom": "3.4.32", - "@vue/server-renderer": "3.4.32", - "@vue/shared": "3.4.32" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", - "dev": true, - "dependencies": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", - "dev": true, - "dependencies": { - "string-width": "^5.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/widest-line/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/widest-line/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/widest-line/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", - "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true - }, - "@algolia/autocomplete-core": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.9.3.tgz", - "integrity": "sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==", - "dev": true, - "requires": { - "@algolia/autocomplete-plugin-algolia-insights": "1.9.3", - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "@algolia/autocomplete-plugin-algolia-insights": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.9.3.tgz", - "integrity": "sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==", - "dev": true, - "requires": { - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "@algolia/autocomplete-preset-algolia": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.9.3.tgz", - "integrity": "sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==", - "dev": true, - "requires": { - "@algolia/autocomplete-shared": "1.9.3" - } - }, - "@algolia/autocomplete-shared": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.9.3.tgz", - "integrity": "sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==", - "dev": true, - "requires": {} - }, - "@algolia/cache-browser-local-storage": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-browser-local-storage/-/cache-browser-local-storage-4.24.0.tgz", - "integrity": "sha512-t63W9BnoXVrGy9iYHBgObNXqYXM3tYXCjDSHeNwnsc324r4o5UiVKUiAB4THQ5z9U5hTj6qUvwg/Ez43ZD85ww==", - "dev": true, - "requires": { - "@algolia/cache-common": "4.24.0" - } - }, - "@algolia/cache-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-common/-/cache-common-4.24.0.tgz", - "integrity": "sha512-emi+v+DmVLpMGhp0V9q9h5CdkURsNmFC+cOS6uK9ndeJm9J4TiqSvPYVu+THUP8P/S08rxf5x2P+p3CfID0Y4g==", - "dev": true - }, - "@algolia/cache-in-memory": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/cache-in-memory/-/cache-in-memory-4.24.0.tgz", - "integrity": "sha512-gDrt2so19jW26jY3/MkFg5mEypFIPbPoXsQGQWAi6TrCPsNOSEYepBMPlucqWigsmEy/prp5ug2jy/N3PVG/8w==", - "dev": true, - "requires": { - "@algolia/cache-common": "4.24.0" - } - }, - "@algolia/client-account": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-account/-/client-account-4.24.0.tgz", - "integrity": "sha512-adcvyJ3KjPZFDybxlqnf+5KgxJtBjwTPTeyG2aOyoJvx0Y8dUQAEOEVOJ/GBxX0WWNbmaSrhDURMhc+QeevDsA==", - "dev": true, - "requires": { - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "@algolia/client-analytics": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-4.24.0.tgz", - "integrity": "sha512-y8jOZt1OjwWU4N2qr8G4AxXAzaa8DBvyHTWlHzX/7Me1LX8OayfgHexqrsL4vSBcoMmVw2XnVW9MhL+Y2ZDJXg==", - "dev": true, - "requires": { - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "@algolia/client-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-4.24.0.tgz", - "integrity": "sha512-bc2ROsNL6w6rqpl5jj/UywlIYC21TwSSoFHKl01lYirGMW+9Eek6r02Tocg4gZ8HAw3iBvu6XQiM3BEbmEMoiA==", - "dev": true, - "requires": { - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "@algolia/client-personalization": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-4.24.0.tgz", - "integrity": "sha512-l5FRFm/yngztweU0HdUzz1rC4yoWCFo3IF+dVIVTfEPg906eZg5BOd1k0K6rZx5JzyyoP4LdmOikfkfGsKVE9w==", - "dev": true, - "requires": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "@algolia/client-search": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-4.24.0.tgz", - "integrity": "sha512-uRW6EpNapmLAD0mW47OXqTP8eiIx5F6qN9/x/7HHO6owL3N1IXqydGwW5nhDFBrV+ldouro2W1VX3XlcUXEFCA==", - "dev": true, - "requires": { - "@algolia/client-common": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "@algolia/logger-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-common/-/logger-common-4.24.0.tgz", - "integrity": "sha512-LLUNjkahj9KtKYrQhFKCzMx0BY3RnNP4FEtO+sBybCjJ73E8jNdaKJ/Dd8A/VA4imVHP5tADZ8pn5B8Ga/wTMA==", - "dev": true - }, - "@algolia/logger-console": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/logger-console/-/logger-console-4.24.0.tgz", - "integrity": "sha512-X4C8IoHgHfiUROfoRCV+lzSy+LHMgkoEEU1BbKcsfnV0i0S20zyy0NLww9dwVHUWNfPPxdMU+/wKmLGYf96yTg==", - "dev": true, - "requires": { - "@algolia/logger-common": "4.24.0" - } - }, - "@algolia/recommend": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-4.24.0.tgz", - "integrity": "sha512-P9kcgerfVBpfYHDfVZDvvdJv0lEoCvzNlOy2nykyt5bK8TyieYyiD0lguIJdRZZYGre03WIAFf14pgE+V+IBlw==", - "dev": true, - "requires": { - "@algolia/cache-browser-local-storage": "4.24.0", - "@algolia/cache-common": "4.24.0", - "@algolia/cache-in-memory": "4.24.0", - "@algolia/client-common": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/logger-console": "4.24.0", - "@algolia/requester-browser-xhr": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/requester-node-http": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "@algolia/requester-browser-xhr": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-4.24.0.tgz", - "integrity": "sha512-Z2NxZMb6+nVXSjF13YpjYTdvV3032YTBSGm2vnYvYPA6mMxzM3v5rsCiSspndn9rzIW4Qp1lPHBvuoKJV6jnAA==", - "dev": true, - "requires": { - "@algolia/requester-common": "4.24.0" - } - }, - "@algolia/requester-common": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-common/-/requester-common-4.24.0.tgz", - "integrity": "sha512-k3CXJ2OVnvgE3HMwcojpvY6d9kgKMPRxs/kVohrwF5WMr2fnqojnycZkxPoEg+bXm8fi5BBfFmOqgYztRtHsQA==", - "dev": true - }, - "@algolia/requester-node-http": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-4.24.0.tgz", - "integrity": "sha512-JF18yTjNOVYvU/L3UosRcvbPMGT9B+/GQWNWnenIImglzNVGpyzChkXLnrSf6uxwVNO6ESGu6oN8MqcGQcjQJw==", - "dev": true, - "requires": { - "@algolia/requester-common": "4.24.0" - } - }, - "@algolia/transporter": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/@algolia/transporter/-/transporter-4.24.0.tgz", - "integrity": "sha512-86nI7w6NzWxd1Zp9q3413dRshDqAzSbsQjhcDhPIatEFiZrL1/TjnHL8S7jVKFePlIMzDsZWXAXwXzcok9c5oA==", - "dev": true, - "requires": { - "@algolia/cache-common": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/requester-common": "4.24.0" - } - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "dev": true - }, - "@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", - "dev": true - }, - "@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.14.0" - } - }, - "@babel/types": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", - "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true - }, - "@docsearch/css": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.6.1.tgz", - "integrity": "sha512-VtVb5DS+0hRIprU2CO6ZQjK2Zg4QU5HrDM1+ix6rT0umsYvFvatMAnf97NHZlVWDaaLlx7GRfR/7FikANiM2Fg==", - "dev": true - }, - "@docsearch/js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.6.1.tgz", - "integrity": "sha512-erI3RRZurDr1xES5hvYJ3Imp7jtrXj6f1xYIzDzxiS7nNBufYWPbJwrmMqWC5g9y165PmxEmN9pklGCdLi0Iqg==", - "dev": true, - "requires": { - "@docsearch/react": "3.6.1", - "preact": "^10.0.0" - } - }, - "@docsearch/react": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.6.1.tgz", - "integrity": "sha512-qXZkEPvybVhSXj0K7U3bXc233tk5e8PfhoZ6MhPOiik/qUQxYC+Dn9DnoS7CxHQQhHfCvTiN0eY9M12oRghEXw==", - "dev": true, - "requires": { - "@algolia/autocomplete-core": "1.9.3", - "@algolia/autocomplete-preset-algolia": "1.9.3", - "@docsearch/css": "3.6.1", - "algoliasearch": "^4.19.1" - } - }, - "@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.7.0.tgz", - "integrity": "sha512-+HencqxU7CFJnQb7IKtuNBqS6Yx3Tz4kOL8BJXo+JyeiBm5MEX6pO8onXDkjrkCRlfYXS1Axro15ZjVFe9YgsA==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true - }, - "@feathers-plus/batch-loader": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.6.tgz", - "integrity": "sha512-r+n31iZ/B5Rl1mLkC9/S20UI445MdkZvE3VBmjupep2t8OuyTYHPkFEgR25HY6khH+RothK1VL3B5eumk9N2QQ==", - "dev": true - }, - "@feathers-plus/cache": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/cache/-/cache-1.4.0.tgz", - "integrity": "sha512-jkUCfrYX/aBrIZ3hKGnJGUELtSYTGVZFBo2MJvVeonW9BXCHTKwzY6HkmVbzMhzSRMAdeo98nvpsz1d2QbURdw==", - "dev": true, - "requires": { - "lru-cache": "4.1.1" - } - }, - "@feathers-plus/common": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/common/-/common-0.1.0.tgz", - "integrity": "sha512-rK4zNVObmw8UKP7nwTwsCVn0g2Zl92r2rpXMfVdFo8FmYfYY4HECAcGB4Aq38EI6NZnvla51CdDjtY9WxW1OHQ==", - "dev": true, - "requires": { - "short-hash": "1.0.0", - "sort-keys": "2.0.0" - } - }, - "@feathers-plus/graphql": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/graphql/-/graphql-1.10.0.tgz", - "integrity": "sha512-ausYkHTRRxIQbNKVvQ7dHj/bkNsghsjGGKw9PO+w9XOCs6OJouO/cj1nj6RjfUDxUbZtFcc4y5QluYzDulEmEQ==", - "dev": true, - "requires": { - "@feathers-plus/batch-loader": "0.3.0", - "@feathers-plus/cache": "1.3.1", - "@feathers-plus/common": "0.1.0", - "@feathersjs/errors": "3.2.0", - "debug": "3.1.0", - "feathers-hooks-common": "4.5.6", - "graphql": "0.11.7", - "graphql-resolvers-ast": "1.4.0", - "graphql-tools": "2.0.0", - "graphql-type-json": "0.1.4", - "join-monster": "2.0.15", - "join-monster-graphql-tools-adapter": "0.0.2", - "lodash.merge": "4.6.1", - "mongo-sql": "4.0.2", - "traverse": "0.6.6" - }, - "dependencies": { - "@feathers-plus/batch-loader": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.0.tgz", - "integrity": "sha512-buElwyOZKVI34kD7jHt+czIDv1brjXLBPJ+7is+RC98JK+TyqWIUuBJ4E0ZMjPxwwkAJIN6IATyPgvhSXhkaxw==", - "dev": true - }, - "@feathers-plus/cache": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@feathers-plus/cache/-/cache-1.3.1.tgz", - "integrity": "sha512-zFpwVutKiOcPW6Gnm73uit4EwnaawYZEt6pIKP+GkYQz/wVkfNMMwZ28THCNhZvFcR1Cn3WwyUBXcASoApHpvA==", - "dev": true, - "requires": { - "lru-cache": "4.1.1" - } - }, - "@feathersjs/errors": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-3.2.0.tgz", - "integrity": "sha512-4xsE7OyzxGvs2hyG19nf2qb4rV2nWoWbQ6/FnDIYrNHi7M9kOy+deLwNhKnXa4r/hg3xf+AVpC8kBjUQjWYWHA==", - "dev": true, - "requires": { - "debug": "^3.1.0" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "graphql": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-0.11.7.tgz", - "integrity": "sha512-x7uDjyz8Jx+QPbpCFCMQ8lltnQa4p4vSYHx6ADe8rVYRTdsyhCJbvSty5DAsLVmU6cGakl+r8HQYolKHxk/tiw==", - "dev": true, - "requires": { - "iterall": "1.1.3" - } - }, - "graphql-relay": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/graphql-relay/-/graphql-relay-0.5.5.tgz", - "integrity": "sha512-CTsapMI0MZc0antZp+9ZcVcNiVoaXncc2xALCxe2Md25quAUxTjH2135xPRNb6BMOoTiY54HtglfxxUCDTUEbA==", - "dev": true, - "requires": {} - }, - "graphql-tools": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/graphql-tools/-/graphql-tools-2.0.0.tgz", - "integrity": "sha512-5cUflK/kECqge0feZxTG/cF05EHlGMvdK47I+xQtDm67KrW8rlfmLTUWHYcyFTOXT+Yl4Sb/6WTJZwnKX+Ofmg==", - "dev": true, - "requires": { - "@types/graphql": "^0.11.4", - "deprecated-decorator": "^0.1.6", - "uuid": "^3.1.0" - } - }, - "join-monster": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/join-monster/-/join-monster-2.0.15.tgz", - "integrity": "sha512-4ZZd0grGtamGsevMP4iCF+dZ5jyeuvbvEgF5LgPp9Gz1VNUTaL79/ZNfc0Hs/uSNJAVj1vbaUGK/wsnopyYLkA==", - "dev": true, - "requires": { - "@stem/nesthydrationjs": "0.4.0", - "debug": "^3.0.1", - "deprecate": "^1.0.0", - "generatorics": "^1.0.8", - "graphql-relay": "^0.5.0", - "lodash": "^4.13.1" - } - }, - "join-monster-graphql-tools-adapter": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/join-monster-graphql-tools-adapter/-/join-monster-graphql-tools-adapter-0.0.2.tgz", - "integrity": "sha512-Q2DaeL/L6yY7Rh30YvkysB48QdPwbMBElo72gXelDOczymw0DzP1jmrvLuClyxeL5FJs5tt28CHKIKEgYwFAbA==", - "dev": true, - "requires": {} - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "traverse": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha512-kdf4JKs8lbARxWdp7RKdNzoJBhGUcIalSYibuGyHJbmk40pOysQ0+QPvlkCOICOivDWU2IJo2rkrxyTK2AH4fw==", - "dev": true - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "@feathersjs/adapter-commons": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/adapter-commons/-/adapter-commons-5.0.29.tgz", - "integrity": "sha512-9D0He+VqkUoYaSbfav4Rg0DMCVXtGmPNNxRO5QDJqbJ7U4deozCru3+qWMIVAYRXc5jiX0x2iFbSVOoMoFf78Q==", - "dev": true, - "requires": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29" - } - }, - "@feathersjs/authentication": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication/-/authentication-5.0.29.tgz", - "integrity": "sha512-kYC1x1etmZ9Q9EZXd6bbMlk1myaHS5TsW3kOty0m6amG9BDcFdEyh9ij/JgVuL0EJ+7KOHweOypdJ3bIpiinqQ==", - "dev": true, - "requires": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/hooks": "^0.9.0", - "@feathersjs/schema": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29", - "@types/jsonwebtoken": "^9.0.6", - "jsonwebtoken": "^9.0.2", - "lodash": "^4.17.21", - "long-timeout": "^0.1.1", - "uuid": "^10.0.0" - } - }, - "@feathersjs/authentication-client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication-client/-/authentication-client-5.0.29.tgz", - "integrity": "sha512-F0aIJPYLSvDJOnPBqhXOT1UUD/IAxJ2u8xdKGDY+sWGpqCIDMl32PDqImilqC8+G+/BmKJ8Rjhe81oXEbbhOBw==", - "dev": true, - "requires": { - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29" - } - }, - "@feathersjs/authentication-local": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/authentication-local/-/authentication-local-5.0.29.tgz", - "integrity": "sha512-Xkv1oCxn4eZGFWM61Wgo0ghabJIHg0xhkr5zy3glTDZFzqmS8xsoRyQufBnzEd8zMQlw09AK/YbFRNWUc8lNIQ==", - "dev": true, - "requires": { - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "bcryptjs": "^2.4.3", - "lodash": "^4.17.21" - } - }, - "@feathersjs/client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/client/-/client-5.0.29.tgz", - "integrity": "sha512-JzzmuBwHR//NhFBGZsadelpMPz0U3UX/FbOrveUiFrACYdk2MkkUwaIJFlWhFIU8gQJrSDDbGIgnMjEwV9XrXA==", - "dev": true, - "requires": { - "@feathersjs/authentication-client": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/rest-client": "^5.0.29", - "@feathersjs/socketio-client": "^5.0.29" - } - }, - "@feathersjs/commons": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-5.0.29.tgz", - "integrity": "sha512-Gr2c0XxBTQ/+SoH8bAxJO1rUzBrFExQmK7Wdasp9g/xwS0InCNLPHhrrNc2KwTVSx8kbsN+GZRBkzytmxgWM0w==" - }, - "@feathersjs/errors": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-5.0.29.tgz", - "integrity": "sha512-SLpvC36V84XKxucAtDC70GXkqmsvTE5SO4uSZXuTpK68VqeefbmSY+KSid2DY9dM0upZN7orwVBB5YciUMCIIg==" - }, - "@feathersjs/express": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/express/-/express-5.0.29.tgz", - "integrity": "sha512-PvbzAuolHZEL2VBQRyuMVhsa9LVM7HuN6nXyGFv7IqSr7t61i3v5BuWbn4SQ6EO88NVHDnb7DZT7ojDVhU6YFw==", - "dev": true, - "requires": { - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29", - "@types/compression": "^1.7.5", - "@types/cors": "^2.8.17", - "@types/express": "^4.17.21", - "@types/express-serve-static-core": "^4.19.5", - "compression": "^1.7.4", - "cors": "^2.8.5", - "express": "^4.19.2" - } - }, - "@feathersjs/feathers": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/feathers/-/feathers-5.0.29.tgz", - "integrity": "sha512-ERY0W0FfZUysIksdwbBhXZot1F1EuLtlhJA27o9VN9EWIh6IHlT30McyqQqdqTiqVhsOS+KJPLTeGPH60REg+Q==", - "requires": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/hooks": "^0.9.0", - "events": "^3.3.0" - } - }, - "@feathersjs/hooks": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@feathersjs/hooks/-/hooks-0.9.0.tgz", - "integrity": "sha512-kLfWnuhbC25CPkR1/TDcVs0rSiv0JLNxrpUivLwc7FUnkyeciRi5VOmC1SOzL2SOagcozu3+m4VQiONyzgfY7w==" - }, - "@feathersjs/memory": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/memory/-/memory-5.0.29.tgz", - "integrity": "sha512-szi/4WcvwxX8OEi3A/7qUozUzx1ZVIPHX3IEOU9bDnNsDMGWfVlHGOOW3HdSMAOVZWhGR56oMsvXvrAcgdCVRw==", - "dev": true, - "requires": { - "@feathersjs/adapter-commons": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "sift": "^17.1.3" - } - }, - "@feathersjs/rest-client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/rest-client/-/rest-client-5.0.29.tgz", - "integrity": "sha512-fqqZOb4yEZe2Gyrd1/+OyZQkYEwNiwYe4OXd2bVkT60bRBa8zpDUKZrMSTKARvPXzxPKttdrMuOeTmCogHq0KA==", - "dev": true, - "requires": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@types/superagent": "^8.1.7", - "qs": "^6.12.3" - } - }, - "@feathersjs/schema": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/schema/-/schema-5.0.29.tgz", - "integrity": "sha512-Eq1wSYyfczJlD7/4mcD5AtNTq3HdjjS191NCJWEurNIKm6MlIssvZXIjMOjnna2A1Vw/80vPIapat65uebEKPg==", - "dev": true, - "requires": { - "@feathersjs/adapter-commons": "^5.0.29", - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/hooks": "^0.9.0", - "@types/json-schema": "^7.0.15", - "ajv": "^8.16.0", - "ajv-formats": "^3.0.1", - "json-schema-to-ts": "^3.1.0" - }, - "dependencies": { - "ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "@feathersjs/socketio": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/socketio/-/socketio-5.0.29.tgz", - "integrity": "sha512-xtHtWAoEgOEgTYmiEKyqEC10DLbZ51U3mMluQPknsGgH1W2+GgI7WwCAVyM3ZPcVFlUwmVa62/GsIznOs33Hjg==", - "dev": true, - "requires": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29", - "socket.io": "^4.7.5" - } - }, - "@feathersjs/socketio-client": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/socketio-client/-/socketio-client-5.0.29.tgz", - "integrity": "sha512-6jw4YCTZ35dwBT1DEvI9CkB99lND02Wk8WfU6xf2Ss1ZBU1oNl1zqVZTECHiuvYp4akPRMS9HIZFm1DK8qLEOQ==", - "dev": true, - "requires": { - "@feathersjs/feathers": "^5.0.29", - "@feathersjs/transport-commons": "^5.0.29" - } - }, - "@feathersjs/transport-commons": { - "version": "5.0.29", - "resolved": "https://registry.npmjs.org/@feathersjs/transport-commons/-/transport-commons-5.0.29.tgz", - "integrity": "sha512-Xy7J9h/t9vLqjPnyn3RnNtcS9wBDp/VfdVYulC0hnpEBFKwDtyjx055rUgrNn8r1B4w0y8CyX02MNSupABgOiQ==", - "dev": true, - "requires": { - "@feathersjs/commons": "^5.0.29", - "@feathersjs/errors": "^5.0.29", - "@feathersjs/feathers": "^5.0.29", - "encodeurl": "^2.0.0", - "lodash": "^4.17.21" - } - }, - "@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", - "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", - "dev": true - }, - "@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "requires": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.27.8" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "dev": true - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", - "dev": true, - "optional": true, - "requires": { - "sparse-bitfield": "^3.0.3" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "dev": true, - "requires": { - "semver": "^7.3.5" - } - }, - "@npmcli/git": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", - "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", - "dev": true, - "requires": { - "@npmcli/promise-spawn": "^6.0.0", - "lru-cache": "^7.4.4", - "npm-pick-manifest": "^8.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^3.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "@npmcli/installed-package-contents": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", - "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", - "dev": true, - "requires": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - } - }, - "@npmcli/node-gyp": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", - "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", - "dev": true - }, - "@npmcli/promise-spawn": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", - "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", - "dev": true, - "requires": { - "which": "^3.0.0" - }, - "dependencies": { - "which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "@npmcli/run-script": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", - "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", - "dev": true, - "requires": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^6.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^3.0.0" - }, - "dependencies": { - "which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", - "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true - }, - "@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true - }, - "@pnpm/network.ca-file": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.1.tgz", - "integrity": "sha512-gkINruT2KUhZLTaiHxwCOh1O4NVnFT0wLjWFBHmTz9vpKag/C/noIMJXBxFe4F0mYpUVX2puLwAieLYFg2NvoA==", - "dev": true, - "requires": { - "graceful-fs": "4.2.10" - } - }, - "@pnpm/npm-conf": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-1.0.5.tgz", - "integrity": "sha512-hD8ml183638O3R6/Txrh0L8VzGOrFXgRtRDG4qQC4tONdZ5Z1M+tlUUDUvrjYdmK6G+JTBTeaCLMna11cXzi8A==", - "dev": true, - "requires": { - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - } - }, - "@rollup/rollup-android-arm-eabi": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.1.tgz", - "integrity": "sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-android-arm64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.1.tgz", - "integrity": "sha512-F/tkdw0WSs4ojqz5Ovrw5r9odqzFjb5LIgHdHZG65dFI1lWTWRVy32KDJLKRISHgJvqUeUhdIvy43fX41znyDg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-darwin-arm64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.1.tgz", - "integrity": "sha512-vk+ma8iC1ebje/ahpxpnrfVQJibTMyHdWpOGZ3JpQ7Mgn/3QNHmPq7YwjZbIE7km73dH5M1e6MRRsnEBW7v5CQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-darwin-x64": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.1.tgz", - "integrity": "sha512-IgpzXKauRe1Tafcej9STjSSuG0Ghu/xGYH+qG6JwsAUxXrnkvNHcq/NL6nz1+jzvWAnQkuAJ4uIwGB48K9OCGA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.1.tgz", - "integrity": "sha512-P9bSiAUnSSM7EmyRK+e5wgpqai86QOSv8BwvkGjLwYuOpaeomiZWifEos517CwbG+aZl1T4clSE1YqqH2JRs+g==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.1.tgz", - "integrity": "sha512-5RnjpACoxtS+aWOI1dURKno11d7krfpGDEn19jI8BuWmSBbUC4ytIADfROM1FZrFhQPSoP+KEa3NlEScznBTyQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.1.tgz", - "integrity": "sha512-8mwmGD668m8WaGbthrEYZ9CBmPug2QPGWxhJxh/vCgBjro5o96gL04WLlg5BA233OCWLqERy4YUzX3bJGXaJgQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm64-musl": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.1.tgz", - "integrity": "sha512-dJX9u4r4bqInMGOAQoGYdwDP8lQiisWb9et+T84l2WXk41yEej8v2iGKodmdKimT8cTAYt0jFb+UEBxnPkbXEQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.1.tgz", - "integrity": "sha512-V72cXdTl4EI0x6FNmho4D502sy7ed+LuVW6Ym8aI6DRQ9hQZdp5sj0a2usYOlqvFBNKQnLQGwmYnujo2HvjCxQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.1.tgz", - "integrity": "sha512-f+pJih7sxoKmbjghrM2RkWo2WHUW8UbfxIQiWo5yeCaCM0TveMEuAzKJte4QskBp1TIinpnRcxkquY+4WuY/tg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.1.tgz", - "integrity": "sha512-qb1hMMT3Fr/Qz1OKovCuUM11MUNLUuHeBC2DPPAWUYYUAOFWaxInaTwTQmc7Fl5La7DShTEpmYwgdt2hG+4TEg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-x64-gnu": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.1.tgz", - "integrity": "sha512-7O5u/p6oKUFYjRbZkL2FLbwsyoJAjyeXHCU3O4ndvzg2OFO2GinFPSJFGbiwFDaCFc+k7gs9CF243PwdPQFh5g==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-x64-musl": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.1.tgz", - "integrity": "sha512-pDLkYITdYrH/9Cv/Vlj8HppDuLMDUBmgsM0+N+xLtFd18aXgM9Nyqupb/Uw+HeidhfYg2lD6CXvz6CjoVOaKjQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.1.tgz", - "integrity": "sha512-W2ZNI323O/8pJdBGil1oCauuCzmVd9lDmWBBqxYZcOqWD6aWqJtVBQ1dFrF4dYpZPks6F+xCZHfzG5hYlSHZ6g==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.1.tgz", - "integrity": "sha512-ELfEX1/+eGZYMaCIbK4jqLxO1gyTSOIlZr6pbC4SRYFaSIDVKOnZNMdoZ+ON0mrFDp4+H5MhwNC1H/AhE3zQLg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-x64-msvc": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.1.tgz", - "integrity": "sha512-yjk2MAkQmoaPYCSu35RLJ62+dz358nE83VfTePJRp8CG7aMg25mEJYpXFiD+NcevhX8LxD5OP5tktPXnXN7GDw==", - "dev": true, - "optional": true - }, - "@shikijs/core": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.10.3.tgz", - "integrity": "sha512-D45PMaBaeDHxww+EkcDQtDAtzv00Gcsp72ukBtaLSmqRvh0WgGMq3Al0rl1QQBZfuneO75NXMIzEZGFitThWbg==", - "dev": true, - "requires": { - "@types/hast": "^3.0.4" - } - }, - "@shikijs/transformers": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-1.10.3.tgz", - "integrity": "sha512-MNjsyye2WHVdxfZUSr5frS97sLGe6G1T+1P41QjyBFJehZphMcr4aBlRLmq6OSPBslYe9byQPVvt/LJCOfxw8Q==", - "dev": true, - "requires": { - "shiki": "1.10.3" - } - }, - "@sigstore/bundle": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-1.1.0.tgz", - "integrity": "sha512-PFutXEy0SmQxYI4texPw3dd2KewuNqv7OuK1ZFtY2fM754yhvG2KdgwIhRnoEE2uHdtdGNQ8s0lb94dW9sELog==", - "dev": true, - "requires": { - "@sigstore/protobuf-specs": "^0.2.0" - } - }, - "@sigstore/protobuf-specs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.2.1.tgz", - "integrity": "sha512-XTWVxnWJu+c1oCshMLwnKvz8ZQJJDVOlciMfgpJBQbThVjKTCG8dwyhgLngBD2KN0ap9F/gOV8rFDEx8uh7R2A==", - "dev": true - }, - "@sigstore/sign": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-1.0.0.tgz", - "integrity": "sha512-INxFVNQteLtcfGmcoldzV6Je0sbbfh9I16DM4yJPw3j5+TFP8X6uIiA18mvpEa9yyeycAKgPmOA3X9hVdVTPUA==", - "dev": true, - "requires": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "make-fetch-happen": "^11.0.1" - } - }, - "@sigstore/tuf": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.3.tgz", - "integrity": "sha512-2bRovzs0nJZFlCN3rXirE4gwxCn97JNjMmwpecqlbgV9WcxX7WRuIrgzx/X7Ib7MYRbyUTpBYE0s2x6AmZXnlg==", - "dev": true, - "requires": { - "@sigstore/protobuf-specs": "^0.2.0", - "tuf-js": "^1.1.7" - } - }, - "@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "@sindresorhus/is": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.3.0.tgz", - "integrity": "sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==", - "dev": true - }, - "@socket.io/component-emitter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", - "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", - "dev": true - }, - "@stem/nesthydrationjs": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@stem/nesthydrationjs/-/nesthydrationjs-0.4.0.tgz", - "integrity": "sha512-hnoLv6W7CmhWXCEp6MBiZv4CdqI48aYmxM+Lo5T3qogP+x+MBR0DOyt7XdppI/X8McqHisCbSNvAOC4fgPhUiw==", - "dev": true, - "requires": { - "lodash": "4.13.1" - }, - "dependencies": { - "lodash": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.13.1.tgz", - "integrity": "sha512-j/GRONYpkXt1aB1bQHzkq0Th7zhv/syoDVrzCDA3FDMntIin0b7TjXi62q9juDC+QfhRs9COr0LFW38vQSH9Tg==", - "dev": true - } - } - }, - "@szmarczak/http-timer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", - "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.1" - } - }, - "@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true - }, - "@tufjs/canonical-json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", - "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", - "dev": true - }, - "@tufjs/models": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", - "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", - "dev": true, - "requires": { - "@tufjs/canonical-json": "1.0.0", - "minimatch": "^9.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "@types/body-parser": { - "version": "1.19.5", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", - "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "@types/cookiejar": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", - "integrity": "sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q==", - "dev": true - }, - "@types/cors": { - "version": "2.8.17", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", - "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/debug": { - "version": "4.1.12", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", - "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", - "dev": true, - "requires": { - "@types/ms": "*" - } - }, - "@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "@types/express": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", - "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.19.5", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", - "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "@types/graphql": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@types/graphql/-/graphql-0.11.8.tgz", - "integrity": "sha512-xGWx4kx9JKlqxDrZA12gw5qi2lvxPNLxnQQcoTXVX83MuGcXcpb7TADatGyGW51GaaXQOQTbjw3x4HuL3ULBaA==", - "dev": true, - "optional": true - }, - "@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, - "requires": { - "@types/unist": "*" - } - }, - "@types/http-errors": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", - "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "@types/jsonwebtoken": { - "version": "9.0.6", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", - "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true - }, - "@types/lodash": { - "version": "4.17.7", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.7.tgz", - "integrity": "sha512-8wTvZawATi/lsmNu10/j2hk1KEP0IvjubqPE3cu1Xz7xfXXt5oCq3SNUz4fMIP4XGF9Ky+Ue2tBA3hcS7LSBlA==", - "dev": true - }, - "@types/markdown-it": { - "version": "14.1.1", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", - "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", - "dev": true, - "requires": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" - } - }, - "@types/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true - }, - "@types/methods": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@types/methods/-/methods-1.1.4.tgz", - "integrity": "sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ==", - "dev": true - }, - "@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true - }, - "@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==", - "dev": true - }, - "@types/node": { - "version": "20.14.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.11.tgz", - "integrity": "sha512-kprQpL8MMeszbz6ojB5/tU8PLN4kesnN8Gjzw349rDlNgsSzg90lAVj3llK99Dh7JON+t9AuscPPFW6mPbTnSA==", - "dev": true, - "requires": { - "undici-types": "~5.26.4" - } - }, - "@types/qs": { - "version": "6.9.11", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz", - "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==", - "dev": true - }, - "@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true - }, - "@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, - "@types/semver-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/semver-utils/-/semver-utils-1.1.3.tgz", - "integrity": "sha512-T+YwkslhsM+CeuhYUxyAjWm7mJ5am/K10UX40RuA6k6Lc7eGtq8iY2xOzy7Vq0GOqhl/xZl5l2FwURZMTPTUww==", - "dev": true - }, - "@types/send": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", - "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", - "dev": true, - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "@types/serve-static": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz", - "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==", - "dev": true, - "requires": { - "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" - } - }, - "@types/superagent": { - "version": "8.1.7", - "resolved": "https://registry.npmjs.org/@types/superagent/-/superagent-8.1.7.tgz", - "integrity": "sha512-NmIsd0Yj4DDhftfWvvAku482PZum4DBW7U51OvS8gvOkDDY0WT1jsVyDV3hK+vplrsYw8oDwi9QxOM7U68iwww==", - "dev": true, - "requires": { - "@types/cookiejar": "^2.1.5", - "@types/methods": "^1.1.4", - "@types/node": "*" - } - }, - "@types/unist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", - "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==", - "dev": true - }, - "@types/web-bluetooth": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", - "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", - "dev": true - }, - "@types/webidl-conversions": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", - "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", - "dev": true - }, - "@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", - "dev": true, - "requires": { - "@types/node": "*", - "@types/webidl-conversions": "*" - } - }, - "@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - } - }, - "@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - } - }, - "@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - } - }, - "@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - } - }, - "@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, - "requires": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - } - }, - "@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "@vitejs/plugin-vue": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.0.5.tgz", - "integrity": "sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==", - "dev": true, - "requires": {} - }, - "@vitest/coverage-v8": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", - "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.1", - "@bcoe/v8-coverage": "^0.2.3", - "debug": "^4.3.4", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.4", - "istanbul-reports": "^3.1.6", - "magic-string": "^0.30.5", - "magicast": "^0.3.3", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "test-exclude": "^6.0.0" - } - }, - "@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", - "dev": true, - "requires": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "chai": "^4.3.10" - } - }, - "@vitest/runner": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", - "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", - "dev": true, - "requires": { - "@vitest/utils": "1.6.0", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" - }, - "dependencies": { - "p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", - "dev": true, - "requires": { - "yocto-queue": "^1.0.0" - } - }, - "yocto-queue": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.1.1.tgz", - "integrity": "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==", - "dev": true - } - } - }, - "@vitest/snapshot": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", - "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", - "dev": true, - "requires": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" - } - }, - "@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", - "dev": true, - "requires": { - "tinyspy": "^2.2.0" - } - }, - "@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", - "dev": true, - "requires": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - } - }, - "@vue/compiler-core": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.32.tgz", - "integrity": "sha512-8tCVWkkLe/QCWIsrIvExUGnhYCAOroUs5dzhSoKL5w4MJS8uIYiou+pOPSVIOALOQ80B0jBs+Ri+kd5+MBnCDw==", - "dev": true, - "requires": { - "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.32", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" - }, - "dependencies": { - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - } - } - }, - "@vue/compiler-dom": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.32.tgz", - "integrity": "sha512-PbSgt9KuYo4fyb90dynuPc0XFTfFPs3sCTbPLOLlo+PrUESW1gn/NjSsUvhR+mI2AmmEzexwYMxbHDldxSOr2A==", - "dev": true, - "requires": { - "@vue/compiler-core": "3.4.32", - "@vue/shared": "3.4.32" - } - }, - "@vue/compiler-sfc": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.32.tgz", - "integrity": "sha512-STy9im/WHfaguJnfKjjVpMHukxHUrOKjm2vVCxiojQJyo3Sb6Os8SMXBr/MI+ekpstEGkDONfqAQoSbZhspLYw==", - "dev": true, - "requires": { - "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.32", - "@vue/compiler-dom": "3.4.32", - "@vue/compiler-ssr": "3.4.32", - "@vue/shared": "3.4.32", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.10", - "postcss": "^8.4.39", - "source-map-js": "^1.2.0" - }, - "dependencies": { - "estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - } - } - }, - "@vue/compiler-ssr": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.32.tgz", - "integrity": "sha512-nyu/txTecF6DrxLrpLcI34xutrvZPtHPBj9yRoPxstIquxeeyywXpYZrQMsIeDfBhlw1abJb9CbbyZvDw2kjdg==", - "dev": true, - "requires": { - "@vue/compiler-dom": "3.4.32", - "@vue/shared": "3.4.32" - } - }, - "@vue/devtools-api": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.3.6.tgz", - "integrity": "sha512-z6cKyxdXrIGgA++eyGBfquj6dCplRdgjt+I18fJx8hjWTXDTIyeQvryyEBMchnfZVyvUTjK3QjGjDpLCnJxPjw==", - "dev": true, - "requires": { - "@vue/devtools-kit": "^7.3.6" - } - }, - "@vue/devtools-kit": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.3.6.tgz", - "integrity": "sha512-5Ym9V3fkJenEoptqKoo+cgY5RTVwrSssFdzRsuyIgaeiskCT+rRJeQdwoo81tyrQ1mfS7Er1rYZlSzr3Y3L/ew==", - "dev": true, - "requires": { - "@vue/devtools-shared": "^7.3.6", - "birpc": "^0.2.17", - "hookable": "^5.5.3", - "mitt": "^3.0.1", - "perfect-debounce": "^1.0.0", - "speakingurl": "^14.0.1", - "superjson": "^2.2.1" - } - }, - "@vue/devtools-shared": { - "version": "7.3.6", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.3.6.tgz", - "integrity": "sha512-R/FOmdJV+hhuwcNoxp6e87RRkEeDMVhWH+nOsnHUrwjjsyeXJ2W1475Ozmw+cbZhejWQzftkHVKO28Fuo1yqCw==", - "dev": true, - "requires": { - "rfdc": "^1.4.1" - } - }, - "@vue/reactivity": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.32.tgz", - "integrity": "sha512-1P7QvghAzhSIWmiNmh4MNkLVjr2QTNDcFv2sKmytEWhR6t7BZzNicgm5ENER4uU++wbWxgRh/pSEYgdI3MDcvg==", - "dev": true, - "requires": { - "@vue/shared": "3.4.32" - } - }, - "@vue/runtime-core": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.32.tgz", - "integrity": "sha512-FxT2dTHUs1Hki8Ui/B1Hu339mx4H5kRJooqrNM32tGUHBPStJxwMzLIRbeGO/B1NMplU4Pg9fwOqrJtrOzkdfA==", - "dev": true, - "requires": { - "@vue/reactivity": "3.4.32", - "@vue/shared": "3.4.32" - } - }, - "@vue/runtime-dom": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.32.tgz", - "integrity": "sha512-Xz9G+ZViRyPFQtRBCPFkhMzKn454ihCPMKUiacNaUhuTIXvyfkAq8l89IZ/kegFVyw/7KkJGRGqYdEZrf27Xsg==", - "dev": true, - "requires": { - "@vue/reactivity": "3.4.32", - "@vue/runtime-core": "3.4.32", - "@vue/shared": "3.4.32", - "csstype": "^3.1.3" - } - }, - "@vue/server-renderer": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.32.tgz", - "integrity": "sha512-3c4rd0522Ao8hKjzgmUAbcjv2mBnvnw0Ld2f8HOMCuWJZjYie/p8cpIoYJbeP0VV2JYmrJJMwGQDO5RH4iQ30A==", - "dev": true, - "requires": { - "@vue/compiler-ssr": "3.4.32", - "@vue/shared": "3.4.32" - } - }, - "@vue/shared": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.32.tgz", - "integrity": "sha512-ep4mF1IVnX/pYaNwxwOpJHyBtOMKWoKZMbnUyd+z0udqIxLUh7YCCd/JfDna8aUrmnG9SFORyIq2HzEATRrQsg==", - "dev": true - }, - "@vueuse/core": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-10.11.0.tgz", - "integrity": "sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==", - "dev": true, - "requires": { - "@types/web-bluetooth": "^0.0.20", - "@vueuse/metadata": "10.11.0", - "@vueuse/shared": "10.11.0", - "vue-demi": ">=0.14.8" - }, - "dependencies": { - "vue-demi": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", - "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", - "dev": true, - "requires": {} - } - } - }, - "@vueuse/integrations": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-10.11.0.tgz", - "integrity": "sha512-Pp6MtWEIr+NDOccWd8j59Kpjy5YDXogXI61Kb1JxvSfVBO8NzFQkmrKmSZz47i+ZqHnIzxaT38L358yDHTncZg==", - "dev": true, - "requires": { - "@vueuse/core": "10.11.0", - "@vueuse/shared": "10.11.0", - "vue-demi": ">=0.14.8" - }, - "dependencies": { - "vue-demi": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", - "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", - "dev": true, - "requires": {} - } - } - }, - "@vueuse/metadata": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-10.11.0.tgz", - "integrity": "sha512-kQX7l6l8dVWNqlqyN3ePW3KmjCQO3ZMgXuBMddIu83CmucrsBfXlH+JoviYyRBws/yLTQO8g3Pbw+bdIoVm4oQ==", - "dev": true - }, - "@vueuse/shared": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-10.11.0.tgz", - "integrity": "sha512-fyNoIXEq3PfX1L3NkNhtVQUSRtqYwJtJg+Bp9rIzculIZWHTkKSysujrOk2J+NrRulLTQH9+3gGSfYLWSEWU1A==", - "dev": true, - "requires": { - "vue-demi": ">=0.14.8" - }, - "dependencies": { - "vue-demi": { - "version": "0.14.8", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.8.tgz", - "integrity": "sha512-Uuqnk9YE9SsWeReYqK2alDI5YzciATE0r2SkA6iMAtuXvNTMNACJLJEXNXaEy94ECuBe4Sk6RzRU80kjdbIo1Q==", - "dev": true, - "requires": {} - } - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dev": true, - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dev": true, - "requires": { - "humanize-ms": "^1.2.1" - } - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "requires": { - "ajv": "^8.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } - }, - "algoliasearch": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-4.24.0.tgz", - "integrity": "sha512-bf0QV/9jVejssFBmz2HQLxUadxk574t4iwjCKp5E7NBzwKkrDEhKPISIIjAU/p6K5qDx3qoeh4+26zWN1jmw3g==", - "dev": true, - "requires": { - "@algolia/cache-browser-local-storage": "4.24.0", - "@algolia/cache-common": "4.24.0", - "@algolia/cache-in-memory": "4.24.0", - "@algolia/client-account": "4.24.0", - "@algolia/client-analytics": "4.24.0", - "@algolia/client-common": "4.24.0", - "@algolia/client-personalization": "4.24.0", - "@algolia/client-search": "4.24.0", - "@algolia/logger-common": "4.24.0", - "@algolia/logger-console": "4.24.0", - "@algolia/recommend": "4.24.0", - "@algolia/requester-browser-xhr": "4.24.0", - "@algolia/requester-common": "4.24.0", - "@algolia/requester-node-http": "4.24.0", - "@algolia/transporter": "4.24.0" - } - }, - "ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "dev": true, - "requires": { - "string-width": "^4.1.0" - } - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - } - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - } - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "dev": true - }, - "array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - } - }, - "array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, - "arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - } - }, - "assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64id": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", - "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "dev": true - }, - "bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", - "dev": true - }, - "binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true - }, - "birpc": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-0.2.17.tgz", - "integrity": "sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==", - "dev": true - }, - "body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - } - } - }, - "boxen": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.0.0.tgz", - "integrity": "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==", - "dev": true, - "requires": { - "ansi-align": "^3.0.1", - "camelcase": "^7.0.0", - "chalk": "^5.0.1", - "cli-boxes": "^3.0.0", - "string-width": "^5.1.2", - "type-fest": "^2.13.0", - "widest-line": "^4.0.1", - "wrap-ansi": "^8.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "bson": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", - "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", - "dev": true - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "requires": { - "semver": "^7.0.0" - } - }, - "bundle-require": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.0.0.tgz", - "integrity": "sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==", - "dev": true, - "requires": { - "load-tsconfig": "^0.2.3" - } - }, - "bytes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "dev": true - }, - "cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true - }, - "cacache": { - "version": "17.1.4", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.4.tgz", - "integrity": "sha512-/aJwG2l3ZMJ1xNAnqbMpA40of9dj/pIH3QfiuQSqjfPJF747VR0J/bHn+/KdNnHKc6XQcWt/AfRSBft82W1d2A==", - "dev": true, - "requires": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^7.7.1", - "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "10.3.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", - "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - } - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", - "dev": true - } - } - }, - "cacheable-lookup": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz", - "integrity": "sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==", - "dev": true - }, - "cacheable-request": { - "version": "10.1.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.1.2.tgz", - "integrity": "sha512-N7F4os5ZI+8mWHSbeJmxn+qimf5uK3WU53FD1b298XLGtOLPpSA/1xAchfP4NJlDwqgaviZ0SQfxTQD0K6lr9w==", - "dev": true, - "requires": { - "get-stream": "^6.0.1", - "http-cache-semantics": "^4.1.0", - "keyv": "^4.5.0", - "mimic-response": "^4.0.0", - "normalize-url": "^7.1.0", - "responselike": "^3.0.0" - } - }, - "call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.0.tgz", - "integrity": "sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==", - "dev": true - }, - "chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", - "dev": true, - "requires": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - } - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "requires": { - "get-func-name": "^2.0.2" - } - }, - "chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.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" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true - }, - "ci-info": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.4.0.tgz", - "integrity": "sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==", - "dev": true - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "dev": true - }, - "cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "requires": { - "@colors/colors": "1.5.0", - "string-width": "^4.2.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "commander": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", - "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", - "dev": true - }, - "compressible": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", - "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "dev": true, - "requires": { - "mime-db": ">= 1.43.0 < 2" - } - }, - "compression": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", - "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "dev": true, - "requires": { - "accepts": "~1.3.5", - "bytes": "3.0.0", - "compressible": "~2.0.16", - "debug": "2.6.9", - "on-headers": "~1.0.2", - "safe-buffer": "5.1.2", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", - "dev": true - }, - "config-chain": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", - "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", - "dev": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - } - } - }, - "configstore": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", - "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", - "dev": true, - "requires": { - "dot-prop": "^6.0.1", - "graceful-fs": "^4.2.6", - "unique-string": "^3.0.0", - "write-file-atomic": "^3.0.3", - "xdg-basedir": "^5.0.1" - } - }, - "consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - } - }, - "content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true - }, - "cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "dev": true - }, - "copy-anything": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz", - "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==", - "dev": true, - "requires": { - "is-what": "^4.1.8" - } - }, - "cors": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", - "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "dev": true, - "requires": { - "object-assign": "^4", - "vary": "^1" - } - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "crypto-random-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", - "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", - "dev": true, - "requires": { - "type-fest": "^1.0.1" - }, - "dependencies": { - "type-fest": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", - "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", - "dev": true - } - } - }, - "csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true - }, - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "requires": { - "type-detect": "^4.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "requires": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - } - }, - "define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "requires": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - } - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, - "deprecate": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/deprecate/-/deprecate-1.1.1.tgz", - "integrity": "sha512-ZGDXefq1xknT292LnorMY5s8UVU08/WKdzDZCUT6t9JzsiMSP4uzUhgpqugffNVcT5WC6wMBiSQ+LFjlv3v7iQ==", - "dev": true - }, - "deprecated-decorator": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz", - "integrity": "sha512-MHidOOnCHGlZDKsI21+mbIIhf4Fff+hhCTB7gtVg4uoIqjcrTZc5v6M+GS2zVI0sV7PqK415rb8XaOSQsQkHOw==", - "dev": true - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "dev": true - }, - "diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", - "dev": true, - "requires": { - "is-obj": "^2.0.0" - } - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true - }, - "encoding": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", - "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, - "optional": true, - "requires": { - "iconv-lite": "^0.6.2" - }, - "dependencies": { - "iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - } - } - }, - "engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", - "dev": true, - "requires": { - "@types/cookie": "^0.4.1", - "@types/cors": "^2.8.12", - "@types/node": ">=10.0.0", - "accepts": "~1.3.4", - "base64id": "2.0.0", - "cookie": "~0.4.1", - "cors": "~2.8.5", - "debug": "~4.3.1", - "engine.io-parser": "~5.2.1", - "ws": "~8.17.1" - }, - "dependencies": { - "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "dev": true - } - } - }, - "engine.io-parser": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", - "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", - "dev": true - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - }, - "env-paths": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true - }, - "err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true - }, - "es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "requires": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - } - }, - "es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.4" - } - }, - "es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true - }, - "es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - } - }, - "es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "requires": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "escape-goat": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", - "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", - "dev": true - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "dependencies": { - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "requires": {} - }, - "eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "requires": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "requires": { - "debug": "^3.2.7" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", - "dev": true, - "requires": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "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.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.15.0" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - } - }, - "eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true - }, - "espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "requires": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - } - }, - "esquery": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.2.tgz", - "integrity": "sha512-JVSoLdTlTDkmjFmab7H/9SL9qGSyjElT3myyKp7krqjVFQCDLmj1QFaCLRFBszBKI0XVZaiiXvuPIX3ZwHe1Ng==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "requires": { - "@types/estree": "^1.0.0" - } - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "exponential-backoff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "dev": true - }, - "express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "dev": true, - "requires": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - } - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fast-memoize": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", - "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", - "dev": true - }, - "fast-uri": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.1.tgz", - "integrity": "sha512-MWipKbbYiYI0UC7cl8m/i/IWTqfC8YXsqjzybjddLsFjStroQzsHXkc73JutMvBiXmOvapk+axIl79ig5t55Bw==", - "dev": true - }, - "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "feathers-hooks-common": { - "version": "4.5.6", - "resolved": "https://registry.npmjs.org/feathers-hooks-common/-/feathers-hooks-common-4.5.6.tgz", - "integrity": "sha512-z0KZP/igmHvEJX46x0f6UC/pSYFXUt/2OfgMwumElGqxwFYU4JrAnK8FbGwCo8MYowMDfpMk72ju+axbq9MV1Q==", - "dev": true, - "requires": { - "@feathers-plus/batch-loader": "0.3.0", - "@feathersjs/commons": "^1.2.0", - "@feathersjs/errors": "^3.0.0", - "ajv": "^5.2.0", - "debug": "^3.0.0", - "process": "0.11.10", - "traverse": "^0.6.6" - }, - "dependencies": { - "@feathers-plus/batch-loader": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@feathers-plus/batch-loader/-/batch-loader-0.3.0.tgz", - "integrity": "sha512-buElwyOZKVI34kD7jHt+czIDv1brjXLBPJ+7is+RC98JK+TyqWIUuBJ4E0ZMjPxwwkAJIN6IATyPgvhSXhkaxw==", - "dev": true - }, - "@feathersjs/commons": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/@feathersjs/commons/-/commons-1.4.4.tgz", - "integrity": "sha512-ZPpzyZA3CPfoa9AuFv3BJUI/ubzaaXixp8T/pqeMFPT6DOaU/6oF7lz1RxwimzfJNna4gy/HByt0EoLSI3BKWg==", - "dev": true - }, - "@feathersjs/errors": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/@feathersjs/errors/-/errors-3.3.6.tgz", - "integrity": "sha512-VCohY/AQU13xYyZGl6rfdUgE+2bjaI76a4aEb6reIphHKgb4mnjYlg2PzS1/hcU1qUNi515kY9yQa5HsE7J1dQ==", - "dev": true, - "requires": { - "debug": "^4.0.0" - }, - "dependencies": { - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha512-Ajr4IcMXq/2QmMkEmSvxqfLN5zGmJ92gHXAeOXq1OekoH2rfDNsgdDoL2f7QaRCy7G/E6TpxBVdRuNraMztGHw==", - "dev": true, - "requires": { - "co": "^4.6.0", - "fast-deep-equal": "^1.0.0", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.3.0" - } - }, - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha512-fueX787WZKCV0Is4/T2cyAdM4+x1S3MXXOAhavE1ys/W42SHAPacLTQhucja22QBYrfGw50M2sRiXPtTGv9Ymw==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha512-4JD/Ivzg7PoW8NzdrBSr3UFwC9mHgvI7Z6z3QGBsSHgKaRTUDmyZAAKJo2UbG1kUVfS9WS8bi36N49U1xw43DA==", - "dev": true - } - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true - }, - "focus-trap": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.4.tgz", - "integrity": "sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==", - "dev": true, - "requires": { - "tabbable": "^6.2.0" - } - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "dependencies": { - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true - } - } - }, - "form-data-encoder": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.2.tgz", - "integrity": "sha512-FCaIOVTRA9E0siY6FeXid7D5yrCqpsErplUkE2a1BEiKj1BE9z6FbKB4ntDTwC4NVLie9p+4E9nX4mWwEOT05A==", - "dev": true - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true - }, - "fp-and-or": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/fp-and-or/-/fp-and-or-0.1.4.tgz", - "integrity": "sha512-+yRYRhpnFPWXSly/6V4Lw9IfOV26uu30kynGJ03PW+MnjOEQe45RZ141QcS0aJehYBYA50GfCDnsRbFJdhssRw==", - "dev": true - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "dev": true - }, - "fs-minipass": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", - "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, - "requires": { - "minipass": "^7.0.3" - }, - "dependencies": { - "minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", - "dev": true - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "optional": true - }, - "function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true - }, - "function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - } - }, - "functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true - }, - "gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, - "requires": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - } - }, - "generatorics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz", - "integrity": "sha512-LuYDCS1DbKQsvChP1xHmAzHnGdd0z0K1XMebmbNbFzGZI62KODnV2CXA7zOqebiDzlK2sxXrPGfwlDzSm9aP4g==", - "dev": true - }, - "get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true - }, - "get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "requires": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - } - }, - "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "requires": { - "is-glob": "^4.0.3" - } - }, - "global-dirs": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", - "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", - "dev": true, - "requires": { - "ini": "2.0.0" - } - }, - "globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - } - }, - "gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "got": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/got/-/got-12.5.0.tgz", - "integrity": "sha512-/Bneo/L6bLN1wDyJCeRZ3CLoixvwb9v3rE3IHulFSfTHwP85xSr4QatA8K0c6GlL5+mc4IZ57BzluNZJiXvHIg==", - "dev": true, - "requires": { - "@sindresorhus/is": "^5.2.0", - "@szmarczak/http-timer": "^5.0.1", - "cacheable-lookup": "^6.0.4", - "cacheable-request": "^10.1.2", - "decompress-response": "^6.0.0", - "form-data-encoder": "^2.1.2", - "get-stream": "^6.0.1", - "http2-wrapper": "^2.1.10", - "lowercase-keys": "^3.0.0", - "p-cancelable": "^3.0.0", - "responselike": "^3.0.0" - } - }, - "graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "graphql": { - "version": "16.9.0", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", - "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==" - }, - "graphql-resolvers-ast": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphql-resolvers-ast/-/graphql-resolvers-ast-1.4.0.tgz", - "integrity": "sha512-L4BeMFgPV7rwyISIvJ+QOsnMfc5+STMsaF097cLzJ9t/kizekDB5dMWNC+jq2pUWq0WoqYZypWYKwFL5vH4dUQ==", - "dev": true - }, - "graphql-type-json": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.1.4.tgz", - "integrity": "sha512-B1zeWRF50alRvW94s/hpkGbVqvRLTtJD0yEyMs6KAvDSlNyBzJCu/d51fLZalqrVntuJAVgXYh13GbUEqe9MrQ==", - "dev": true, - "requires": {} - }, - "has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "requires": { - "es-define-property": "^1.0.0" - } - }, - "has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, - "has-yarn": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", - "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", - "dev": true - }, - "hash-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/hash-string/-/hash-string-1.0.0.tgz", - "integrity": "sha512-dtNNyxXobzHavayZwOwRWhBTqS9GX4jDjIMsGc0fDyaN2A+4zMn5Ua9ODDCggN6w3Spma6mAHL3ImmW3BkWDmQ==", - "dev": true - }, - "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, - "requires": { - "function-bind": "^1.1.2" - } - }, - "hookable": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", - "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", - "dev": true - }, - "hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, - "requires": { - "lru-cache": "^7.5.1" - }, - "dependencies": { - "lru-cache": { - "version": "7.14.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz", - "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==", - "dev": true - } - } - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - } - }, - "http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "requires": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - } - }, - "http2-wrapper": { - "version": "2.1.11", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.1.11.tgz", - "integrity": "sha512-aNAk5JzLturWEUiuhAN73Jcbq96R7rTitAoXV54FYMatvihnpD2+6PUgU4ce3D/m5VDbw+F5CsyKSF176ptitQ==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.2.0" - } - }, - "https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", - "dev": true, - "requires": { - "minimatch": "^9.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true - }, - "internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "requires": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true - }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true - }, - "is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true - }, - "is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "requires": { - "ci-info": "^3.2.0" - } - }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "requires": { - "hasown": "^2.0.0" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "requires": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - } - }, - "is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-npm": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", - "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", - "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "requires": { - "which-typed-array": "^1.1.11" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-what": { - "version": "4.1.16", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", - "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==", - "dev": true - }, - "is-yarn-global": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.0.tgz", - "integrity": "sha512-HneQBCrXGBy15QnaDfcn6OLoU8AQPAa0Qn0IeJR/QCo4E8dNZaGGwxpCwWyEBQC5QvFonP8d6t60iGpAHVAfNA==", - "dev": true - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true - }, - "istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - } - }, - "istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "iterall": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/iterall/-/iterall-1.1.3.tgz", - "integrity": "sha512-Cu/kb+4HiNSejAPhSaN1VukdNTTi/r4/e+yykqjlG/IW+1gZH5b4+Bq3whDX4tvbYugta3r8KTMUiqT3fIGxuQ==", - "dev": true - }, - "jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, - "requires": { - "@isaacs/cliui": "^8.0.2", - "@pkgjs/parseargs": "^0.11.0" - } - }, - "jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true - }, - "joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true - }, - "js-tokens": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", - "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", - "dev": true - }, - "json-parse-helpfulerror": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", - "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", - "dev": true, - "requires": { - "jju": "^1.1.0" - } - }, - "json-schema-to-ts": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/json-schema-to-ts/-/json-schema-to-ts-3.1.0.tgz", - "integrity": "sha512-UeVN/ery4/JeXI8h4rM8yZPxsH+KqPi/84qFxHfTGHZnWnK9D0UU9ZGYO+6XAaJLqCWMiks+ARuFOKAiSxJCHA==", - "dev": true, - "requires": { - "@babel/runtime": "^7.18.3", - "ts-algebra": "^2.0.0" - } - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonlines": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", - "integrity": "sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==", - "dev": true - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true - }, - "jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "dev": true, - "requires": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - } - }, - "jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dev": true, - "requires": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dev": true, - "requires": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "keyv": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.0.tgz", - "integrity": "sha512-2YvuMsA+jnFGtBareKqgANOEKe1mk3HKiXu2fRmAfyxG0MJAywNhi5ttWA3PMjl4NmpyjZNbFifR2vNjW1znfA==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true - }, - "latest-version": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", - "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", - "dev": true, - "requires": { - "package-json": "^8.1.0" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", - "dev": true - }, - "local-pkg": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.0.tgz", - "integrity": "sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==", - "dev": true, - "requires": { - "mlly": "^1.4.2", - "pkg-types": "^1.0.3" - } - }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "dev": true - }, - "lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "dev": true - }, - "lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "dev": true - }, - "lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "dev": true - }, - "lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true - }, - "lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", - "dev": true - }, - "lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true - }, - "long-timeout": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/long-timeout/-/long-timeout-0.1.1.tgz", - "integrity": "sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==", - "dev": true - }, - "loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "requires": { - "get-func-name": "^2.0.1" - } - }, - "lowercase-keys": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", - "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", - "dev": true - }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, - "magicast": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.3.tgz", - "integrity": "sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw==", - "dev": true, - "requires": { - "@babel/parser": "^7.23.6", - "@babel/types": "^7.23.6", - "source-map-js": "^1.0.2" - } - }, - "make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "requires": { - "semver": "^7.5.3" - } - }, - "make-fetch-happen": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", - "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", - "dev": true, - "requires": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - } - } - }, - "mark.js": { - "version": "8.11.1", - "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", - "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", - "dev": true - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true - }, - "memory-pager": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", - "dev": true, - "optional": true - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", - "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "dev": true, - "requires": { - "encoding": "^0.1.13", - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "dependencies": { - "minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", - "dev": true - } - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "minisearch": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.0.1.tgz", - "integrity": "sha512-xLeX/AwTJLzgBF2/bdUI7MEePwXtzaLExkRwu8YFGfLDwSe06KYkplqPodLANsqvfc5Ks/r5ItFUSjIp7+9xtw==", - "dev": true - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "mitt": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "mlly": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", - "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", - "dev": true, - "requires": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.1", - "ufo": "^1.5.3" - } - }, - "mongo-sql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/mongo-sql/-/mongo-sql-4.0.2.tgz", - "integrity": "sha512-/S2uYugCpOx73dwvWRZWlTBIE0U2e6jhIWi9bcfUrM9QkKR4U1yYjP6wXiYt+kdWqhV1lICgTLMoaKR1VMdd6A==", - "dev": true - }, - "mongodb": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", - "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", - "dev": true, - "requires": { - "@mongodb-js/saslprep": "^1.1.0", - "bson": "^5.5.0", - "mongodb-connection-string-url": "^2.6.0", - "socks": "^2.7.1" - } - }, - "mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", - "dev": true, - "requires": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true - }, - "neotraverse": { - "version": "0.6.14", - "resolved": "https://registry.npmjs.org/neotraverse/-/neotraverse-0.6.14.tgz", - "integrity": "sha512-co+mqQYo1wf3CRWRHWOT1ZgG7gsdNZSrrQkWxVnGAlD/UA/IZuPlE9UNkGZRwTLeml+dT5BytRW4ANqzPQeNLg==" - }, - "node-gyp": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", - "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", - "dev": true, - "requires": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^11.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - } - }, - "nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, - "requires": { - "abbrev": "^1.0.0" - } - }, - "normalize-package-data": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", - "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", - "dev": true, - "requires": { - "hosted-git-info": "^6.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "dependencies": { - "hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "requires": { - "lru-cache": "^7.5.1" - } - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true - }, - "normalize-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-7.1.0.tgz", - "integrity": "sha512-JgkdydFdLe1E5Q7DpLvKVyBZOOwXYGhIbMbOMm3lJ06XKzaiit+qo1HciO3z3IFklStfarzJHVQf9ZcNPTvZlw==", - "dev": true - }, - "npm-bundled": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", - "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", - "dev": true, - "requires": { - "npm-normalize-package-bin": "^3.0.0" - } - }, - "npm-check-updates": { - "version": "16.14.20", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.20.tgz", - "integrity": "sha512-sYbIhun4DrjO7NFOTdvs11nCar0etEhZTsEjL47eM0TuiGMhmYughRCxG2SpGRmGAQ7AkwN7bw2lWzoE7q6yOQ==", - "dev": true, - "requires": { - "@types/semver-utils": "^1.1.1", - "chalk": "^5.3.0", - "cli-table3": "^0.6.3", - "commander": "^10.0.1", - "fast-memoize": "^2.5.2", - "find-up": "5.0.0", - "fp-and-or": "^0.1.4", - "get-stdin": "^8.0.0", - "globby": "^11.0.4", - "hosted-git-info": "^5.1.0", - "ini": "^4.1.1", - "js-yaml": "^4.1.0", - "json-parse-helpfulerror": "^1.0.3", - "jsonlines": "^0.1.1", - "lodash": "^4.17.21", - "make-fetch-happen": "^11.1.1", - "minimatch": "^9.0.3", - "p-map": "^4.0.0", - "pacote": "15.2.0", - "parse-github-url": "^1.0.2", - "progress": "^2.0.3", - "prompts-ncu": "^3.0.0", - "rc-config-loader": "^4.1.3", - "remote-git-tags": "^3.0.0", - "rimraf": "^5.0.5", - "semver": "^7.5.4", - "semver-utils": "^1.1.4", - "source-map-support": "^0.5.21", - "spawn-please": "^2.0.2", - "strip-ansi": "^7.1.0", - "strip-json-comments": "^5.0.1", - "untildify": "^4.0.0", - "update-notifier": "^6.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true - }, - "glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - } - }, - "ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "dev": true - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", - "dev": true, - "requires": { - "glob": "^10.3.7" - } - }, - "strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - }, - "strip-json-comments": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", - "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", - "dev": true - } - } - }, - "npm-install-checks": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.2.0.tgz", - "integrity": "sha512-744wat5wAAHsxa4590mWO0tJ8PKxR8ORZsH9wGpQc3nWTzozMAgBN/XyqYw7mg3yqLM8dLwEnwSfKMmXAjF69g==", - "dev": true, - "requires": { - "semver": "^7.1.1" - } - }, - "npm-normalize-package-bin": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", - "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", - "dev": true - }, - "npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "requires": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "dependencies": { - "hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "requires": { - "lru-cache": "^7.5.1" - } - }, - "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - } - } - }, - "npm-packlist": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", - "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", - "dev": true, - "requires": { - "ignore-walk": "^6.0.0" - } - }, - "npm-pick-manifest": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.2.tgz", - "integrity": "sha512-1dKY+86/AIiq1tkKVD3l0WI+Gd3vkknVGAggsFeBkTvbhMQ1OND/LKkYv4JtXPKUJ8bOTCyLiqEg2P6QNdK+Gg==", - "dev": true, - "requires": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^10.0.0", - "semver": "^7.3.5" - } - }, - "npm-registry-fetch": { - "version": "14.0.5", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", - "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", - "dev": true, - "requires": { - "make-fetch-happen": "^11.0.0", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^10.0.0", - "proc-log": "^3.0.0" - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "requires": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true - }, - "object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - } - }, - "object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } - }, - "object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "requires": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - } - }, - "p-cancelable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", - "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "package-json": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.0.tgz", - "integrity": "sha512-hySwcV8RAWeAfPsXb9/HGSPn8lwDnv6fabH+obUZKX169QknRkRhPxd1yMubpKDskLFATkl3jHpNtVtDPFA0Wg==", - "dev": true, - "requires": { - "got": "^12.1.0", - "registry-auth-token": "^5.0.1", - "registry-url": "^6.0.0", - "semver": "^7.3.7" - } - }, - "package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true - }, - "pacote": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", - "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", - "dev": true, - "requires": { - "@npmcli/git": "^4.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^6.0.1", - "@npmcli/run-script": "^6.0.0", - "cacache": "^17.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^5.0.0", - "npm-package-arg": "^10.0.0", - "npm-packlist": "^7.0.0", - "npm-pick-manifest": "^8.0.0", - "npm-registry-fetch": "^14.0.0", - "proc-log": "^3.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^6.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^1.3.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - } - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-github-url": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", - "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "requires": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "minipass": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", - "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", - "dev": true - } - } - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true - }, - "pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true - }, - "perfect-debounce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", - "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", - "dev": true - }, - "picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true - }, - "pkg-types": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.3.tgz", - "integrity": "sha512-+JrgthZG6m3ckicaOB74TwQ+tBWsFl3qVQg7mN8ulwSOElJ7gBhKzj2VkCPnZ4NlF6kEquYU+RIYNVAvzd54UA==", - "dev": true, - "requires": { - "confbox": "^0.1.7", - "mlly": "^1.7.1", - "pathe": "^1.1.2" - } - }, - "postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", - "dev": true, - "requires": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.1", - "source-map-js": "^1.2.0" - }, - "dependencies": { - "nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true - } - } - }, - "postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "requires": { - "lilconfig": "^3.1.1" - } - }, - "preact": { - "version": "10.22.1", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.22.1.tgz", - "integrity": "sha512-jRYbDDgMpIb5LHq3hkI0bbl+l/TQ9UnkdQ0ww+lp+4MMOdqaUYdFc5qeyP+IV8FAd/2Em7drVPeKdQxsiWCf/A==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "requires": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true - }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true - }, - "promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "requires": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - } - }, - "prompts-ncu": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/prompts-ncu/-/prompts-ncu-3.0.0.tgz", - "integrity": "sha512-qyz9UxZ5MlPKWVhWrCmSZ1ahm2GVYdjLb8og2sg0IPth1KRuhcggHGuijz0e41dkx35p1t1q3GRISGH7QGALFA==", - "dev": true, - "requires": { - "kleur": "^4.0.1", - "sisteransi": "^1.0.5" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "dev": true - }, - "proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "requires": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" - }, - "pupa": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", - "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", - "dev": true, - "requires": { - "escape-goat": "^4.0.0" - } - }, - "qs": { - "version": "6.12.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.12.3.tgz", - "integrity": "sha512-AWJm14H1vVaO/iNZ4/hO+HyaTehuy9nRqVdkTqlJt0HWvBiBIEXFmb4C0DGeYo3Xes9rrEW+TxHsaigCbN5ICQ==", - "dev": true, - "requires": { - "side-channel": "^1.0.6" - } - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "quick-lru": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true - }, - "range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true - }, - "raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "dev": true, - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "dependencies": { - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true - } - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true - } - } - }, - "rc-config-loader": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", - "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", - "dev": true, - "requires": { - "debug": "^4.3.4", - "js-yaml": "^4.1.0", - "json5": "^2.2.2", - "require-from-string": "^2.0.2" - } - }, - "react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true - }, - "read-package-json": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", - "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", - "dev": true, - "requires": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^5.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "10.3.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.3.tgz", - "integrity": "sha512-92vPiMb/iqpmEgsOoIDvTjc50wf9CCCvMzsi6W0JLPeUKE8TWP1a73PgqSrqy7iAZxaSD1YdzU7QZR5LF51MJw==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - } - }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", - "dev": true, - "requires": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", - "dev": true, - "requires": { - "resolve": "^1.1.6" - } - }, - "regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true - }, - "regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - } - }, - "registry-auth-token": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.1.tgz", - "integrity": "sha512-UfxVOj8seK1yaIOiieV4FIP01vfBDLsY0H9sQzi9EbbUdJiuuBjJgLa1DpImXMNPnVkBD4eVxTEXcrZA6kfpJA==", - "dev": true, - "requires": { - "@pnpm/npm-conf": "^1.0.4" - } - }, - "registry-url": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", - "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", - "dev": true, - "requires": { - "rc": "1.2.8" - } - }, - "remote-git-tags": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", - "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", - "dev": true - }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "requires": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "responselike": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", - "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", - "dev": true, - "requires": { - "lowercase-keys": "^3.0.0" - } - }, - "retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true - }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rollup": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.1.tgz", - "integrity": "sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==", - "dev": true, - "requires": { - "@rollup/rollup-android-arm-eabi": "4.18.1", - "@rollup/rollup-android-arm64": "4.18.1", - "@rollup/rollup-darwin-arm64": "4.18.1", - "@rollup/rollup-darwin-x64": "4.18.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.1", - "@rollup/rollup-linux-arm-musleabihf": "4.18.1", - "@rollup/rollup-linux-arm64-gnu": "4.18.1", - "@rollup/rollup-linux-arm64-musl": "4.18.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.1", - "@rollup/rollup-linux-riscv64-gnu": "4.18.1", - "@rollup/rollup-linux-s390x-gnu": "4.18.1", - "@rollup/rollup-linux-x64-gnu": "4.18.1", - "@rollup/rollup-linux-x64-musl": "4.18.1", - "@rollup/rollup-win32-arm64-msvc": "4.18.1", - "@rollup/rollup-win32-ia32-msvc": "4.18.1", - "@rollup/rollup-win32-x64-msvc": "4.18.1", - "@types/estree": "1.0.5", - "fsevents": "~2.3.2" - } - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", - "dev": true, - "requires": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "safe-regex-test": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.2.tgz", - "integrity": "sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", - "is-regex": "^1.1.4" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "search-insights": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.15.0.tgz", - "integrity": "sha512-ch2sPCUDD4sbPQdknVl9ALSi9H7VyoeVbsxznYz6QV55jJ8CI3EtwpO1i84keN4+hF5IeHWIeGvc08530JkVXQ==", - "dev": true, - "peer": true - }, - "semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "semver-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", - "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", - "dev": true, - "requires": { - "semver": "^7.3.5" - } - }, - "semver-utils": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/semver-utils/-/semver-utils-1.1.4.tgz", - "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", - "dev": true - }, - "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dev": true, - "requires": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - } - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } - } - }, - "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dev": true, - "requires": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "dependencies": { - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "dev": true - } - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, - "set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "requires": { - "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": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "requires": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - } - }, - "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", - "dev": true, - "requires": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - } - }, - "shiki": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-1.10.3.tgz", - "integrity": "sha512-eneCLncGuvPdTutJuLyUGS8QNPAVFO5Trvld2wgEq1e002mwctAhJKeMGWtWVXOIEzmlcLRqcgPSorR6AVzOmQ==", - "dev": true, - "requires": { - "@shikijs/core": "1.10.3", - "@types/hast": "^3.0.4" - } - }, - "short-hash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/short-hash/-/short-hash-1.0.0.tgz", - "integrity": "sha512-qbUCD2Pkl4IXRyVqneEjGnUr0NGDGLzZnBUVGJngIQZf/FrhOL0yJhH+JQzak0t8xMmScIKpoX1SxOsPHdwa4w==", - "dev": true, - "requires": { - "hash-string": "^1.0.0" - } - }, - "shx": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", - "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", - "dev": true, - "requires": { - "minimist": "^1.2.3", - "shelljs": "^0.8.5" - } - }, - "side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "requires": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - } - }, - "sift": { - "version": "17.1.3", - "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz", - "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==", - "dev": true - }, - "siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sigstore": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.9.0.tgz", - "integrity": "sha512-0Zjz0oe37d08VeOtBIuB6cRriqXse2e8w+7yIy2XSXjshRKxbc2KkhXjL229jXSxEm7UbcjS76wcJDGQddVI9A==", - "dev": true, - "requires": { - "@sigstore/bundle": "^1.1.0", - "@sigstore/protobuf-specs": "^0.2.0", - "@sigstore/sign": "^1.0.0", - "@sigstore/tuf": "^1.0.3", - "make-fetch-happen": "^11.0.1" - } - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true - }, - "socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "dev": true, - "requires": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "cors": "~2.8.5", - "debug": "~4.3.2", - "engine.io": "~6.5.2", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.4" - } - }, - "socket.io-adapter": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", - "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", - "dev": true, - "requires": { - "debug": "~4.3.4", - "ws": "~8.17.1" - } - }, - "socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", - "dev": true, - "requires": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" - } - }, - "socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dev": true, - "requires": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" - } - }, - "socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, - "requires": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - } - }, - "sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha512-/dPCrG1s3ePpWm6yBbxZq5Be1dXGLyLn9Z791chDC3NFrpkVbWGzkBwPN1knaciexFXgRJ7hzdnwZ4stHSDmjg==", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "sparse-bitfield": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", - "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", - "dev": true, - "optional": true, - "requires": { - "memory-pager": "^1.0.2" - } - }, - "spawn-please": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-2.0.2.tgz", - "integrity": "sha512-KM8coezO6ISQ89c1BzyWNtcn2V2kAVtwIXd3cN/V5a0xPYc1F/vydrRc01wsKFEQ/p+V1a4sw4z2yMITIXrgGw==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3" - } - }, - "spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", - "dev": true - }, - "speakingurl": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", - "dev": true - }, - "ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "dev": true, - "requires": { - "minipass": "^7.0.3" - }, - "dependencies": { - "minipass": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", - "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", - "dev": true - } - } - }, - "stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true - }, - "std-env": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", - "dev": true - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string-width-cjs": { - "version": "npm:string-width@4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-ansi-cjs": { - "version": "npm:strip-ansi@6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, - "strip-literal": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", - "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", - "dev": true, - "requires": { - "js-tokens": "^9.0.0" - } - }, - "sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - } - }, - "jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "requires": { - "@isaacs/cliui": "^8.0.2", - "@pkgjs/parseargs": "^0.11.0" - } - }, - "minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - }, - "minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true - } - } - }, - "superjson": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.1.tgz", - "integrity": "sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==", - "dev": true, - "requires": { - "copy-anything": "^3.0.2" - } - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "synckit": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.1.tgz", - "integrity": "sha512-7gr8p9TQP6RAHusBOSLs46F4564ZrjV8xFmw5zCmgmhGUcw2hxsShhJ6CEiHQMgPDwAQ1fWHPM0ypc4RMAig4A==", - "dev": true, - "requires": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - } - }, - "tabbable": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", - "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", - "dev": true - }, - "tar": { - "version": "6.1.15", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", - "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", - "dev": true, - "requires": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "dependencies": { - "fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "tinybench": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", - "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", - "dev": true - }, - "tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true - }, - "tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - }, - "toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true - }, - "tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } - }, - "traverse": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", - "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", - "dev": true - }, - "tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true - }, - "ts-algebra": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-algebra/-/ts-algebra-2.0.0.tgz", - "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", - "dev": true - }, - "ts-api-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.2.tgz", - "integrity": "sha512-Cbu4nIqnEdd+THNEsBdkolnOXhg0I8XteoHaEKgvsxpsbWda4IsUut2c187HxywQCvveojow0Dgw/amxtSKVkQ==", - "dev": true, - "requires": {} - }, - "ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "requires": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - } - } - }, - "tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", - "dev": true - }, - "tsup": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.1.2.tgz", - "integrity": "sha512-Gzw/PXSX/z0aYMNmkcI54bKKFVFJQbLne+EqTJZeQ3lNT3QpumjtMU4rl+ZwTTp8oRF3ahMbEAxT2sZPJLFSrg==", - "dev": true, - "requires": { - "bundle-require": "^5.0.0", - "cac": "^6.7.14", - "chokidar": "^3.6.0", - "consola": "^3.2.3", - "debug": "^4.3.5", - "esbuild": "^0.23.0", - "execa": "^5.0.0", - "globby": "^11.0.3", - "joycon": "^3.1.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.18.1", - "source-map": "0.8.0-beta.0", - "sucrase": "^3.35.0", - "tree-kill": "^1.2.2" - }, - "dependencies": { - "@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", - "dev": true, - "optional": true - }, - "esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", - "dev": true, - "requires": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "requires": { - "whatwg-url": "^7.0.0" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "tuf-js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", - "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", - "dev": true, - "requires": { - "@tufjs/models": "1.0.4", - "debug": "^4.3.4", - "make-fetch-happen": "^11.1.1" - } - }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dev": true, - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - } - }, - "typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - } - }, - "typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - } - }, - "typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - } - }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } - }, - "typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", - "dev": true - }, - "ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - } - }, - "undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, - "requires": { - "unique-slug": "^4.0.0" - } - }, - "unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unique-string": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", - "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", - "dev": true, - "requires": { - "crypto-random-string": "^4.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "update-notifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", - "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", - "dev": true, - "requires": { - "boxen": "^7.0.0", - "chalk": "^5.0.1", - "configstore": "^6.0.0", - "has-yarn": "^3.0.0", - "import-lazy": "^4.0.0", - "is-ci": "^3.0.1", - "is-installed-globally": "^0.4.0", - "is-npm": "^6.0.0", - "is-yarn-global": "^0.4.0", - "latest-version": "^7.0.0", - "pupa": "^3.1.0", - "semver": "^7.3.7", - "semver-diff": "^4.0.0", - "xdg-basedir": "^5.1.0" - }, - "dependencies": { - "chalk": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.0.1.tgz", - "integrity": "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==", - "dev": true - } - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "dev": true - }, - "uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + }, + "yaml": { + "optional": true + } } }, - "validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "node_modules/vite-node": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.2.tgz", + "integrity": "sha512-Xj/jovjZvDXOq2FgLXu8NsY4uHUMWtzVmMC2LkCu9HWdr9Qu1Is5sanX3Z4jOFKdohfaWDnEJWp9pRP0vVpAcA==", "dev": true, - "requires": { - "builtins": "^5.0.0" + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true - }, - "vite": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.4.tgz", - "integrity": "sha512-Cw+7zL3ZG9/NZBB8C+8QbQZmR54GwqIz+WMI4b3JgdYJvX+ny9AjJXqkGQlDXSXRP9rP0B4tbciRMOVEKulVOA==", + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, - "requires": { - "esbuild": "^0.21.3", - "fsevents": "~2.3.3", - "postcss": "^8.4.39", - "rollup": "^4.13.0" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "vite-node": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", - "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "requires": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "vitepress": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.3.1.tgz", - "integrity": "sha512-soZDpg2rRVJNIM/IYMNDPPr+zTHDA5RbLDHAxacRu+Q9iZ2GwSR0QSUlLs+aEZTkG0SOX1dc8RmUYwyuxK8dfQ==", - "dev": true, - "requires": { - "@docsearch/css": "^3.6.0", - "@docsearch/js": "^3.6.0", - "@shikijs/core": "^1.10.3", - "@shikijs/transformers": "^1.10.3", - "@types/markdown-it": "^14.1.1", - "@vitejs/plugin-vue": "^5.0.5", - "@vue/devtools-api": "^7.3.5", - "@vue/shared": "^3.4.31", - "@vueuse/core": "^10.11.0", - "@vueuse/integrations": "^10.11.0", - "focus-trap": "^7.5.4", + "node_modules/vitepress": { + "version": "2.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-2.0.0-alpha.6.tgz", + "integrity": "sha512-k58ZsFJi+ml0eHM6skEC3wSUm0piDJJmNJu2LSa9BhGMge69vSN07qTBDK5Ad87aDyYhmkbiIFW2AG6bboMFcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@docsearch/css": "^3.9.0", + "@docsearch/js": "^3.9.0", + "@iconify-json/simple-icons": "^1.2.38", + "@shikijs/core": "^3.6.0", + "@shikijs/transformers": "^3.6.0", + "@shikijs/types": "^3.6.0", + "@vitejs/plugin-vue": "^5.2.4", + "@vue/devtools-api": "^7.7.6", + "@vue/shared": "^3.5.16", + "@vueuse/core": "^13.3.0", + "@vueuse/integrations": "^13.3.0", + "focus-trap": "^7.6.5", "mark.js": "8.11.1", - "minisearch": "^7.0.0", - "shiki": "^1.10.3", - "vite": "^5.3.3", - "vue": "^3.4.31" - } - }, - "vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", - "dev": true, - "requires": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.0", - "why-is-node-running": "^2.2.2" - }, - "dependencies": { - "execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - } - }, - "get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true + "minisearch": "^7.1.2", + "shiki": "^3.6.0", + "vite": "^6.3.5", + "vue": "^3.5.16" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "oxc-minify": "^0.72.3", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true }, - "human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true + "oxc-minify": { + "optional": true }, - "is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true + "postcss": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.2.tgz", + "integrity": "sha512-fyNn/Rp016Bt5qvY0OQvIUCwW2vnaEBLxP42PmKbNIoasSYjML+8xyeADOPvBe+Xfl/ubIw4og7Lt9jflRsCNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.2", + "@vitest/mocker": "3.2.2", + "@vitest/pretty-format": "^3.2.2", + "@vitest/runner": "3.2.2", + "@vitest/snapshot": "3.2.2", + "@vitest/spy": "3.2.2", + "@vitest/utils": "3.2.2", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.0", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.2", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.2", + "@vitest/ui": "3.2.2", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true }, - "mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true + "@types/debug": { + "optional": true }, - "npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "requires": { - "path-key": "^4.0.0" - } + "@types/node": { + "optional": true }, - "onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "requires": { - "mimic-fn": "^4.0.0" - } + "@vitest/browser": { + "optional": true }, - "path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true + "@vitest/ui": { + "optional": true }, - "signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true + "happy-dom": { + "optional": true }, - "strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true + "jsdom": { + "optional": true } } }, - "vue": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.32.tgz", - "integrity": "sha512-9mCGIAi/CAq7GtaLLLp2J92pEic+HArstG+pq6F+H7+/jB9a0Z7576n4Bh4k79/50L1cKMIhZC3MC0iGpl+1IA==", + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, - "requires": { - "@vue/compiler-dom": "3.4.32", - "@vue/compiler-sfc": "3.4.32", - "@vue/runtime-dom": "3.4.32", - "@vue/server-renderer": "3.4.32", - "@vue/shared": "3.4.32" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true + "node_modules/vitest/node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" }, - "whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "node_modules/vue": { + "version": "3.5.16", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.16.tgz", + "integrity": "sha512-rjOV2ecxMd5SiAmof2xzh2WxntRcigkX/He4YFJ6WdRvVUrbt6DxC1Iujh10XLl8xCDRDtGKMeO3D+pRQ1PP9w==", "dev": true, - "requires": { - "tr46": "^3.0.0", - "webidl-conversions": "^7.0.0" + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.16", + "@vue/compiler-sfc": "3.5.16", + "@vue/runtime-dom": "3.5.16", + "@vue/server-renderer": "3.5.16", + "@vue/shared": "3.5.16" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/vue-resize": { + "version": "2.0.0-alpha.1", + "resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz", + "integrity": "sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==", "dev": true, - "requires": { - "isexe": "^2.0.0" + "license": "MIT", + "peerDependencies": { + "vue": "^3.0.0" } }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } + "license": "MIT" }, - "which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "why-is-node-running": { + "node_modules/why-is-node-running": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" } }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "widest-line": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", - "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { - "string-width": "^5.0.1" - }, + "license": "MIT", "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } - } - }, - "wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "requires": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, - "dependencies": { - "ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true - }, - "ansi-styles": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.1.1.tgz", - "integrity": "sha512-qDOv24WjnYuL+wbwHdlsYZFy+cgPtrYw0Tn7GLORicQp9BkQLzrgI3Pm4VyR9ERZ41YTn7KlMPuL1n05WdZvmg==", - "dev": true - }, - "emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "requires": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - } - }, - "strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", - "dev": true, - "requires": { - "ansi-regex": "^6.0.1" - } - } + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@7.0.0", + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, - "requires": { + "license": "MIT", + "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "wrappy": { + "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } + "license": "ISC" }, - "ws": { + "node_modules/ws": { "version": "8.17.1", "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, - "requires": {} + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } }, - "xdg-basedir": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", - "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", - "dev": true + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } }, - "yallist": { + "node_modules/yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } } } } diff --git a/package.json b/package.json index f9a56062..9ad09e35 100644 --- a/package.json +++ b/package.json @@ -3,20 +3,37 @@ "version": "8.2.1", "description": "Useful hooks for use with Feathersjs services.", "main": "./dist/index.js", - "module": "./dist/index.mjs", + "module": "./dist/index.js", "types": "./dist/index.d.ts", + "type": "module", "exports": { ".": { - "require": "./dist/index.js", - "import": "./dist/index.mjs", - "types": "./dist/index.d.ts" + "types": "./dist/index.d.ts", + "import": "./dist/index.js" + }, + "./hooks": { + "types": "./dist/hooks.d.ts", + "import": "./dist/hooks.js" + }, + "./utils": { + "types": "./dist/utils.d.ts", + "import": "./dist/utils.js" + }, + "./predicates": { + "types": "./dist/predicates.d.ts", + "import": "./dist/predicates.js" + }, + "./resolvers": { + "types": "./dist/resolvers.d.ts", + "import": "./dist/resolvers.js" } }, "scripts": { - "compile": "shx rm -rf dist/ && tsup src/index.ts --format cjs,esm --dts --treeshake", - "docs": "vitepress dev docs", + "build": "tsc --noEmit && tsdown", + "docs:dev": "vitepress dev docs --port 5177", "docs:build": "vitepress build docs", - "prepublishOnly": "npm run compile", + "docs:preview": "vitepress preview docs --port 4177", + "prepublishOnly": "npm run build", "publish": "git push origin --tags && npm run changelog && git push origin", "release:prerelease": "npm version prerelease --preid pre && npm publish --tag pre", "release:premajor": "npm version premajor --preid pre && npm publish --tag pre", @@ -24,11 +41,12 @@ "release:minor": "npm version minor && npm publish", "release:major": "npm version major && npm publish", "changelog": "github_changelog_generator --max-issues 200 -u feathersjs-ecosystem -p feathers-hooks-common && git add CHANGELOG.md && git commit -am \"Updating changelog\"", - "lint": "eslint src/**/*.ts test/**/*.ts --fix", - "update-dependencies": "ncu -u -x ajv", + "lint": "eslint .", + "update-dependencies": "ncu -u", "test:unit": "vitest run", "coverage": "vitest run --coverage", - "test": "npm run lint && npm run coverage" + "test": "npm run lint && npm run coverage", + "vitest": "vitest" }, "repository": { "type": "git", @@ -62,49 +80,43 @@ "dist/**" ], "dependencies": { - "@feathersjs/errors": "^5.0.29", - "ajv": "^6.12.6", - "debug": "^4.3.5", - "graphql": "^16.9.0", + "@feathersjs/errors": "^5.0.31", + "fast-copy": "^3.0.2", "lodash": "^4.17.21", - "neotraverse": "^0.6.14" + "neotraverse": "^0.6.18" }, "devDependencies": { - "@feathers-plus/batch-loader": "^0.3.6", + "@feathers-community/eslint-config": "^0.0.7", "@feathers-plus/cache": "^1.4.0", - "@feathers-plus/graphql": "^1.10.0", - "@feathersjs/authentication": "^5.0.29", - "@feathersjs/authentication-local": "^5.0.29", - "@feathersjs/client": "^5.0.29", - "@feathersjs/express": "^5.0.29", - "@feathersjs/memory": "^5.0.29", - "@feathersjs/socketio": "^5.0.29", - "@feathersjs/socketio-client": "^5.0.29", - "@types/debug": "^4.1.12", - "@types/lodash": "^4.17.7", - "@types/node": "^20.14.11", - "@typescript-eslint/eslint-plugin": "^6.21.0", - "@typescript-eslint/parser": "^6.21.0", - "@vitest/coverage-v8": "^1.6.0", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-prefer-arrow": "^1.2.3", - "eslint-plugin-prettier": "^5.2.1", - "mongodb": "^5.9.2", - "npm-check-updates": "^16.14.20", - "prettier": "^3.3.3", + "@feathersjs/authentication": "^5.0.31", + "@feathersjs/authentication-local": "^5.0.31", + "@feathersjs/client": "^5.0.31", + "@feathersjs/express": "^5.0.31", + "@feathersjs/memory": "^5.0.31", + "@feathersjs/socketio": "^5.0.31", + "@feathersjs/socketio-client": "^5.0.31", + "@shikijs/vitepress-twoslash": "^3.6.0", + "@tailwindcss/vite": "^4.1.10", + "@tsconfig/node22": "^22.0.2", + "@types/lodash": "^4.17.14", + "@types/node": "^22.10.7", + "@vitest/coverage-v8": "^3.0.3", + "dedent": "^1.6.0", + "eslint": "^9.18.0", + "glob": "^11.0.2", + "gray-matter": "^4.0.3", + "npm-check-updates": "^17.1.14", + "prettier": "^3.4.2", "shx": "^0.3.4", "sift": "^17.1.3", - "tsup": "^8.1.2", - "typescript": "^5.5.3", - "vitepress": "^1.3.1", - "vitest": "^1.6.0" + "tailwindcss": "^4.1.10", + "tsdown": "^0.12.7", + "typescript": "^5.7.3", + "unplugin-unused": "^0.5.0", + "vitepress": "^2.0.0-alpha.6", + "vitest": "^3.0.3" }, "peerDependencies": { "@feathersjs/feathers": "^5.0.0" - }, - "engines": { - "node": ">= 18" } } diff --git a/src/common/clone.ts b/src/common/clone.ts index 825ce060..4f35d9b0 100644 --- a/src/common/clone.ts +++ b/src/common/clone.ts @@ -1,3 +1,3 @@ export function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); + return JSON.parse(JSON.stringify(obj)) } diff --git a/src/common/index.ts b/src/common/index.ts index d1efe961..4fd737f1 100644 --- a/src/common/index.ts +++ b/src/common/index.ts @@ -1,9 +1,6 @@ export function isPromise(p: any): p is Promise { - return !!p && (typeof p === 'object' || typeof p === 'function') && typeof p.then === 'function'; + return p instanceof Promise } -export { pluck } from './pluck'; -export { setFields } from './set-fields'; -export { transformItems } from './transform-items'; -export { traverse } from './traverse'; -export { clone } from './clone'; +export { traverse } from './traverse.js' +export { clone } from './clone.js' diff --git a/src/common/pluck.ts b/src/common/pluck.ts deleted file mode 100755 index ecd91d9f..00000000 --- a/src/common/pluck.ts +++ /dev/null @@ -1,24 +0,0 @@ -import _pick from 'lodash/pick.js'; - -export function pluck>( - items: T, - fieldNames: string[], -): Record; -export function pluck>( - items: T[], - fieldNames: string[], -): Record[]; -export function pluck>( - items: T | T[], - fieldNames: string[], -): Record | Record[] { - if (!Array.isArray(items)) { - return _pick(items, fieldNames); - } - - const pluckedItems = (Array.isArray(items) ? items : [items]).map(item => - _pick(item, fieldNames), - ); - - return pluckedItems; -} diff --git a/src/common/set-fields.ts b/src/common/set-fields.ts deleted file mode 100755 index 8ae66905..00000000 --- a/src/common/set-fields.ts +++ /dev/null @@ -1,18 +0,0 @@ -import _set from 'lodash/set.js'; - -export function setFields>( - items: T | T[], - fieldValue: any, - fieldNames: string[], - defaultFieldName: string, -): void { - const value = typeof fieldValue === 'function' ? fieldValue() : fieldValue; - - if (!fieldNames.length) fieldNames = [defaultFieldName]; - - (Array.isArray(items) ? items : [items]).forEach(item => { - fieldNames.forEach((fieldName: any) => { - _set(item, fieldName, value); - }); - }); -} diff --git a/src/common/transform-items.ts b/src/common/transform-items.ts deleted file mode 100755 index 091e94ce..00000000 --- a/src/common/transform-items.ts +++ /dev/null @@ -1,13 +0,0 @@ -import _get from 'lodash/get.js'; - -export function transformItems>( - items: T | T[], - fieldNames: string[], - transformer: (item: T, fieldName: string, val: any) => void, -): void { - (Array.isArray(items) ? items : [items]).forEach(item => { - fieldNames.forEach((fieldName: any) => { - transformer(item, fieldName, _get(item, fieldName)); - }); - }); -} diff --git a/src/common/traverse.ts b/src/common/traverse.ts index 58212a04..b8337f1d 100755 --- a/src/common/traverse.ts +++ b/src/common/traverse.ts @@ -1,10 +1,10 @@ -import traverser from 'neotraverse/legacy'; +import traverser from 'neotraverse/legacy' export function traverse>( items: T | T[], converter: (item: T) => void, ) { - (Array.isArray(items) ? items : [items]).forEach(item => { - traverser(item).forEach(converter); // replacement is in place - }); + ;(Array.isArray(items) ? items : [items]).forEach(item => { + traverser(item).forEach(converter) // replacement is in place + }) } diff --git a/src/hooks/act-on-dispatch.ts b/src/hooks/act-on-dispatch.ts deleted file mode 100755 index 893ffe07..00000000 --- a/src/hooks/act-on-dispatch.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import type { HookFunction } from '../types'; -import { combine } from '../utils/combine'; - -/** - * Runs a series of hooks which mutate context.data or context.result (the Feathers default). - * @see https://hooks-common.feathersjs.com/hooks.html#actondefault - */ -export const actOnDefault = (...hooks: HookFunction[]) => - actOn(undefined, ...hooks); - -/** - * Runs a series of hooks which mutate context.dispatch. - * @see https://hooks-common.feathersjs.com/hooks.html#actondispatch - */ -export const actOnDispatch = (...hooks: HookFunction[]) => - actOn('dispatch', ...hooks); - -function actOn(what: any, ...hooks: HookFunction[]) { - return async (context: H) => { - // @ts-ignore - const currActOn = context.params._actOn; - // @ts-ignore - context.params._actOn = what; - - const newContext = await combine(...hooks)(context); - newContext.params._actOn = currActOn; - return newContext; - }; -} diff --git a/src/hooks/alter-items.ts b/src/hooks/alter-items.ts deleted file mode 100755 index 4e6863dc..00000000 --- a/src/hooks/alter-items.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; - -import type { HookContext } from '@feathersjs/feathers'; -import { isPromise } from '../common'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; - -/** - * Make changes to data or result items. Very flexible. - * @see https://hooks-common.feathersjs.com/hooks.html#alteritems - */ -export function alterItems( - cb: (record: T, context: H) => any, -) { - if (!cb) { - cb = () => {}; - } - - if (typeof cb !== 'function') { - throw new BadRequest('Function required. (alter)'); - } - - return (context: H) => { - let items = getItems(context); - const isArray = Array.isArray(items); - - const results: any[] = (isArray ? items : [items]).map((item: any) => cb(item, context)); - - const hasPromises = results.some((result: any) => isPromise(result)); - - const setItem = (value: any, index: any) => { - if (typeof value === 'object' && value !== null) { - if (isArray) { - items[index] = value; - } else { - items = value; - } - } - }; - - if (hasPromises) { - return Promise.all(results).then(values => { - values.forEach(setItem); - - replaceItems(context, items); - return context; - }); - } else { - results.forEach(setItem); - - replaceItems(context, items); - return context; - } - }; -} diff --git a/src/hooks/cache.ts b/src/hooks/cache.ts deleted file mode 100755 index fe9c94d2..00000000 --- a/src/hooks/cache.ts +++ /dev/null @@ -1,89 +0,0 @@ -import type { HookContext, Id } from '@feathersjs/feathers'; -import { getItems } from '../utils/get-items'; -import { clone as defaultClone } from '../common/clone'; - -export type CacheMap = Map; - -export interface CacheOptions { - clone?(item: T): T; - makeCacheKey?(id: Id): string; -} - -const defaultMakeCacheKey = (key: any) => key; - -/** - * Persistent, most-recently-used record cache for services. - * - * @see https://hooks-common.feathersjs.com/hooks.html#cache - */ -export function cache( - cacheMap: CacheMap, - keyField?: string, - options?: CacheOptions, -) { - const clone = options?.clone || defaultClone; - const makeCacheKey = options?.makeCacheKey || defaultMakeCacheKey; - - return (context: H) => { - keyField = keyField || context.service?.id; // Will be undefined on client - - let items = getItems(context); - items = Array.isArray(items) ? items : [items]; - - const query = context.params.query || {}; - - if (context.type === 'after') { - if (context.method === 'remove') { - items.forEach((item: any) => { - const idName = getIdName(keyField, item); - const key = makeCacheKey(item[idName]); - cacheMap.delete(key); - }); - return context; - } - - if (query.$select) return context; - - items.forEach((item: any) => { - const idName = getIdName(keyField, item); - const key = makeCacheKey(item[idName]); - cacheMap.set(key, clone(item)); - }); - - return context; - } - - switch (context.method) { - case 'find': // fall through - case 'remove': // skip remove in before remove - case 'create': - return context; - case 'get': { - if (!Object.keys(query).length) { - const key = makeCacheKey(context.id!); - const value = cacheMap.get(key); - if (value) context.result = value; - } - return context; - } - default: // update, patch, remove - if (context.id) { - cacheMap.delete(context.id); - return context; - } - - items.forEach((item: any) => { - const idName = getIdName(keyField, item); - const key = makeCacheKey(item[idName]); - cacheMap.delete(key); - }); - } - - return context; - }; -} - -function getIdName(keyField: any, item: any) { - if (keyField) return keyField; - return '_id' in item ? '_id' : 'id'; -} diff --git a/src/hooks/cache/cache.md b/src/hooks/cache/cache.md new file mode 100644 index 00000000..ad7ba63e --- /dev/null +++ b/src/hooks/cache/cache.md @@ -0,0 +1,94 @@ +--- +title: cache +description: Persistent, least-recently-used record cache for services. +category: hooks +hook: + type: ['before', 'after'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- + +## Arguments + +- `{Object | Map} cacheMap` +- `{String} [ keyField ]` +- `{Object} [ options ]` + - `{Function} [ clone ]` + - `{Function} [makeCacheKey]` + +| Argument | Type | Default | Description | +| ---------- | :------------: | -------------------------------------------------- | ---------------------------------------------------------------------------- | +| `cacheMap` | `Object` `Map` | | Instance of `Map`, or an object with a similar API, to be used as the cache. | +| `keyField` | `String` | `context.service.id` or `item._id ? '_id' !! 'id'` | The name of the record id field. | +| `option` | `Object` | | Options. | + +| `options` | Argument | Type | Default | Description | +| -------------- | ---------- | :--------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------ | ----------- | +| `clone` | `Function` | `item => JSON.parse(` `JSON.stringify(item) )` | Function to perform a deep clone. See below. | +| `makeCacheKey` | `Function` | `key => key` | Function to convert record key to cache key. Use this to convert MongoDB/Mongoose ObjectId/bson keys to a cache key using `item._id.toString()`. | + +## Examples + +```ts twoslash +const CacheMap = require('@feathers-plus/cache'); +const { cache } = require('feathers-hooks-common/index.js'); + +const cacheMap = CacheMap({ max: 100 }); // Keep the 100 most recently used. + +module.exports = { before: { all: cache(cacheMap) }, after: { all: cache(cacheMap) } }; +``` + +```js +const { cache } = require('feathers-hooks-common/index.js'); + +const cacheMap = new Map(); + +module.exports = { before: { all: cache(cacheMap) }, after: { all: cache(cacheMap) } }; +``` + +```js +const CacheMap = require('@feathers-plus/cache'); +const mongoose = require('mongoose'); +const { cache } = require('feathers-hooks-common/index.js'); + +const cacheMap = CacheMap({ max: 100 }); +const makeCacheKey = key => (key instanceof mongoose.Types.ObjectId ? key.toString() : key); + +module.exports = { + before: { all: cache(cacheMap, undefined, { makeCacheKey }) }, + after: { all: cache(cacheMap, undefined, { makeCacheKey }) }, +}; +``` + +> The `cache` hook **must** be registered in both `before` and `after`. + +

The cache will grow without limit when `Map` is used and the resulting memory pressure may adversely affect your performance. `Map` should only be used when you know or can control its size.

+ +## Details + +The `cache` hook maintain a persistent cache for the service it is registerd on. A persistent cache stores records so future requests for those records can be served faster; the records stored in the cache are duplicates of records stored in the database. + +The `get` service method retrieves records from the cache and updates `context.result` `[.data]`. The other methods remove their `context.data` entries from the cache in the `before` hook, and add entries in the `after` hook. All the records returned by a `find` call are added to the cache. + +The `cache` hook may be provided a custom Map instance to use as its memoization cache. Any object that implements the methods get(), set(), delete() and clear() can be provided. This allows for custom Maps which implement various [cache algorithms](https://en.wikipedia.org/wiki/Cache_replacement_policies) to be provided. + +The companion `@feathers-plus/cache` provides a least recently-used cache which discards the least recently used items first. It is compatible with `cache` as well as the BatchLoaders used with the `fastJoin` hook. + +> The `cache` hook can make [fastJoin](#fastjoin) hooks run more efficiently. + +MongoDB and Mongoose store record keys as bson objects rather than as scalars. The safest way to use the cache is in conjunction with the `makeCacheKey` option. + +- **options.clone** + + The clone function has a single parameter. + + - `{Object} item` + + It returns + + - `{Object} clonedItem` + +| Argument | Type | Default | Description | +| ------------ | :------: | ------- | ------------------ | +| `item` | `Object` | | The record. | +| `clonedItem` | `Object` | | A clone of `item`. | diff --git a/src/hooks/cache/cache.test.ts b/src/hooks/cache/cache.test.ts new file mode 100755 index 00000000..b39b8d1f --- /dev/null +++ b/src/hooks/cache/cache.test.ts @@ -0,0 +1,364 @@ +import { assert } from 'vitest' +import { cache } from './cache.js' + +// @ts-expect-error old +import CacheMap from '@feathers-plus/cache' + +let cacheMap: any +let hookBeforeSingle: any +let hookBeforeMulti: any +let hookAfterSingle: any +let hookAfterSingleNormalize: any +let hookAfterMulti: any +let hookAfterPaginated: any +let hookBeforeUuid: any +let hookAfterUuid: any +let hookBeforeMultiMixed: any +let hookAfterMultiMixed: any +let map: any +let cloneCount: any + +const makeCacheKey = (key: any) => -key + +describe('service cache', () => { + beforeEach(() => { + cacheMap = CacheMap({ max: 3 }) + map = new Map() + cloneCount = 0 + + hookBeforeSingle = { + type: 'before', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + data: { id: 1, first: 'John', last: 'Doe' }, + } + hookBeforeMulti = { + type: 'before', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + data: [ + { id: 1, first: 'John', last: 'Doe' }, + { id: 2, first: 'Jane', last: 'Doe' }, + ], + } + hookAfterSingle = { + type: 'after', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + result: { id: 1, first: 'Jane', last: 'Doe' }, + } + hookAfterSingleNormalize = { + type: 'after', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + result: { id: -1, first: 'Jane', last: 'Doe' }, + } + hookAfterMulti = { + type: 'after', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + result: [ + { id: 1, first: 'John', last: 'Doe' }, + { id: 2, first: 'Jane', last: 'Doe' }, + ], + } + hookAfterPaginated = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: { + total: 2, + data: [ + { id: 1, first: 'John', last: 'Doe' }, + { id: 2, first: 'Jane', last: 'Doe' }, + ], + }, + } + hookBeforeUuid = { + type: 'before', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + data: { uuid: 1, first: 'John', last: 'Doe' }, + service: { id: 'uuid' }, + } + hookAfterUuid = { + type: 'after', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + result: { uuid: 1, first: 'Jane', last: 'Doe' }, + service: { id: 'uuid' }, + } + hookBeforeMultiMixed = { + type: 'before', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + data: [ + { _id: 1, first: 'John', last: 'Doe' }, + { id: 2, first: 'Jane', last: 'Doe' }, + ], + } + hookAfterMultiMixed = { + type: 'after', + id: undefined, + method: undefined, + params: { provider: 'rest' }, + result: [ + { id: 1, first: 'John', last: 'Doe' }, + { _id: 2, first: 'Jane', last: 'Doe' }, + ], + } + }) + + describe('Can build a cache', () => { + it('Can build a cache', () => { + cacheMap.set('a', 'aa') + assert.equal(cacheMap.get('a'), 'aa', 'bad get after set') + + cacheMap.delete('a') + assert.equal(cacheMap.get('a'), undefined, 'bad get after delete') + + cacheMap.set('a', 'aa') + cacheMap.clear() + assert.equal(cacheMap.get('a'), undefined, 'bad get after clear') + }) + }) + + describe('Clears cache', () => { + it('Before one-record update', () => { + hookBeforeSingle.method = 'update' + + cacheMap.set(1, 123) + + cache(cacheMap, 'id')(hookBeforeSingle) + assert.deepEqual(cacheMap.get(1), undefined) + }) + + it('Before multi-record update', () => { + hookBeforeMulti.method = 'update' + + cacheMap.set(1, 123) + cacheMap.set(2, 124) + + cache(cacheMap, 'id')(hookBeforeMulti) + + assert.deepEqual(cacheMap.get(1), undefined) + assert.deepEqual(cacheMap.get(2), undefined) + }) + + it('Before one-record patch', () => { + hookBeforeSingle.method = 'patch' + + cacheMap.set(1, 123) + + cache(cacheMap, 'id')(hookBeforeSingle) + + assert.deepEqual(cacheMap.get(1), undefined) + }) + + it('Before multi-record patch', () => { + hookBeforeMulti.method = 'patch' + + cacheMap.set(1, 123) + cacheMap.set(2, 789) + + cache(cacheMap, 'id')(hookBeforeMulti) + assert.deepEqual(cacheMap.get(1), undefined, 'id 1') + assert.deepEqual(cacheMap.get(2), undefined, 'id 2') + }) + + it('NOT before one-record create', () => { + hookBeforeSingle.method = 'create' + + cacheMap.set(1, 123) + + cache(cacheMap, 'id')(hookBeforeSingle) + assert.deepEqual(cacheMap.get(1), 123) + }) + + it('NOT before multi-record remove', () => { + hookBeforeMulti.method = 'remove' + + cacheMap.set(1, 123) + cacheMap.set(2, 321) + + cache(cacheMap, 'id')(hookBeforeMulti) + assert.deepEqual(cacheMap.get(1), 123) + assert.deepEqual(cacheMap.get(2), 321) + }) + + it('After multi-record remove', () => { + hookAfterMulti.method = 'remove' + + cacheMap.set(1, 123) + cacheMap.set(2, 321) + + cache(cacheMap, 'id')(hookAfterMulti) + + assert.deepEqual(cacheMap.get(1), undefined, 'id 1') + assert.deepEqual(cacheMap.get(2), undefined, 'id 2') + }) + }) + + describe('Loads cache', () => { + it('After one-record create', () => { + hookAfterSingle.method = 'create' + + cache(cacheMap, 'id')(hookAfterSingle) + assert.deepEqual(cacheMap.get(1), { id: 1, first: 'Jane', last: 'Doe' }) + }) + + it('After multi-record patch', () => { + hookAfterMulti.method = 'patch' + + cache(cacheMap, 'id')(hookAfterMulti) + + assert.deepEqual(cacheMap.get(1), { id: 1, first: 'John', last: 'Doe' }, 'id 1') + assert.deepEqual(cacheMap.get(2), { id: 2, first: 'Jane', last: 'Doe' }, 'id 2') + }) + + it('After paginated find', () => { + cache(cacheMap, 'id')(hookAfterPaginated) + + assert.deepEqual(cacheMap.get(1), { id: 1, first: 'John', last: 'Doe' }, 'id 1') + assert.deepEqual(cacheMap.get(2), { id: 2, first: 'Jane', last: 'Doe' }, 'id 2') + }) + + it('NOT after remove', () => { + hookAfterMulti.method = 'remove' + + cache(cacheMap, 'id')(hookAfterMulti) + + assert.deepEqual(cacheMap.get(1), undefined, 'id 1') + assert.deepEqual(cacheMap.get(2), undefined, 'id 2') + }) + + it('Normalizes record', () => { + hookAfterSingleNormalize.method = 'create' + + // @ts-expect-error TODO + cache(cacheMap, 'id', { makeCacheKey })(hookAfterSingleNormalize) + assert.deepEqual(cacheMap.get(1), { id: -1, first: 'Jane', last: 'Doe' }) + }) + }) + + describe('Gets from cache', () => { + it('Before one-record get', () => { + hookBeforeSingle.method = 'get' + hookBeforeSingle.id = 1 + + cacheMap.set(1, { foo: 'bar' }) + + cache(cacheMap, 'id')(hookBeforeSingle) + + assert.deepEqual(cacheMap.get(1), { foo: 'bar' }, 'cache') + assert.deepEqual(hookBeforeSingle.result, { foo: 'bar' }) + }) + + it('Normalizes record', () => { + hookBeforeSingle.method = 'get' + hookBeforeSingle.id = -1 + + cacheMap.set(1, { id: -1, foo: 'bar' }) + + // @ts-expect-error TODO + cache(cacheMap, 'id', { makeCacheKey })(hookBeforeSingle) + + assert.deepEqual(cacheMap.get(1), { id: -1, foo: 'bar' }, 'cache') + assert.deepEqual(hookBeforeSingle.result, { id: -1, foo: 'bar' }) + }) + }) + + describe('Uses context.service.id', () => { + it('Clears cache before one-record update', () => { + hookBeforeUuid.method = 'update' + + cacheMap.set(1, 123) + + cache(cacheMap)(hookBeforeUuid) + assert.deepEqual(cacheMap.get(1), undefined) + }) + + it('Loads cache after one-record create', () => { + hookAfterUuid.method = 'create' + + cache(cacheMap)(hookAfterUuid) + assert.deepEqual(cacheMap.get(1), { uuid: 1, first: 'Jane', last: 'Doe' }) + }) + + it('Before one-record get', () => { + hookBeforeUuid.method = 'get' + hookBeforeUuid.id = 1 + + cacheMap.set(1, { foo: 'bar' }) + + cache(cacheMap)(hookBeforeUuid) + + assert.deepEqual(cacheMap.get(1), { foo: 'bar' }, 'cache') + assert.deepEqual(hookBeforeUuid.result, { foo: 'bar' }) + }) + }) + + describe('Uses item._id || item.id', () => { + it('Clears cache before multi-record patch', () => { + hookBeforeMultiMixed.method = 'patch' + + cacheMap.set(1, 123) + cacheMap.set(2, 789) + + cache(cacheMap)(hookBeforeMultiMixed) + assert.deepEqual(cacheMap.get(1), undefined, 'id 1') + assert.deepEqual(cacheMap.get(2), undefined, 'id 2') + }) + + it('Loads cache after multi-record patch', () => { + hookAfterMultiMixed.method = 'patch' + + cache(cacheMap)(hookAfterMultiMixed) + + assert.deepEqual(cacheMap.get(1), { id: 1, first: 'John', last: 'Doe' }, 'id 1') + assert.deepEqual(cacheMap.get(2), { _id: 2, first: 'Jane', last: 'Doe' }, 'id 2') + }) + }) + + describe('Works with an ES6 Map', () => { + it('Clears cache before one-record update', () => { + hookBeforeUuid.method = 'update' + + map.set(1, 123) + + cache(map)(hookBeforeUuid) + assert.deepEqual(map.get(1), undefined) + }) + + it('Loads cache after one-record create', () => { + hookAfterUuid.method = 'create' + + cache(map)(hookAfterUuid) + assert.deepEqual(map.get(1), { uuid: 1, first: 'Jane', last: 'Doe' }) + }) + }) + + describe('Misc', () => { + it('Uses option.clone', () => { + hookAfterUuid.method = 'create' + + // @ts-expect-error TODO + cache(cacheMap, null, { clone })(hookAfterUuid) + assert.deepEqual(cacheMap.get(1), { uuid: 1, first: 'Jane', last: 'Doe' }, 'get') + assert.equal(cloneCount, 1, 'count') + }) + }) +}) + +function clone(obj: any) { + cloneCount += 1 + return Object.assign({}, obj) +} diff --git a/src/hooks/cache/cache.ts b/src/hooks/cache/cache.ts new file mode 100755 index 00000000..d575cec6 --- /dev/null +++ b/src/hooks/cache/cache.ts @@ -0,0 +1,92 @@ +import type { HookContext, Id } from '@feathersjs/feathers' +import { getItems } from '../../utils/index.js' +import { clone as defaultClone } from '../../common/index.js' + +export type CacheMap = Map + +export interface CacheOptions { + clone?(item: T): T + makeCacheKey?(id: Id): string +} + +const defaultMakeCacheKey = (key: any) => key + +/** + * A hook that caches results in a Map. + * + * @param cacheMap - The Map to use for caching. + * @param keyField - Optional field name to use as the cache key. + * @param options - Optional configuration for cloning and cache key generation. + * @param options.clone - Function to clone items before caching. + */ +export function cache( + cacheMap: CacheMap, + keyField?: string, + options?: CacheOptions, +) { + const clone = options?.clone || defaultClone + const makeCacheKey = options?.makeCacheKey || defaultMakeCacheKey + + return (context: H) => { + keyField = keyField || context.service?.id // Will be undefined on client + + let items = getItems(context) + items = Array.isArray(items) ? items : [items] + + const query = context.params.query || {} + + if (context.type === 'after') { + if (context.method === 'remove') { + items.forEach((item: any) => { + const idName = getIdName(keyField, item) + const key = makeCacheKey(item[idName]) + cacheMap.delete(key) + }) + return context + } + + if (query.$select) return context + + items.forEach((item: any) => { + const idName = getIdName(keyField, item) + const key = makeCacheKey(item[idName]) + cacheMap.set(key, clone(item)) + }) + + return context + } + + switch (context.method) { + case 'find': // fall through + case 'remove': // skip remove in before remove + case 'create': + return context + case 'get': { + if (!Object.keys(query).length) { + const key = makeCacheKey(context.id!) + const value = cacheMap.get(key) + if (value) context.result = value + } + return context + } + default: // update, patch, remove + if (context.id) { + cacheMap.delete(context.id) + return context + } + + items.forEach((item: any) => { + const idName = getIdName(keyField, item) + const key = makeCacheKey(item[idName]) + cacheMap.delete(key) + }) + } + + return context + } +} + +function getIdName(keyField: any, item: any) { + if (keyField) return keyField + return '_id' in item ? '_id' : 'id' +} diff --git a/src/hooks/check-required/check-required.md b/src/hooks/check-required/check-required.md new file mode 100644 index 00000000..fc190fb5 --- /dev/null +++ b/src/hooks/check-required/check-required.md @@ -0,0 +1,24 @@ +--- +title: checkRequired +description: Check selected fields exist and are not falsey. Numeric 0 is acceptable. +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | ------------------------------------------------------------------- | +| fieldNames | dot notation | These fields must exist and not be falsey. Numeric 0 is acceptable. | + +## Example + +```js +const { required } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { all: required('email', 'password') } }; +``` diff --git a/src/hooks/check-required/check-required.test.ts b/src/hooks/check-required/check-required.test.ts new file mode 100755 index 00000000..85c6d935 --- /dev/null +++ b/src/hooks/check-required/check-required.test.ts @@ -0,0 +1,36 @@ +import { assert } from 'vitest' +import { checkRequired } from './check-required.js' +import type { HookContext } from '@feathersjs/feathers' + +let hookBefore: HookContext + +describe('checkRequired', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + } as HookContext + }) + + it('does 1 prop with no dots', () => { + checkRequired('empl')(hookBefore) + }) + + it('does multi props with 1 dot', () => { + checkRequired(['empl.name', 'dept'])(hookBefore) + }) + + it('does multi props with 2 dots', () => { + checkRequired(['empl.name.last', 'empl.status', 'dept'])(hookBefore) + }) + + it('throws on bad or missing paths', () => { + assert.throws(() => checkRequired(['empl.name.first', 'empl.name.surname'])(hookBefore)) + }) + + it('ignores bad or missing no dot path', () => { + assert.throws(() => checkRequired('xx')(hookBefore)) + }) +}) diff --git a/src/hooks/check-required/check-required.ts b/src/hooks/check-required/check-required.ts new file mode 100755 index 00000000..a872ec12 --- /dev/null +++ b/src/hooks/check-required/check-required.ts @@ -0,0 +1,41 @@ +import _get from 'lodash/get.js' +import _has from 'lodash/has.js' +import { BadRequest } from '@feathersjs/errors' + +import { checkContext, getDataIsArray } from '../../utils/index.js' +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Check selected fields exist and are not falsey. Numeric 0 is acceptable. + * @see https://hooks-common.feathersjs.com/hooks.html#required + */ +export function checkRequired(fieldNames: MaybeArray) { + const fieldNamesArray = toArray(fieldNames) + return (context: H, next?: NextFunction) => { + checkContext(context, ['before', 'around'], ['create', 'update', 'patch'], 'checkRequired') + + const { data } = getDataIsArray(context) + + for (let i = 0; i < data.length; i++) { + const item = data[i] + + for (let j = 0; j < fieldNamesArray.length; j++) { + const name = fieldNamesArray[j] + + if (!_has(item, name)) { + throw new BadRequest(`Field ${name} does not exist. (required)`) + } + + const value = _get(item, name) + + if (!value && value !== 0 && value !== false) { + throw new BadRequest(`Field ${name} is null. (required)`) + } + } + } + + if (next) return next().then(() => context) + } +} diff --git a/src/hooks/combine/combine.md b/src/hooks/combine/combine.md new file mode 100644 index 00000000..59e0189a --- /dev/null +++ b/src/hooks/combine/combine.md @@ -0,0 +1,43 @@ +--- +title: combine +description: Sequentially execute multiple sync or async hooks. +category: hooks +hook: + type: ['before', 'after'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{Array< Function >} hookFuncs` + +| Argument | Type | Default | Description | +| ----------- | :----------------: | ------- | --------------------------------------------------- | +| `hookFuncs` | `Array` | | Hooks, used the same way as when you register them. | + +## Example + +```js +const { combine, createdAt, updatedAt } = require('feathers-hooks-common/index.js'); + +async function myCustomHook(context) { + const newContext = await combine(setNow('createdAt'), setNow('updatedAt')).call(this, context); + return newContext; +} +``` + +## Details + +`combine` has the signature of a hook, but is primarily intended to be used within your custom hooks, not when registering hooks. + +The following is a better technique to use when registering hooks. + +```js +const workflow = [createdAt(), updatedAt(), ...]; + +module.exports = { before: { + update: [...workflow], + patch: [...workflow], +} }; +``` diff --git a/src/hooks/combine/combine.test.ts b/src/hooks/combine/combine.test.ts new file mode 100755 index 00000000..b83e38e5 --- /dev/null +++ b/src/hooks/combine/combine.test.ts @@ -0,0 +1,152 @@ +/* eslint-disable @typescript-eslint/no-this-alias */ +import { assert } from 'vitest' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { combine } from './combine.js' +import { clone } from '../../common/index.js' + +const startId = 6 +const storeInit = { + 0: { name: 'Jane Doe', key: 'a', id: 0 }, + 1: { name: 'Jack Doe', key: 'a', id: 1 }, + 2: { name: 'Jack Doe', key: 'a', id: 2, deleted: true }, + 3: { name: 'Rick Doe', key: 'b', id: 3 }, + 4: { name: 'Dick Doe', key: 'b', id: 4 }, + 5: { name: 'Dick Doe', key: 'b', id: 5, deleted: true }, +} +let store + +function services(app: any) { + app.configure(user) +} + +function user(app: any) { + let service: any + let hookId: any + let hookData: any + let hookParamsQuery: any + store = clone(storeInit) + + app.use( + '/users', + new MemoryService({ + store, + startId, + }), + ) + + app.service('users').hooks({ + before: { + all: [ + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 0.') + } + service = this + + hook.data = { a: 'a' } + + hookId = hook.id + hookData = clone(hook.data) + hookParamsQuery = clone(hook.params.query) + + return hook + }, + combine( + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 1.') + } + if (service !== this) { + throw new Error('Service wrong 1.') + } + hook.params.trace = ['sync1'] + return hook + }, + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 2.') + } + if (service !== this) { + throw new Error('Service wrong 2.') + } + + if (hook.params.query.key === 'b') { + throw new Error('Requested throw.') + } + + hook.params.trace.push('promise1') + return Promise.resolve(hook) + }, + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 3.') + } + if (service !== this) { + throw new Error('Service wrong 3.') + } + hook.params.trace.push('sync2') + }, + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 4.') + } + if (service !== this) { + throw new Error('Service wrong 4.') + } + hook.params.trace.push('cb1') + + return hook + }, + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 5.') + } + if (service !== this) { + throw new Error('Service wrong 5.') + } + hook.params.trace.push('sync3') + return hook + }, + ), + function (this: any, hook: any) { + if (hook.app !== app) { + throw new Error('App wrong 9.') + } + if (service !== this) { + throw new Error('Service wrong 9.') + } + + assert.equal(hook.id, hookId) + assert.deepEqual(hook.data, hookData) + assert.deepEqual(hook.params.query, hookParamsQuery) + + assert.deepEqual(hook.params.trace, ['sync1', 'promise1', 'sync2', 'cb1', 'sync3']) + }, + ], + }, + }) +} + +describe('util combine', () => { + let app + let user: any + + beforeEach(() => { + app = feathers().configure(services) + user = app.service('users') + }) + + it('runs successful hooks', async () => { + await user.find({ query: { key: 'a' } }) + }) + + it('throws on unsuccessful hook', async () => { + await user + .find({ query: { key: 'b' } }) + .then((_data: any) => { + assert.fail(true, false) + }) + .catch(() => {}) + }) +}) diff --git a/src/utils/combine.ts b/src/hooks/combine/combine.ts similarity index 59% rename from src/utils/combine.ts rename to src/hooks/combine/combine.ts index e1e44eca..51a0e036 100755 --- a/src/utils/combine.ts +++ b/src/hooks/combine/combine.ts @@ -1,8 +1,8 @@ -import type { HookContext } from '@feathersjs/feathers'; -import type { HookFunction } from '../types'; +import type { HookContext } from '@feathersjs/feathers' +import type { HookFunction } from '../../types.js' /** - * Sequentially execute multiple sync or async hooks. + * Sequentially execute multiple hooks. * @see https://hooks-common.feathersjs.com/utilities.html#combine */ export function combine(...serviceHooks: HookFunction[]) { @@ -11,11 +11,11 @@ export function combine(...serviceHooks: Ho // } const isContext = function (ctx: H) { - return typeof ctx?.method === 'string' && typeof ctx?.type === 'string'; - }; + return typeof ctx?.method === 'string' && typeof ctx?.type === 'string' + } return async function (context: H) { - let ctx = context; + let ctx = context const updateCurrentHook = (current: void | H) => { // Either use the returned hook object or the current @@ -24,37 +24,36 @@ export function combine(...serviceHooks: Ho if (!isContext(current)) { throw new Error( `${ctx.type} hook for '${ctx.method}' method returned invalid hook object`, - ); + ) } - ctx = current; + ctx = current } - return ctx; - }; + return ctx + } // Go through all hooks and chain them into our promise - // @ts-ignore + + // @ts-expect-error TODO const promise = serviceHooks.reduce(async (current, fn) => { - // @ts-ignore - const hook = fn.bind(this); + // @ts-expect-error TODO + const hook = fn.bind(this) // Use the returned hook object or the old one - // eslint-disable-next-line @typescript-eslint/await-thenable - const currentHook = await current; - const currentCtx = await hook(currentHook); - // @ts-ignore - return updateCurrentHook(currentCtx); - }, Promise.resolve(ctx)); + + const currentHook = await current + const currentCtx = await hook(currentHook) + return updateCurrentHook(currentCtx) + }, Promise.resolve(ctx)) try { - // eslint-disable-next-line @typescript-eslint/await-thenable - await promise; - return ctx; + await promise + return ctx } catch (error: any) { // Add the hook information to any errors - error.hook = ctx; - throw error; + error.hook = ctx + throw error } - }; + } } diff --git a/src/hooks/create-related/create-related.md b/src/hooks/create-related/create-related.md new file mode 100644 index 00000000..137a5666 --- /dev/null +++ b/src/hooks/create-related/create-related.md @@ -0,0 +1,9 @@ +--- +title: createRelated +description: Create related records in other services. +category: hooks +hook: + type: ['before', 'around'] + method: ['create'] + multi: true +--- diff --git a/src/hooks/create-related/create-related.test.ts b/src/hooks/create-related/create-related.test.ts new file mode 100644 index 00000000..94641c34 --- /dev/null +++ b/src/hooks/create-related/create-related.test.ts @@ -0,0 +1,247 @@ +import assert from 'node:assert' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { createRelated } from './create-related.js' + +type MockAppOptions = { + multi?: boolean +} + +const defaultOptions = { + multi: true, +} + +const mockApp = (_options?: MockAppOptions) => { + const options = Object.assign({}, defaultOptions, _options) + const app = feathers() + + app.use('users', new MemoryService({ startId: 1, multi: true })) + app.use('todos', new MemoryService({ startId: 1, multi: options.multi })) + + const usersService = app.service('users') + const todosService = app.service('todos') + + return { + app, + todosService, + usersService, + } +} + +describe('hook - createRelated', function () { + it('creates single item for single item', async function () { + const { app, todosService } = mockApp() + + app.service('users').hooks({ + after: { + create: [ + createRelated({ + service: 'todos', + data: (item, context) => ({ + title: 'First issue', + userId: item.id, + }), + }), + ], + }, + }) + + const user = await app.service('users').create({ + name: 'John Doe', + }) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [{ id: 1, title: 'First issue', userId: 1 }]) + }) + + it('can use context in data function', async function () { + const { app, todosService } = mockApp() + + app.service('users').hooks({ + after: { + create: [ + createRelated({ + service: 'todos', + data: (item, context) => ({ + title: context.path, + userId: item.id, + }), + }), + ], + }, + }) + + const user = await app.service('users').create({ + name: 'John Doe', + }) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [{ id: 1, title: 'users', userId: 1 }]) + }) + + it('creates multiple items for multiple items', async function () { + const { app, todosService } = mockApp() + + app.service('users').hooks({ + after: { + create: [ + createRelated({ + service: 'todos', + data: (item, context) => ({ + title: item.name, + userId: item.id, + }), + }), + ], + }, + }) + + const users = await app + .service('users') + .create([{ name: 'user1' }, { name: 'user2' }, { name: 'user3' }]) + + const todos = await todosService.find({ query: { $sort: { userId: 1 } } }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'user1', userId: 1 }, + { id: 2, title: 'user2', userId: 2 }, + { id: 3, title: 'user3', userId: 3 }, + ]) + }) + + it('creates multple items for multiple items with multi: false', async function () { + const { app, todosService } = mockApp({ multi: false }) + + app.service('users').hooks({ + after: { + create: [ + createRelated({ + service: 'todos', + data: (item, context) => ({ + title: item.name, + userId: item.id, + }), + multi: false, + }), + ], + }, + }) + + // @ts-expect-error - does not have options + assert.strictEqual(todosService.options.multi, false) + + const users = await app + .service('users') + .create([{ name: 'user1' }, { name: 'user2' }, { name: 'user3' }]) + + const todos = await todosService.find({ query: { $sort: { userId: 1 } } }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'user1', userId: 1 }, + { id: 2, title: 'user2', userId: 2 }, + { id: 3, title: 'user3', userId: 3 }, + ]) + }) + + it('can create multiple data for one record', async function () { + const { app, todosService } = mockApp() + + app.service('users').hooks({ + after: { + create: [ + createRelated({ + service: 'todos', + data: (item, context) => [ + { + title: 1, + userId: item.id, + }, + { + title: 2, + userId: item.id, + }, + ], + }), + ], + }, + }) + + const user = await app.service('users').create({ + name: 'John Doe', + }) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 1, userId: 1 }, + { id: 2, title: 2, userId: 1 }, + ]) + }) + + it('can pass an array', async function () { + const { app, todosService } = mockApp() + + app.service('users').hooks({ + after: { + create: [ + createRelated([ + { + service: 'todos', + data: (item, context) => [ + { + title: 1, + userId: item.id, + }, + ], + }, + { + service: 'todos', + data: (item, context) => [ + { + title: 2, + userId: item.id, + }, + ], + }, + ]), + ], + }, + }) + + const user = await app.service('users').create({ + name: 'John Doe', + }) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 1, userId: 1 }, + { id: 2, title: 2, userId: 1 }, + ]) + }) + + it('does not create items if falsey', async function () { + const { app, todosService } = mockApp() + + app.service('users').hooks({ + after: { + create: [ + createRelated({ + service: 'todos', + data: (item, context) => null as any, + }), + ], + }, + }) + + const user = await app.service('users').create({ + name: 'John Doe', + }) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, []) + }) +}) diff --git a/src/hooks/create-related/create-related.ts b/src/hooks/create-related/create-related.ts new file mode 100644 index 00000000..6598780e --- /dev/null +++ b/src/hooks/create-related/create-related.ts @@ -0,0 +1,54 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { checkContext, getResultIsArray } from '../../utils/index.js' +import type { MaybeArray, Promisable } from '../../internal.utils.js' + +export interface CreateRelatedOptions> { + service: keyof S + multi?: boolean + data: (item: any, context: HookContext) => Promisable> +} + +/** + * hook to create related items + */ +export function createRelated, H extends HookContext = HookContext>( + options: MaybeArray>, +) { + return async (context: H, next?: NextFunction) => { + checkContext(context, ['after', 'around'], ['create'], 'createRelated') + + if (next) { + await next() + } + + const { result } = getResultIsArray(context) + + const entries = Array.isArray(options) ? options : [options] + + await Promise.all( + entries.map(async entry => { + const { data, service, multi } = entry + + const dataToCreate = ( + await Promise.all(result.map(async item => data(item, context))) + ).filter(x => !!x) + + if (!dataToCreate || dataToCreate.length <= 0) { + return context + } + + if (multi || dataToCreate.length === 1) { + await context.app + .service(service as string) + .create(dataToCreate.length === 1 ? dataToCreate[0] : dataToCreate) + } else { + await Promise.all( + dataToCreate.map(async item => context.app.service(service as string).create(item)), + ) + } + }), + ) + + return context + } +} diff --git a/src/hooks/de-populate.ts b/src/hooks/de-populate.ts deleted file mode 100755 index 2a57d308..00000000 --- a/src/hooks/de-populate.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import _omit from 'lodash/omit.js'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; - -/** - * Remove records and properties created by the populate hook. - * @see https://hooks-common.feathersjs.com/hooks.html#depopulate - */ -export function dePopulate(func?: (item: any) => void) { - return (context: H) => { - const items = getItems(context); - const converter = (item: any) => { - if (typeof func === 'function') { - func(item); - } - - const keys = ['_elapsed', '_computed', '_include']; - const { _computed = [], _include = [] } = item; - - return _omit(item, keys.concat(_computed).concat(_include)); - }; - const converted = Array.isArray(items) ? items.map(converter) : converter(items); - - replaceItems(context, converted); - - return context; - }; -} diff --git a/src/hooks/debug/debug.md b/src/hooks/debug/debug.md new file mode 100644 index 00000000..fbd53d2d --- /dev/null +++ b/src/hooks/debug/debug.md @@ -0,0 +1,49 @@ +--- +title: debug +description: Display the current hook context for debugging. +category: hooks +hook: + type: ['before', 'after'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{String} label` +- `{Array < String >} [ fieldNames ]` + +| Argument | Type | Default | Description | +| ------------ | :----------: | ------- | ------------------------------------------------ | +| `label` | `String` | | Label to identify the logged information. | +| `fieldNames` | dot notation | | The field values in `context.params` to display. | + +## Example + +```js +const { debug } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { + all: [ debug('step 1'), setNow('updatedAt'), debug(' step 2') ], +} }; + +// Result +* step 1 +type: before, method: create +data: { name: 'Joe Doe' } +query: { sex: 'm' } +result: { assigned: true } +params props: [ 'query' ] +* step 2 +type: before, method: create +data: { name: 'Joe Doe', createdAt: 1510518511547 } +query: { sex: 'm' } +result: { assigned: true } +params props: [ 'query' ] +params.query: { sex: 'm' } +error: ... +``` + +## Details + +`debug` is great for debugging issues with hooks. Log the hook context before and after a hook to see what the hook started with, and what it changed. diff --git a/test/hooks/debug.test.ts b/src/hooks/debug/debug.test.ts similarity index 75% rename from test/hooks/debug.test.ts rename to src/hooks/debug/debug.test.ts index d4ec03f1..7b1ca49f 100755 --- a/test/hooks/debug.test.ts +++ b/src/hooks/debug/debug.test.ts @@ -1,4 +1,4 @@ -import { debug } from '../../src'; +import { debug } from './debug.js' describe('services debug', () => { it('does not crash', () => { @@ -8,9 +8,9 @@ describe('services debug', () => { data: { a: 'a' }, params: { query: { b: 'b' } }, result: { c: 'c' }, - }; - debug('my message')(hook); - }); + } + debug('my message')(hook) + }) it('display params props', () => { const hook: any = { @@ -19,7 +19,7 @@ describe('services debug', () => { data: { a: 'a' }, params: { query: { b: 'b' }, foo: 'bar' }, result: { c: 'c' }, - }; - debug('my message', 'query', 'foo')(hook); - }); -}); + } + debug('my message', 'query', 'foo')(hook) + }) +}) diff --git a/src/hooks/debug.ts b/src/hooks/debug/debug.ts similarity index 52% rename from src/hooks/debug.ts rename to src/hooks/debug/debug.ts index 6d54e0d9..5e9a79fe 100755 --- a/src/hooks/debug.ts +++ b/src/hooks/debug/debug.ts @@ -1,55 +1,57 @@ -/* eslint-disable no-console */ -import type { HookContext } from '@feathersjs/feathers'; +import type { HookContext, NextFunction } from '@feathersjs/feathers' /** * Display the current hook context for debugging. * @see https://hooks-common.feathersjs.com/hooks.html#debug */ -export function debug(msg: string, ...fieldNames: string[]) { - return (context: H) => { +export const debug = + (msg: string, ...fieldNames: string[]) => + async (context: H, next?: NextFunction) => { + if (next) { + await next() + } + // display timestamp - const now = new Date(); + const now = new Date() console.log( `${now.getFullYear()}-${ now.getMonth() + 1 }-${now.getDate()} ${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`, - ); + ) if (msg) { - console.log(msg); + console.log(msg) } // display service, method & type of hook (before/after/error) - console.log(`${context.type} service('${context.path}').${context.method}()`); + console.log(`${context.type} service('${context.path}').${context.method}()`) // display id for get, patch, update & remove if (!['find', 'create'].includes(context.method) && 'id' in context) { - console.log('id:', context.id); + console.log('id:', context.id) } if (context.data) { - console.log('data:', context.data); + console.log('data:', context.data) } if (context.params?.query) { - console.log('query:', context.params.query); + console.log('query:', context.params.query) } if (context.result) { - console.log('result:', context.result); + console.log('result:', context.result) } // display additional params - const params = context.params || {}; - console.log('params props:', Object.keys(params).sort()); + const params = context.params || {} + console.log('params props:', Object.keys(params).sort()) fieldNames.forEach(name => { - // @ts-ignore - console.log(`params.${name}:`, params[name]); - }); + console.log(`params.${name}:`, params[name]) + }) if (context.error) { - console.log('error', context.error); + console.log('error', context.error) } - }; -} + } diff --git a/src/hooks/disable-pagination.ts b/src/hooks/disable-pagination.ts deleted file mode 100755 index 83d5d23c..00000000 --- a/src/hooks/disable-pagination.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { checkContext } from '../utils/check-context'; - -/** - * Disables pagination when query.$limit is -1 or '-1'. - * @see https://hooks-common.feathersjs.com/hooks.html#disablepagination - */ -export function disablePagination() { - return (context: H) => { - checkContext(context, 'before', ['find'], 'disablePagination'); - const $limit = (context.params.query || {}).$limit; - - if ($limit === '-1' || $limit === -1) { - // @ts-ignore - context.params.paginate = false; - delete context.params.query.$limit; - } - - return context; - }; -} diff --git a/src/hooks/disable-pagination/disable-pagination.md b/src/hooks/disable-pagination/disable-pagination.md new file mode 100644 index 00000000..c7653a54 --- /dev/null +++ b/src/hooks/disable-pagination/disable-pagination.md @@ -0,0 +1,21 @@ +--- +title: disablePagination +description: Disable pagination when query.$limit is -1 or '-1'. +category: hooks +hook: + type: ['before'] + method: ['find'] + multi: true +--- + +## Example + +```js +const { disablePagination } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { find: disablePagination() } }; +``` + +## Details + +Pagination is disabled if `context.query.$limit` is -1 or '-1'. It works for all types of calls including REST. diff --git a/test/hooks/disable-pagination.test.ts b/src/hooks/disable-pagination/disable-pagination.test.ts similarity index 50% rename from test/hooks/disable-pagination.test.ts rename to src/hooks/disable-pagination/disable-pagination.test.ts index 9ff8fe9c..d8ba22ae 100755 --- a/test/hooks/disable-pagination.test.ts +++ b/src/hooks/disable-pagination/disable-pagination.test.ts @@ -1,7 +1,7 @@ -import { assert } from 'vitest'; -import { disablePagination } from '../../src'; +import { assert } from 'vitest' +import { disablePagination } from './disable-pagination.js' -let hookBefore: any; +let hookBefore: any describe('services disablePagination', () => { beforeEach(() => { @@ -9,36 +9,36 @@ describe('services disablePagination', () => { type: 'before', method: 'find', params: { query: { id: 1, $limit: -1 } }, - }; - }); + } + }) it('disables on $limit = -1', () => { - hookBefore.params.query.$limit = -1; + hookBefore.params.query.$limit = -1 - const result: any = disablePagination()(hookBefore); - assert.deepEqual(result.params, { paginate: false, query: { id: 1 } }); - }); + const result: any = disablePagination()(hookBefore) + assert.deepEqual(result.params, { paginate: false, query: { id: 1 } }) + }) it('disables on $limit = "-1"', () => { - hookBefore.params.query.$limit = '-1'; + hookBefore.params.query.$limit = '-1' - const result: any = disablePagination()(hookBefore); - assert.deepEqual(result.params, { paginate: false, query: { id: 1 } }); - }); + const result: any = disablePagination()(hookBefore) + assert.deepEqual(result.params, { paginate: false, query: { id: 1 } }) + }) it('throws if after hook', () => { - hookBefore.type = 'after'; + hookBefore.type = 'after' assert.throws(() => { - disablePagination()(hookBefore); - }); - }); + disablePagination()(hookBefore) + }) + }) it('throws if not find', () => { - hookBefore.method = 'get'; + hookBefore.method = 'get' assert.throws(() => { - disablePagination()(hookBefore); - }); - }); -}); + disablePagination()(hookBefore) + }) + }) +}) diff --git a/src/hooks/disable-pagination/disable-pagination.ts b/src/hooks/disable-pagination/disable-pagination.ts new file mode 100755 index 00000000..2b6ac88a --- /dev/null +++ b/src/hooks/disable-pagination/disable-pagination.ts @@ -0,0 +1,22 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { checkContext } from '../../utils/index.js' + +/** + * Disables pagination when query.$limit is -1 or '-1'. + * @see https://hooks-common.feathersjs.com/hooks.html#disablepagination + */ +export const disablePagination = + () => + (context: H, next?: NextFunction) => { + checkContext(context, 'before', ['find'], 'disablePagination') + const $limit = context.params?.query?.$limit + + if ($limit === '-1' || $limit === -1) { + context.params.paginate = false + delete context.params.query.$limit + } + + if (next) return next().then(() => context) + + return context + } diff --git a/src/hooks/disallow.ts b/src/hooks/disallow.ts deleted file mode 100755 index c46d6e2e..00000000 --- a/src/hooks/disallow.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MethodNotAllowed } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import type { TransportName } from '../types'; - -/** - * Prevents access to a service method completely or for specific transports. - * @see https://hooks-common.feathersjs.com/hooks.html#disallow - */ -export function disallow(...transports: TransportName[]) { - return (context: H) => { - const hookProvider = context.params?.provider; - - const anyProvider = transports.length === 0; - const thisProvider = transports.some( - provider => - provider === hookProvider || - (provider === 'server' && !hookProvider) || - (provider === 'external' && !!hookProvider), - ); - - if (anyProvider || thisProvider) { - throw new MethodNotAllowed( - `Provider '${context.params.provider}' can not call '${context.method}'. (disallow)`, - ); - } - }; -} diff --git a/src/hooks/disallow/disallow.md b/src/hooks/disallow/disallow.md new file mode 100644 index 00000000..b0bcc6ad --- /dev/null +++ b/src/hooks/disallow/disallow.md @@ -0,0 +1,48 @@ +--- +title: disallow +description: Prevents access to a service method completely or for specific transports. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['all'] + multi: true + methods: ['all'] +--- + +## Arguments + +- `{Array< String >} transports` + +| Argument | Type | Default | Description | +| ------------ | :---------------: | ----------------------- | ----------------------------------------- | +| `transports` | `Array< String >` | disallow all transports | The transports that you want to disallow. | + +| `transports` | Value | Description | +| ------------ | ------------------------------------- | ----------- | +| `socketio` | disallow calls by Socket.IO transport | +| `rest` | disallow calls by REST transport | +| `external` | disallow calls other than from server | +| `server` | disallow calls from server | + +## Example + +```js +const { disallow, iff } = require('feathers-hooks-common/index.js'); + +module.exports = { + before: { + // Users can not be created by external access + create: disallow('external'), + // A user can not be deleted through the REST provider + remove: disallow('rest'), + // disallow calling `update` completely (e.g. to allow only `patch`) + update: disallow(), + // disallow the remove hook if the user is not an admin + remove: iff(context => !context.params.user.isAdmin, disallow()), + }, +}; +``` + +## Details + +Prevents access to a service method completely or just for specific transports. All transports set the `context.params.provider` property, and `disallow` checks this. diff --git a/src/hooks/disallow/disallow.test.ts b/src/hooks/disallow/disallow.test.ts new file mode 100755 index 00000000..7a226ed2 --- /dev/null +++ b/src/hooks/disallow/disallow.test.ts @@ -0,0 +1,151 @@ +import { assert } from 'vitest' +import { disallow } from './disallow.js' + +describe('services disallow', () => { + describe('disallow is compatible with .disable (without predicate)', () => { + let hookRest: any + let hookSocketio: any + let hookServer: any + + beforeEach(() => { + hookRest = { method: 'create', params: { provider: 'rest' } } + hookSocketio = { method: 'create', params: { provider: 'socketio' } } + hookServer = { method: 'create', params: { provider: '' } } + }) + + it('disables all providers with no param', () => { + assert.throws(() => { + disallow()(hookSocketio) + }) + assert.throws(() => { + disallow()(hookServer) + }) + }) + + it('disables a provider', () => { + assert.throws(() => { + disallow('socketio')(hookSocketio) + }) + }) + + it('does not disable the server', () => { + disallow('socketio')(hookServer) + assert.throws(() => { + disallow('socketio')(hookSocketio) + }) + }) + + it('does not disable another provider', () => { + disallow('socketio')(hookRest) + assert.throws(() => { + disallow('socketio')(hookSocketio) + }) + }) + + it('disables multiple providers', () => { + disallow(['socketio', 'rest'])(hookServer) + assert.throws(() => { + disallow(['socketio', 'rest'])(hookSocketio) + }) + assert.throws(() => { + disallow(['socketio', 'rest'])(hookRest) + }) + }) + + it('"external" disables all external providers', () => { + disallow(['socketio', 'rest'])(hookServer) + assert.throws(() => { + disallow(['socketio', 'rest'])(hookSocketio) + }) + assert.throws(() => { + disallow(['socketio', 'rest'])(hookRest) + }) + }) + }) + + describe('disallow functionality is like isProvider', () => { + let hookServer: any + let hookSocketio: any + let hook: any + + beforeEach(() => { + hookServer = { type: 'before', method: 'create', params: { provider: '' } } + hookSocketio = { type: 'before', method: 'create', params: { provider: 'socketio' } } + }) + + it('returns a function', () => { + const fcn = disallow('server') + + assert.isFunction(fcn) + }) + + it('throws on no args', () => { + assert.throws(() => disallow()(hook)) + }) + + it('finds provider with 1 arg', () => { + const hook = structuredClone(hookSocketio) + + const result = disallow('rest')(hook) + assert.equal(result, undefined) + + assert.throws(() => { + disallow('socketio')(hook) + }) + }) + + it('finds provider with 2 args', () => { + const hook = structuredClone(hookSocketio) + + const result = disallow(['rest', 'server'])(hook) + assert.equal(result, undefined) + + assert.throws(() => { + disallow(['rest', 'socketio'])(hook) + }) + }) + + it('finds server', () => { + const hook = structuredClone(hookServer) + + const result = disallow(['rest', 'socketio', 'external'])(hook) + assert.equal(result, undefined) + + assert.throws(() => { + disallow(['rest', 'socketio', 'server'])(hook) + }) + }) + + it('finds external', () => { + const hook = structuredClone(hookSocketio) + + const result = disallow(['rest', 'server'])(hook) + assert.equal(result, undefined) + + assert.throws(() => { + disallow(['rest', 'server', 'external'])(hook) + }) + }) + + it('succeeds if not provider', () => { + const hook = structuredClone(hookServer) + + const result = disallow('socketio')(hook) + assert.equal(result, undefined) + }) + + it('succeeds if not external', () => { + const hook = structuredClone(hookServer) + + const result = disallow('external')(hook) + assert.equal(result, undefined) + }) + + it('succeeds if not server', () => { + const hook = structuredClone(hookSocketio) + + const result = disallow('server')(hook) + assert.equal(result, undefined) + }) + }) +}) diff --git a/src/hooks/disallow/disallow.ts b/src/hooks/disallow/disallow.ts new file mode 100755 index 00000000..bc353a1e --- /dev/null +++ b/src/hooks/disallow/disallow.ts @@ -0,0 +1,29 @@ +import { MethodNotAllowed } from '@feathersjs/errors' +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { TransportName } from '../../types.js' +import { isProvider } from '../../predicates/index.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Prevents access to a service method completely or for specific transports. + * @see https://hooks-common.feathersjs.com/hooks.html#disallow + */ +export const disallow = ( + transports?: MaybeArray, +) => { + const transportsArr = toArray(transports) + return (context: H, next?: NextFunction) => { + if (!transports) { + throw new MethodNotAllowed('Method not allowed') + } + + if (isProvider(...(transportsArr as TransportName[]))(context)) { + throw new MethodNotAllowed( + `Provider '${context.params.provider}' can not call '${context.method}'. (disallow)`, + ) + } + + if (next) return next().then(() => context) + } +} diff --git a/src/hooks/discard-query.ts b/src/hooks/discard-query.ts deleted file mode 100755 index e298680d..00000000 --- a/src/hooks/discard-query.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import _omit from 'lodash/omit.js'; -import { checkContext } from '../utils/check-context'; - -/** - * Delete certain fields from the query object. - * @see https://hooks-common.feathersjs.com/hooks.html#discardquery - */ -export function discardQuery(...fieldNames: string[]) { - return (context: H) => { - checkContext(context, 'before', null, 'discardQuery'); - - const query = context.params.query || {}; - - context.params.query = _omit(query, fieldNames); - - return context; - }; -} diff --git a/src/hooks/discard.ts b/src/hooks/discard.ts deleted file mode 100755 index 5ad1c888..00000000 --- a/src/hooks/discard.ts +++ /dev/null @@ -1,23 +0,0 @@ -import _omit from 'lodash/omit.js'; -import { checkContextIf } from '../utils/check-context-if'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Delete certain fields from the record(s). - * @see https://hooks-common.feathersjs.com/hooks.html#discard - */ -export function discard(...fieldNames: string[]) { - return (context: H) => { - checkContextIf(context, 'before', ['create', 'update', 'patch'], 'discard'); - - const items = getItems(context); - const convert = (item: any) => _omit(item, fieldNames); - const converted = Array.isArray(items) ? items.map(convert) : convert(items); - - replaceItems(context, converted); - - return context; - }; -} diff --git a/src/hooks/fast-join.ts b/src/hooks/fast-join.ts deleted file mode 100755 index 3dd46c50..00000000 --- a/src/hooks/fast-join.ts +++ /dev/null @@ -1,128 +0,0 @@ -import type { Application, HookContext, Query, Service } from '@feathersjs/feathers'; -import type { SyncContextFunction } from '../types'; - -export interface ResolverContext - extends HookContext { - _loaders: any; -} - -export type SimpleResolver = ( - ...args: any[] -) => (item: any, context: H) => Promise; - -export interface RecursiveResolver { - resolver: SimpleResolver; - joins: ResolverMap; -} - -export interface ResolverMap { - after?: (context: H) => void | Promise; - before?: (context: H) => void | Promise; - joins: { - [property: string]: SimpleResolver | RecursiveResolver; - }; -} - -/** - * We often want to combine rows from two or more tables based on a relationship between them. The fastJoin hook - * will select records that have matching values in both tables. It can batch service calls and cache records, - * thereby needing roughly an order of magnitude fewer database calls than the populate hook, i.e. 2 calls instead - * of 20. It uses a GraphQL-like imperative API. - * - * fastJoin is not restricted to using data from Feathers services. Resources for which there are no Feathers - * adapters can also be used. - * - * - * fastJoin(postResolvers) - * fastJoin(postResolvers, query) - * fastJoin(context => postResolvers) - * fastJoin(postResolvers, context => query) // supports queries from client - * @see https://hooks-common.feathersjs.com/hooks.html#fastjoin - */ -export function fastJoin( - resolvers: ResolverMap | SyncContextFunction, H>, - query?: Query | SyncContextFunction, -) { - return (context: H) => { - const { method, data, result, params } = context; - - // @ts-ignore - if (params._populate || params._graphql) return context; // our service called within another populate - - const q = typeof query === 'function' ? query(context) : query; - const joins2 = typeof resolvers === 'function' ? resolvers(context) : resolvers; - const { before, joins, after } = joins2; - - const temp = result || (Array.isArray(data) ? data : [data]); - const results = method === 'find' ? result.data || temp : temp; - - const prevLoaders = context._loaders; - context._loaders = {}; - - return ( - Promise.resolve() - // @ts-ignore - .then(() => before && before(context)) - .then( - () => joins && results && recursive(joinsForQuery(joins2, q, context), results, context), - ) - // @ts-ignore - .then(() => after && after(context)) - .then(() => { - context._loaders = prevLoaders; - return context; - }) - ); - }; -} - -function joinsForQuery({ joins }: any = {}, query: any = undefined, context = {}) { - const runtime: any = []; - - Object.keys(joins).forEach(outerLabel => { - if (query && !query[outerLabel]) return; - - let join = joins[outerLabel]; - if (typeof join === 'function') { - join = { resolver: join }; - } - - const { resolver } = join; - let { joins: innerJoins } = join; - if (innerJoins && !innerJoins.resolver && innerJoins.joins) { - // support embedded resolvers for other services - innerJoins = innerJoins.joins; - } - - let args: any = query ? query[outerLabel] : []; - if (!Array.isArray(args)) { - args = typeof args === 'object' && args !== null ? args.args : []; - } - - runtime.push({ - args, - resolver, - joins: innerJoins - ? joinsForQuery({ joins: innerJoins }, query ? query[outerLabel] : null, context) - : null, - }); - }); - - return runtime; -} - -function recursive(joins: any, results: any, context: any) { - return Promise.all( - (Array.isArray(results) ? results : [results]).map(result => - Promise.all( - joins.map(({ args = [], resolver, joins }: any) => { - return Promise.resolve(resolver(...args)(result, context)).then(addedResults => { - if (!addedResults || !joins) return context; - - return recursive(joins, addedResults, context); - }); - }), - ), - ), - ); -} diff --git a/src/hooks/fgraphql.ts b/src/hooks/fgraphql.ts deleted file mode 100755 index c68d8135..00000000 --- a/src/hooks/fgraphql.ts +++ /dev/null @@ -1,461 +0,0 @@ -import type { Application, HookContext, Query } from '@feathersjs/feathers'; -import makeDebug from 'debug'; -import type { parse, GraphQLFieldResolver } from 'graphql'; -import type { SyncContextFunction } from '../types'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; - -export type FGraphQLResolverMapFactory = (app: Application, runtime: any) => FGraphQLResolverMap; - -export interface FGraphQLResolverMap { - [i: string]: { - [i: string]: GraphQLFieldResolver; - }; - Query: { - [i: string]: GraphQLFieldResolver; - }; -} - -export interface FGraphQLOptions { - skipHookWhen?: SyncContextFunction; - inclAllFieldsServer?: boolean; - inclAllFieldsClient?: boolean; - inclAllFields?: boolean; - inclJoinedNames?: boolean; - extraAuthProps?: string[]; -} - -export interface FGraphQLHookOptions { - recordType: string; - schema: string; - resolvers: FGraphQLResolverMap | FGraphQLResolverMapFactory; - query: Query | SyncContextFunction; - options?: FGraphQLOptions; - runTime: any; - parse: typeof parse; -} - -const debug = makeDebug('fgraphql'); -const graphqlActions = ['Query', 'Mutation', 'Subscription']; - -/** - * Generate Graphql Resolvers for services - * @see https://medium.com/@eddyystop/38faee75dd1 - */ -export function fgraphql(options1: FGraphQLHookOptions) { - debug('init call'); - const { parse, recordType, resolvers, runTime, query } = options1; - let { schema } = options1; - - let ourResolvers: any; // will be initialized when hook is first called - - const options = { - skipHookWhen: (context: any) => !!(context.params || {}).graphql, - inclAllFieldsServer: true, - inclAllFieldsClient: true, - inclAllFields: null, // Will be initialized each hook call. - inclJoinedNames: true, - extraAuthProps: [], - ...(options1.options || {}), - }; - - // @ts-ignore - schema = isFunction(schema) ? schema() : schema; - - if (!isObject(schema) && !isString(schema)) { - throwError( - `Resolved schema is typeof ${typeof schema} rather than string or object. (fgraphql)`, - 101, - ); - } - - if (!isObject(runTime)) { - throwError(`option runTime is typeof ${typeof runTime} rather than an object. (fgraphql)`, 106); - } - - if (!isString(recordType)) { - throwError(`recordType is typeof ${typeof recordType} rather than string. (fgraphql)`, 103); - } - - // @ts-ignore - if (!isArray(options.extraAuthProps)) { - // @ts-ignore - throwError( - `option extraAuthProps is typeof ${typeof options.extraAuthProps} rather than array. (fgraphql)`, - 105, - ); - } - - const feathersSdl = isObject(schema) ? schema : convertSdlToFeathersSchemaObject(schema, parse); - debug('schema now in internal form'); - - // Return the hook. - return (context: H) => { - const contextParams = context.params; - // @ts-ignore - const optSkipHookWhen = options.skipHookWhen; - const skipHookWhen = isFunction(optSkipHookWhen) ? optSkipHookWhen(context) : optSkipHookWhen; - debug( - `\n.....hook called. type ${context.type} method ${context.method} resolved skipHookWhen ${skipHookWhen}`, - ); - - if (context.params.$populate) return context; // populate or fastJoin are running - if (skipHookWhen) return context; - - // @ts-ignore - const q = isFunction(query) ? query(context) : query; - - if (!isObject(q)) { - throwError(`Resolved query is typeof ${typeof q} rather than object. (fgraphql)`, 102); - } - - if (!ourResolvers) { - // @ts-ignore - ourResolvers = resolvers(context.app, runTime); - debug(`ourResolvers has Types ${Object.keys(ourResolvers)}`); - } - - if (!ourResolvers[recordType]) { - throwError(`recordType ${recordType} not found in resolvers. (fgraphql)`, 104); - } - - // @ts-ignore - options.inclAllFields = contextParams.provider - ? // @ts-ignore - options.inclAllFieldsClient - : // @ts-ignore - options.inclAllFieldsServer; - // @ts-ignore - debug(`inclAllField ${options.inclAllFields}`); - - // Build content parameter passed to resolver functions. - const resolverContent: Record = { - app: context.app, - provider: contextParams.provider, - user: contextParams.user, - authenticated: contextParams.authenticated, - batchLoaders: {}, - cache: {}, - }; - - // @ts-ignore - (options.extraAuthProps || []).forEach((name: any) => { - if (name in contextParams && !(name in resolverContent)) { - resolverContent[name] = contextParams[name]; - } - }); - - // Static values used by fgraphql functions. - const store = { - feathersSdl, - ourResolvers, - options, - resolverContent, - }; - - // Populate data. - const recs = getItems(context); - - // @ts-ignore - return processRecords(store, q, recs, recordType).then(() => { - replaceItems(context, recs); - return context; - }); - }; -} - -// Process records recursively. -function processRecords(store: any, query: any, recs: any, type: any, depth = 0): any { - if (!recs) return; // Catch no data to populate. - - recs = isArray(recs) ? recs : [recs]; - debug(`\nvvvvvvvvvv enter ${depth}`); - debug(`processRecords depth ${depth} #recs ${recs.length} Type ${type}`); - - const storeOurResolversType = store.ourResolvers[type]; - if (!isObject(storeOurResolversType)) { - throwError( - `Resolvers for Type ${type} are typeof ${typeof storeOurResolversType} not object. (fgraphql)`, - 201, - ); - } - - if (!isObject(query)) { - throwError(`query at Type ${type} are typeof ${typeof query} not object. (fgraphql)`, 202); - } - - return Promise.all( - recs.map((rec: any, j: any) => processRecord(store, query, depth, rec, type, j)), - ).then(() => { - debug(`^^^^^^^^^^ exit ${depth}\n`); - }); -} - -// Process the a record. -function processRecord(store: any, query: any, depth: any, rec: any, type: any, j: any): any { - debug(`processRecord rec# ${j} typeof ${typeof rec} Type ${type}`); - if (!rec) return; // Catch any null values from resolvers. - - const queryPropNames = Object.keys(query); - const recFieldNamesInQuery: any = []; - const joinedNamesInQuery: any = []; - - // Process every query item. - return Promise.all( - queryPropNames.map((fieldName, i) => - processRecordQuery( - store, - query, - depth, - rec, - fieldName, - type, - recFieldNamesInQuery, - joinedNamesInQuery, - j, - i, - ), - ), - ).then(() => { - // Retain only record fields selected - debug(`field names found ${recFieldNamesInQuery} joined names ${joinedNamesInQuery}`); - if ( - recFieldNamesInQuery.length || - !store.options.inclAllFields || - queryPropNames.includes('_none') - ) { - // recs[0] may have been created by [rec] so can't replace array elem - Object.keys(rec).forEach(key => { - if (!recFieldNamesInQuery.includes(key) && !joinedNamesInQuery.includes(key)) { - delete rec[key]; - } - }); - } - - // Include joined names in record. - if (store.options.inclJoinedNames && joinedNamesInQuery.length) { - rec._include = joinedNamesInQuery; - } - }); -} - -// Process one query field for a record. -function processRecordQuery( - store: any, - query: any, - depth: any, - rec: any, - fieldName: any, - type: any, - recFieldNamesInQuery: any, - joinedNamesInQuery: any, - j: any, - i: any, -): any { - debug(`\nprocessRecordQuery rec# ${j} Type ${type} field# ${i} name ${fieldName}`); - - // One way to include/exclude rec fields is to give their names a falsey value. - // _args and _none are not record field names but special purpose - if (query[fieldName] && fieldName !== '_args' && fieldName !== '_none') { - if (store.ourResolvers[type][fieldName]) { - joinedNamesInQuery.push(fieldName); - return processRecordFieldResolver(store, query, depth, rec, fieldName, type); - } else { - debug('is not resolver call'); - recFieldNamesInQuery.push(fieldName); - } - } -} - -// Process a resolver call. -function processRecordFieldResolver( - store: any, - query: any, - depth: any, - rec: any, - fieldName: any, - type: any, -) { - debug('is resolver call'); - const ourQuery = store.feathersSdl[type][fieldName]; - const ourResolver = store.ourResolvers[type][fieldName]; - - if (!isFunction(ourResolver)) { - throwError( - `Resolver for Type ${type} fieldName ${fieldName} is typeof ${typeof ourResolver} not function. (fgraphql)`, - 203, - ); - } - - const args = isObject(query[fieldName]) ? query[fieldName]._args : undefined; - debug(`resolver listType ${ourQuery.listType} args ${JSON.stringify(args)}`); - - // Call resolver function. - return Promise.resolve(ourResolver(rec, args || {}, store.resolverContent)).then( - async rawResult => { - debug( - `resolver returned typeof ${ - isArray(rawResult) ? `array #recs ${rawResult.length}` : typeof rawResult - }`, - ); - - // Convert rawResult to query requirements. - const result = convertResolverResult(rawResult, ourQuery, fieldName, type); - if (isArray(rawResult !== isArray(result) || typeof rawResult !== typeof result)) { - debug( - `.....resolver result converted to typeof ${ - isArray(result) ? `array #recs ${result.length}` : typeof result - }`, - ); - } - rec[fieldName] = result; - - const nextType = ourQuery.typeof; - debug(`Type ${type} fieldName ${fieldName} next Type ${nextType}`); - - // Populate returned records if their query defn has more fields or Types. - // Ignore resolvers returning base values like string. - if (store.ourResolvers[nextType] && isObject(query[fieldName])) { - return processRecords(store, query[fieldName], result, nextType, depth + 1); - } else { - debug('no population of results required'); - } - }, - ); -} - -// Convert result of resolver function to match query field requirements. -function convertResolverResult(result: any, ourQuery: any, fieldName: any, type: any) { - if (result === null || result === undefined) { - return ourQuery.listType ? [] : null; - } - - if (ourQuery.listType) { - if (!isArray(result)) return [result]; - } else if (isArray(result)) { - if (result.length > 1) { - throwError( - `Query listType true. Resolver for Type ${type} fieldName ${fieldName} result is array len ${result.length} (fgraphql)`, - 204, - ); - } - - return result[0]; - } - - return result; -} - -function convertSdlToFeathersSchemaObject(schemaDefinitionLanguage: any, parse: any) { - const graphQLSchemaObj = parse(schemaDefinitionLanguage); - return convertDocument(graphQLSchemaObj); -} - -function convertDocument(ast: any) { - const result: Record = {}; - - if (ast.kind !== 'Document' || !isArray(ast.definitions)) { - throw new Error('Not a valid GraphQL Document.'); - } - - ast.definitions.forEach((definition: any, definitionIndex: any) => { - const [objectName, converted] = convertObjectTypeDefinition(definition, definitionIndex); - - if (objectName) { - result[objectName] = converted; - } - }); - - return result; -} - -function convertObjectTypeDefinition(definition: any, definitionIndex: any) { - const converted: Record = {}; - - if (definition.kind !== 'ObjectTypeDefinition' || !isArray(definition.fields)) { - throw new Error(`Type# ${definitionIndex} is not a valid ObjectTypeDefinition`); - } - - const objectTypeName = convertName(definition.name, `Type# ${definitionIndex}`); - if (graphqlActions.includes(objectTypeName)) return [null, null]; - - definition.fields.forEach((field: any) => { - const [fieldName, fieldDefinition] = convertFieldDefinition(field, `Type ${objectTypeName}`); - converted[fieldName] = fieldDefinition; - }); - - return [objectTypeName, converted]; -} - -function convertName(nameObj: any, errDesc?: any) { - if (!isObject(nameObj) || !isString(nameObj.value)) { - throw new Error(`${errDesc} does not have a valid name prop.`); - } - - return nameObj.value; -} - -function convertFieldDefinition(field: any, errDesc: any) { - if (field.kind !== 'FieldDefinition' || !isObject(field.type)) { - throw new Error(`${errDesc} is not a valid ObjectTypeDefinition`); - } - - const fieldName = convertName(field.name, errDesc); - const converted = convertFieldDefinitionType(field.type, errDesc); - converted.inputValues = field.arguments && field.arguments.length !== 0; - - return [fieldName, converted]; -} - -function convertFieldDefinitionType(fieldDefinitionType: any, errDesc: any, converted?: any): any { - converted = converted || { - nonNullTypeList: false, - listType: false, - nonNullTypeField: false, - typeof: null, - }; - - if (!isObject(fieldDefinitionType)) { - throw new Error(`${errDesc} is not a valid Fielddefinition "type".`); - } - - switch (fieldDefinitionType.kind) { - case 'NamedType': - converted.typeof = convertName(fieldDefinitionType.name); - return converted; - case 'NonNullType': - if (fieldDefinitionType.type.kind === 'NamedType') { - converted.nonNullTypeField = true; - } else { - converted.nonNullTypeList = true; - } - - return convertFieldDefinitionType(fieldDefinitionType.type, errDesc, converted); - case 'ListType': - converted.listType = true; - return convertFieldDefinitionType(fieldDefinitionType.type, errDesc, converted); - } -} - -function throwError(msg: any, code: any) { - const err = new Error(msg); - // @ts-ignore - err.code = code; - throw err; -} - -function isObject(obj: any) { - return typeof obj === 'object' && obj !== null; -} - -function isString(str: any) { - return typeof str === 'string'; -} - -function isFunction(func: any) { - return typeof func === 'function'; -} - -function isArray(array: any) { - return Array.isArray(array); -} diff --git a/src/hooks/iff-else/iff-else.md b/src/hooks/iff-else/iff-else.md new file mode 100644 index 00000000..2148061a --- /dev/null +++ b/src/hooks/iff-else/iff-else.md @@ -0,0 +1,40 @@ +--- +title: iffElse +description: Execute one array of hooks or another based on a sync or async predicate. +category: hooks +hook: + type: ['before', 'after'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{Function} predicate` +- `{Array< Functions >} hookFuncsTrue` +- `{Array< Functions >} hookFuncsFalse` + +| Argument | Type | Default | Description | +| ---------------- | :--------------------------------: | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `predicate` | `Boolean`, `Promise` or `Function` | | Determine if `hookFuncsTrue` or `hookFuncsFalse` should be run. If a function, `predicate` is called with the `context` as its param. It returns either a boolean or a Promise that evaluates to a boolean. | +| `hookFuncsTrue` | `Array<` `Function >` | | Sync or async hook functions to run if `true`. They may include other conditional hooks. | +| `hookFuncsFalse` | `Array<` `Function >` | | Sync or async hook functions to run if `false`. They may include other conditional hooks. | + +## Example + +```js +const { iffElse, populate, serialize } = require('feathers-hooks-common/index.js'); + +module.exports = { after: { + create: iffElse(() => { ... }, + [populate(poAccting), serialize( ... )], + [populate(poReceiving), serialize( ... )] + ) +} }; +``` + +## Details + +Resolve the predicate, then run one set of hooks sequentially. + +The predicate and hook functions will not be called with `this` set to the service, as is normal for hook functions. Use `hook.service` instead. diff --git a/src/hooks/iff-else/iff-else.test.ts b/src/hooks/iff-else/iff-else.test.ts new file mode 100755 index 00000000..74d49c12 --- /dev/null +++ b/src/hooks/iff-else/iff-else.test.ts @@ -0,0 +1,206 @@ +/* eslint-disable @typescript-eslint/no-this-alias */ +import type { HookContext } from '@feathersjs/feathers' +import { assert } from 'vitest' +import { iffElse } from './iff-else.js' +import { some } from '../../predicates/some/some.js' +import { every } from '../../predicates/every/every.js' +import { clone } from '../../common/index.js' + +let hook: any +let hookBefore: any +let hookAfter: any +let hookFcnSyncCalls: any +let hookFcnAsyncCalls: any +let hookFcnCalls: any +let predicateParam1: any +let predicateParam2: any +let predicateParam3: any +let predicateParam4: any +let context: any +let predicateTrueContext: any +let hookFcnSyncContext: any +let hookFcnAsyncContext: any +let hookFcnContext: any + +const hookFcnSync = function (this: any, hook: any) { + hookFcnSyncContext = this + + hookFcnSyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + return hook +} + +const hookFcnAsync = function (this: any, hook: any) { + hookFcnAsyncContext = this + + return new Promise(resolve => { + hookFcnAsyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + resolve(hook) + }) +} + +const hookFcn = function (this: any, hook: any, _cb: any) { + hookFcnContext = this + + hookFcnCalls = +1 + + return hook +} + +const predicateTrue = function (this: any, hook: any, more2: any, more3: any, more4: any): true { + predicateTrueContext = this + + predicateParam1 = hook + predicateParam2 = more2 + predicateParam3 = more3 + predicateParam4 = more4 + + return true +} + +describe('services iffElse', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + describe('runs single hook', () => { + it('when true', () => { + return iffElse( + true, + hookFcnSync, + hookFcnAsync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.equal(hookFcnAsyncCalls, 0) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('when false', () => { + return iffElse( + false, + hookFcnSync, + hookFcnAsync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 0) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + }) + + describe('runs multiple hooks', () => { + it('when true', () => { + return iffElse( + true, + // @ts-expect-error TODO + [hookFcnSync, hookFcnAsync, hookFcn], + null, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.equal(hookFcnAsyncCalls, 1) + assert.equal(hookFcnCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('when false', () => { + return ( + // @ts-expect-error TODO + iffElse(false, null, [hookFcnSync, hookFcnAsync, hookFcn])(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.equal(hookFcnAsyncCalls, 1) + assert.equal(hookFcnCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + ) + }) + }) + + describe('predicate gets right params', () => { + it('when true', () => { + return iffElse( + // @ts-expect-error TODO + predicateTrue, + [hookFcnSync, hookFcnAsync, hookFcn], + null, + )(hook).then(() => { + assert.deepEqual(predicateParam1, hook, 'param1') + assert.strictEqual(predicateParam2, undefined, 'param2') + assert.strictEqual(predicateParam3, undefined, 'param3') + assert.strictEqual(predicateParam4, undefined, 'param4') + }) + }) + + it('every passes on correct params', () => { + return iffElse( + // @ts-expect-error TODO + every(predicateTrue), + // @ts-expect-error TODO + [hookFcnSync, hookFcnAsync, hookFcn], + null, + )(hook).then(() => { + assert.deepEqual(predicateParam1, hook, 'param1') + assert.strictEqual(predicateParam2, undefined, 'param2') + assert.strictEqual(predicateParam3, undefined, 'param3') + assert.strictEqual(predicateParam4, undefined, 'param4') + }) + }) + + it('some passes on correct params', () => { + return iffElse( + // @ts-expect-error TODO + some(predicateTrue), + // @ts-expect-error TODO + [hookFcnSync, hookFcnAsync, hookFcn], + null, + )(hook).then(() => { + assert.deepEqual(predicateParam1, hook, 'param1') + assert.strictEqual(predicateParam2, undefined, 'param2') + assert.strictEqual(predicateParam3, undefined, 'param3') + assert.strictEqual(predicateParam4, undefined, 'param4') + }) + }) + }) + + describe('predicate and hooks get right context', () => { + beforeEach(() => { + context = { service: 'abc' } + predicateTrueContext = undefined + hookFcnSyncContext = undefined + hookFcnAsyncContext = undefined + hookFcnContext = undefined + }) + + it('services', () => { + return ( + // @ts-expect-error TODO + iffElse(predicateTrue, [hookFcnSync, hookFcnAsync, hookFcn], null) + .call(context, hook) + .then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.equal(hookFcnAsyncCalls, 1) + assert.equal(hookFcnCalls, 1) + assert.deepEqual(hook, hookAfter) + + assert.deepEqual(predicateTrueContext, { service: 'abc' }) + assert.deepEqual(hookFcnSyncContext, { service: 'abc' }) + assert.deepEqual(hookFcnAsyncContext, { service: 'abc' }) + assert.deepEqual(hookFcnContext, { service: 'abc' }) + }) + ) + }) + }) +}) diff --git a/src/hooks/iff-else.ts b/src/hooks/iff-else/iff-else.ts similarity index 64% rename from src/hooks/iff-else.ts rename to src/hooks/iff-else/iff-else.ts index 7e35fe07..a9ee48ec 100755 --- a/src/hooks/iff-else.ts +++ b/src/hooks/iff-else/iff-else.ts @@ -1,7 +1,7 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { isPromise } from '../common'; -import { combine } from '../utils/combine'; -import type { HookFunction, PredicateFn } from '../types'; +import type { HookContext } from '@feathersjs/feathers' +import { isPromise } from '../../common/index.js' +import { combine } from '../combine/combine.js' +import type { HookFunction, PredicateFn } from '../../types.js' /** * Execute one array of hooks or another based on a sync or async predicate. @@ -18,30 +18,31 @@ export function iffElse( ? trueHook : typeof trueHook === 'function' ? [trueHook] - : undefined; + : undefined const falseHooks = Array.isArray(falseHook) ? falseHook : typeof falseHook === 'function' ? [falseHook] - : undefined; + : undefined - const that = this; - const check = typeof predicate === 'function' ? predicate.apply(that, [ctx]) : !!predicate; + // eslint-disable-next-line @typescript-eslint/no-this-alias + const that = this + const check = typeof predicate === 'function' ? predicate.apply(that, [ctx]) : !!predicate if (!check) { - return callHooks.call(that, ctx, falseHooks as any); + return callHooks.call(that, ctx, falseHooks as any) } if (!isPromise(check)) { - return callHooks.call(that, ctx, trueHooks as any); + return callHooks.call(that, ctx, trueHooks as any) } return check.then((check1: any) => { - const hooks = check1 ? trueHooks : falseHooks; - return callHooks.call(that, ctx, hooks as any); - }); - }; + const hooks = check1 ? trueHooks : falseHooks + return callHooks.call(that, ctx, hooks as any) + }) + } } function callHooks( @@ -49,5 +50,5 @@ function callHooks( ctx: H, serviceHooks: HookFunction[], ) { - return serviceHooks ? combine(...serviceHooks).call(this, ctx) : ctx; + return serviceHooks ? combine(...serviceHooks).call(this, ctx) : ctx } diff --git a/src/hooks/iff/iff.md b/src/hooks/iff/iff.md new file mode 100644 index 00000000..7292f89e --- /dev/null +++ b/src/hooks/iff/iff.md @@ -0,0 +1,54 @@ +--- +title: iff +description: Execute one or another series of hooks depending on a sync or async predicate. +category: hooks +hook: + type: ['before', 'after'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{Boolean | Promise | Function} predicate` +- `{Array< Function >} hookFuncsTrue` +- `{Array< Function >} hookFuncsFalse` + +| Argument | Type | Default | Description | +| ---------------- | :--------------------------------: | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `predicate` | `Boolean`, `Promise` or `Function` | | Determine if `hookFuncsTrue` or `hookFuncsFalse` should be run. If a function, `predicate` is called with the `context` as its param. It returns either a boolean or a Promise that evaluates to a boolean. | +| `hookFuncsTrue` | `Array<` `Function >` | | Sync or async hook functions to run if `true`. They may include other conditional hooks. | +| `hookFuncsFalse` | `Array<` `Function >` | | Sync or async hook functions to run if `false`. They may include other conditional hooks. | + +## Example + +```js +const { discard, iff, isProvider, populate } = require('feathers-hooks-common/index.js'); +const isNotAdmin = adminRole => context => context.params.user.roles.indexOf(adminRole || 'admin') === -1; + +module.exports = { before: { + create: iff( + () => new Promise((resolve, reject) => { ... }), + populate('user', { field: 'authorisedByUserId', service: 'users' }) + ), + + get: [ iff(isNotAdmin(), discard('budget')) ] + + update: + iff(isProvider('server'), + hookA, + iff(isProvider('rest'), hook1, hook2, hook3) + .else(hook4, hook5), + hookB + ) + .else( + iff(hook => hook.path === 'users', hook6, hook7) + ) +} }; +``` + +## Details + +Resolve the predicate, then run one set of hooks sequentially. + +The predicate and hook functions will not be called with `this` set to the service, as is normal for hook functions. Use `hook.service` instead. diff --git a/src/hooks/iff/iff.test.ts b/src/hooks/iff/iff.test.ts new file mode 100755 index 00000000..93db8320 --- /dev/null +++ b/src/hooks/iff/iff.test.ts @@ -0,0 +1,401 @@ +import type { HookContext } from '@feathersjs/feathers' +import { assert } from 'vitest' +import { iff } from './iff.js' +import { clone, isPromise } from '../../common/index.js' + +let hook: any +let hookBefore: any +let hookAfter: any +let hookFcnSyncCalls: any +let hookFcnAsyncCalls: any +let hookFcnCbCalls: any +let predicateHook: any +let predicateOptions: any +let predicateValue: any + +const predicateSync = (hook: any) => { + predicateHook = clone(hook) + return true +} + +const predicateSync2 = (options: any) => (hook: any) => { + predicateOptions = clone(options) + predicateHook = clone(hook) + return true +} + +const predicateAsync = (hook: any) => { + predicateHook = clone(hook) + return new Promise(resolve => resolve(true)) +} + +const predicateAsync2 = (options: any) => (hook: any) => { + predicateOptions = clone(options) + predicateHook = clone(hook) + return new Promise(resolve => resolve(true)) +} + +const predicateAsyncFunny = (hook: any) => { + predicateHook = clone(hook) + return new Promise(resolve => { + predicateValue = 'abc' + return resolve(predicateValue) + }) +} + +const hookFcnSync = (hook: HookContext): HookContext => { + hookFcnSyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + return hook +} + +const hookFcnAsync = (hook: HookContext) => + new Promise(resolve => { + hookFcnAsyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + resolve(hook) + }) + +const hookFcn = (hook: HookContext): HookContext => { + hookFcnCbCalls = +1 + + return hook +} + +describe('services iff - sync predicate, sync hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls sync hook function if truthy non-function', () => { + iff( + // @ts-expect-error TODO + 'a', + hookFcnSync, + )(hook) + // @ts-expect-error TODO + .then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call sync hook function if falsey non-function', () => { + // @ts-expect-error TODO + const result = iff('', hookFcnSync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } else { + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + } + }) + + it('calls sync hook function if sync predicate truthy', () => { + iff( + // @ts-expect-error TODO + () => 'a', + hookFcnSync, + )(hook) + // @ts-expect-error TODO + .then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call sync hook function if sync predicate falsey', () => { + // @ts-expect-error TODO + const result = iff(() => '', hookFcnSync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } else { + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + } + }) +}) + +describe('services iff - sync predicate, async hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls async hook function if sync predicate truthy', async () => { + const result = iff(true, hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call async hook function if sync predicate falsey', () => { + const result = iff(false, hookFcnAsync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } + + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnAsyncCalls, 0) + assert.deepEqual(hook, hookBefore) + }) + + it('calls async hook function if sync predicate returns truthy', async () => { + const result = iff(() => true, hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) +}) + +describe('services iff - async predicate, sync hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls sync hook function if aync predicate truthy', async () => { + const result = iff(() => new Promise(resolve => resolve(true)), hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) + + it('does not call sync hook function if async predicate falsey', async () => { + const result = iff(() => new Promise(resolve => resolve(false)), hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + }) + }) +}) + +describe('services iff - async predicate, async hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls async hook function if aync predicate truthy', async () => { + const result = iff(() => new Promise(resolve => resolve(true)), hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) + + it('does not call async hook function if async predicate falsey', async () => { + const result = iff(() => new Promise(resolve => resolve(false)), hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookBefore) + assert.equal(hookFcnAsyncCalls, 0) + assert.deepEqual(hook, hookBefore) + }) + }) +}) + +describe('services iff - sync predicate', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + predicateHook = null + predicateOptions = null + }) + + it('does not need to access hook', () => { + iff( + // @ts-expect-error TODO + () => 'a', + hookFcnSync, + )(hook) + // @ts-expect-error TODO + .then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('is passed hook as param', () => { + iff( + predicateSync, + hookFcnSync, + )(hook) + // @ts-expect-error TODO + .then((hook: any) => { + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('a higher order predicate can pass more options', () => { + iff( + predicateSync2({ z: 'z' }), + hookFcnSync, + )(hook) + // @ts-expect-error TODO + .then((hook: any) => { + assert.deepEqual(predicateOptions, { z: 'z' }) + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) +}) + +describe('services iff - async predicate', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + predicateHook = null + predicateOptions = null + predicateValue = null + }) + + it('is passed hook as param', async () => { + // @ts-expect-error TODO + const result = iff(predicateAsync, hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) + + it('is resolved', async () => { + // @ts-expect-error TODO + const result = iff(predicateAsyncFunny, hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + + assert.equal(predicateValue, 'abc') + }) + }) + + it('a higher order predicate can pass more options', async () => { + // @ts-expect-error TODO + const result = iff(predicateAsync2({ y: 'y' }), hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(predicateOptions, { y: 'y' }) + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) +}) + +describe('services iff - runs multiple hooks', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('runs successfully', async () => { + await iff( + true, + hookFcnSync, + hookFcnAsync, + hookFcn, + )(hook) + // @ts-expect-error TODO + .then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.equal(hookFcnAsyncCalls, 1) + assert.equal(hookFcnCbCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) +}) diff --git a/src/hooks/iff.ts b/src/hooks/iff/iff.ts similarity index 62% rename from src/hooks/iff.ts rename to src/hooks/iff/iff.ts index 8012d633..2bdba9fc 100755 --- a/src/hooks/iff.ts +++ b/src/hooks/iff/iff.ts @@ -1,9 +1,9 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { iffElse } from './iff-else'; -import type { HookFunction, PredicateFn } from '../types'; +import type { HookContext } from '@feathersjs/feathers' +import { iffElse } from '../iff-else/iff-else.js' +import type { HookFunction, PredicateFn } from '../../types.js' export interface IffHook extends HookFunction { - else(...hooks: HookFunction[]): HookFunction; + else(...hooks: HookFunction[]): HookFunction } /** @@ -15,20 +15,19 @@ export function iff( ...hooks: HookFunction[] ): IffHook { if (hooks.length && Array.isArray(hooks[0])) { - hooks = hooks[0]; + hooks = hooks[0] } const iffWithoutElse = function (context: H) { - return iffElse(predicate, hooks.slice())(context); - }; + return iffElse(predicate, hooks.slice())(context) + } iffWithoutElse.else = (...falseHooks: any[]) => (context: H) => - // @ts-ignore - iffElse(predicate, hooks.slice(), falseHooks.slice())(context); + iffElse(predicate, hooks.slice(), falseHooks.slice())(context) - return iffWithoutElse as IffHook; + return iffWithoutElse as IffHook } -export { iff as when }; +export { iff as when } diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 00000000..8235ba06 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,36 @@ +export * from './cache/cache.js' +export * from './check-required/check-required.js' +export * from './combine/combine.js' +export * from './create-related/create-related.js' +export * from './debug/debug.js' +export * from './disable-pagination/disable-pagination.js' +export * from './disallow/disallow.js' +export * from './iff-else/iff-else.js' +export * from './iff/iff.js' +export * from './lowercase-data/lowercase-data.js' +export * from './lowercase-result/lowercase-result.js' +export * from './omit-data/omit-data.js' +export * from './omit-query/omit-query.js' +export * from './omit-result/omit-result.js' +export * from './params-for-server/params-for-server.js' +export * from './params-from-client/params-from-client.js' +export * from './pick-data/pick-data.js' +export * from './pick-query/pick-query.js' +export * from './pick-result/pick-result.js' +export * from './prevent-changes/prevent-changes.js' +export * from './run-parallel/run-parallel.js' +export * from './set-field/set-field.js' +export * from './set-now-data/set-now-data.js' +export * from './set-now-result/set-now-result.js' +export * from './set-slug/set-slug.js' +export * from './soft-delete/soft-delete.js' +export * from './stash-before/stash-before.js' +export * from './throw-if-is-multi/throw-if-is-multi.js' +export * from './throw-if-is-provider/throw-if-is-provider.js' +export * from './throw-if/throw-if.js' +export * from './trim-data/trim-data.js' +export * from './trim-result/trim-result.js' +export * from './transform-data/transform-data.js' +export * from './transform-result/transform-result.js' +export * from './traverse/traverse.js' +export * from './unless/unless.js' diff --git a/src/hooks/keep-in-array.ts b/src/hooks/keep-in-array.ts deleted file mode 100755 index 51833bba..00000000 --- a/src/hooks/keep-in-array.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; -import _get from 'lodash/get.js'; -import _set from 'lodash/set.js'; -import _has from 'lodash/has.js'; -import { getItems } from '../utils/get-items'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Keep certain fields in a nested array inside the record(s), deleting the rest. - * @see https://hooks-common.feathersjs.com/hooks.html#keepinarray - */ -export function keepInArray( - arrayName: string, - fieldNames: string[], -) { - return (context: H) => { - const items = getItems(context); - - if (Array.isArray(items)) { - items.forEach(item => replaceIn(item, arrayName, fieldNames)); - } else { - replaceIn(items, arrayName, fieldNames); - } - - return context; - }; -} - -function replaceIn(item: any, field: any, fieldNames: any) { - const target = _get(item, field); - if (target) { - if (!Array.isArray(target)) - throw new BadRequest( - `The 'field' param must lead to array. found type '${typeof target}' instead`, - ); - - _set( - item, - field, - target.map(item => replaceItem(item, fieldNames)), - ); - } -} - -function replaceItem(item: any, fields: any) { - if (typeof item !== 'object' || item === null) return item; - - const newItem = {}; - fields.forEach((field: any) => { - if (!_has(item, field)) return; - - const value = _get(item, field); - _set(newItem, field, value); - }); - item = newItem; - return item; -} diff --git a/src/hooks/keep-query-in-array.ts b/src/hooks/keep-query-in-array.ts deleted file mode 100644 index 7b32ab5d..00000000 --- a/src/hooks/keep-query-in-array.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { checkContext } from '../utils/check-context'; -import { BadRequest } from '@feathersjs/errors'; -import _get from 'lodash/get.js'; -import _set from 'lodash/set.js'; -import _has from 'lodash/has.js'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Keep certain fields in a nested array inside the query object, deleting the rest. - * @see https://hooks-common.feathersjs.com/hooks.html#keepqueryinarray - */ -export function keepQueryInArray( - arrayName: string, - fieldNames: string[], -) { - return (context: H) => { - checkContext(context, 'before', null, 'keepQueryInArray'); - - replaceIn(context.query, arrayName, fieldNames); - - return context; - }; -} - -function replaceIn(item: any, field: any, fieldNames: any) { - const target = _get(item, field); - if (target) { - if (!Array.isArray(target)) - throw new BadRequest( - `The 'field' param must lead to array. found type '${typeof target}' instead`, - ); - - _set( - item, - field, - target.map(item => replaceItem(item, fieldNames)), - ); - } -} - -function replaceItem(item: any, fields: any) { - if (typeof item !== 'object' || item === null) return item; - - const newItem = {}; - fields.forEach((field: any) => { - if (!_has(item, field)) return; - - const value = _get(item, field); - _set(newItem, field, value); - }); - item = newItem; - return item; -} diff --git a/src/hooks/keep-query.ts b/src/hooks/keep-query.ts deleted file mode 100755 index aac6d2e0..00000000 --- a/src/hooks/keep-query.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { pluck } from '../common'; -import { checkContext } from '../utils/check-context'; - -/** - * Keep certain fields in the query object, deleting the rest. - * @see https://hooks-common.feathersjs.com/hooks.html#keepquery - */ -export function keepQuery(...fieldNames: string[]) { - return (context: H) => { - checkContext(context, 'before', null, 'keepQuery'); - - const query = context.params.query || {}; - context.params.query = pluck(query, fieldNames); - - return context; - }; -} diff --git a/src/hooks/keep.ts b/src/hooks/keep.ts deleted file mode 100755 index 48df0eef..00000000 --- a/src/hooks/keep.ts +++ /dev/null @@ -1,44 +0,0 @@ -import _get from 'lodash/get.js'; -import _set from 'lodash/set.js'; -import _has from 'lodash/has.js'; - -import { checkContextIf } from '../utils/check-context-if'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Keep certain fields in the record(s), deleting the rest. - * @see https://hooks-common.feathersjs.com/hooks.html#keep - */ -export function keep(...fieldNames: string[]) { - return (context: H) => { - checkContextIf(context, 'before', ['create', 'update', 'patch'], 'keep'); - const items = getItems(context); - - if (Array.isArray(items)) { - replaceItems( - context, - items.map(item => replaceItem(item, fieldNames)), - ); - } else { - replaceItems(context, replaceItem(items, fieldNames)); - } - - return context; - }; -} - -function replaceItem(item: any, fields: any) { - if (typeof item !== 'object' || item === null) return item; - - const newItem = {}; - fields.forEach((field: any) => { - if (!_has(item, field)) return; - - const value = _get(item, field); - _set(newItem, field, value); - }); - item = newItem; - return item; -} diff --git a/src/hooks/lower-case.ts b/src/hooks/lower-case.ts deleted file mode 100755 index f71cb1ae..00000000 --- a/src/hooks/lower-case.ts +++ /dev/null @@ -1,29 +0,0 @@ -import _set from 'lodash/set.js'; -import { BadRequest } from '@feathersjs/errors'; - -import { transformItems } from '../common'; -import { checkContextIf } from '../utils/check-context-if'; -import { getItems } from '../utils/get-items'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Convert certain field values to lower case. - * @see https://hooks-common.feathersjs.com/hooks.html#lowercase - */ -export function lowerCase(...fieldNames: string[]) { - return (context: H) => { - checkContextIf(context, 'before', ['create', 'update', 'patch'], 'lowercase'); - - transformItems(getItems(context), fieldNames, (item: any, fieldName: any, value: any) => { - if (value !== undefined) { - if (typeof value !== 'string' && value !== null) { - throw new BadRequest(`Expected string data. (lowercase ${fieldName})`); - } - - _set(item, fieldName, value ? value.toLowerCase() : value); - } - }); - - return context; - }; -} diff --git a/src/hooks/lowercase-data/lowercase-data.md b/src/hooks/lowercase-data/lowercase-data.md new file mode 100644 index 00000000..d849b1ba --- /dev/null +++ b/src/hooks/lowercase-data/lowercase-data.md @@ -0,0 +1,28 @@ +--- +title: lowercaseData +description: Convert certain field values to lower case. +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | --------------------------------------------------------------------- | +| fieldNames | dot notation | The fields in the record(s) whose values are converted to lower case. | + +## Example + +```js +const { lowerCase } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { create: lowerCase('email', 'username', 'div.dept') } }; +``` + +## Details + +Update either `context.data` (before hook) or `context.result[.data]` (after hook). diff --git a/src/hooks/lowercase-data/lowercase-data.test.ts b/src/hooks/lowercase-data/lowercase-data.test.ts new file mode 100755 index 00000000..eef82fa3 --- /dev/null +++ b/src/hooks/lowercase-data/lowercase-data.test.ts @@ -0,0 +1,96 @@ +import { assert } from 'vitest' +import { lowercaseData } from './lowercase-data.js' + +let hookBefore: any + +describe('lowercaseData', () => { + describe('updates data', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + }) + + it('updates hook before::create', () => { + lowercaseData(['first', 'last'])(hookBefore) + assert.deepEqual(hookBefore.data, { first: 'john', last: 'doe' }) + }) + + it('does not throw if field is missing', () => { + const hook: any = { type: 'before', method: 'create', data: { last: 'Doe' } } + lowercaseData(['first', 'last'])(hook) + assert.deepEqual(hook.data, { last: 'doe' }) + }) + + it('does not throw if field is undefined', () => { + const hook: any = { + type: 'before', + method: 'create', + data: { first: undefined, last: 'Doe' }, + } + lowercaseData(['first', 'last'])(hook) + assert.deepEqual(hook.data, { first: undefined, last: 'doe' }) + }) + + it('does not throw if field is null', () => { + const hook: any = { type: 'before', method: 'create', data: { first: null, last: 'Doe' } } + lowercaseData(['first', 'last'])(hook) + assert.deepEqual(hook.data, { first: null, last: 'doe' }) + }) + + it('throws if field is not a string', async () => { + const hook: any = { type: 'before', method: 'create', data: { first: 1, last: 'Doe' } } + await expect(async () => { + await lowercaseData(['first', 'last'])(hook) + }).rejects.toThrow('Expected string data. (lowercase first)') + }) + }) + + describe('handles dot notation', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + } + }) + + it('prop with no dots', () => { + lowercaseData('dept')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'acct', + }) + }) + + it('prop with 1 dot', () => { + lowercaseData('empl.status')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'aa' }, + dept: 'Acct', + }) + }) + + it('prop with 2 dots', () => { + lowercaseData('empl.name.first')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'john', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + + it('ignores bad or missing paths', () => { + lowercaseData('empl.xx.first')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + + it('ignores bad or missing no dot path', () => { + lowercaseData('xx')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + }) +}) diff --git a/src/hooks/lowercase-data/lowercase-data.ts b/src/hooks/lowercase-data/lowercase-data.ts new file mode 100755 index 00000000..af05d1db --- /dev/null +++ b/src/hooks/lowercase-data/lowercase-data.ts @@ -0,0 +1,31 @@ +import _get from 'lodash/get.js' +import _set from 'lodash/set.js' +import { BadRequest } from '@feathersjs/errors' +import { transformData } from '../transform-data/transform-data.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Convert certain field values to lower case. + * @see https://hooks-common.feathersjs.com/hooks.html#lowercase + */ +export const lowercaseData = (fieldNames: MaybeArray) => { + const fieldNamesArr = toArray(fieldNames) + + return transformData(item => { + for (let i = 0; i < fieldNamesArr.length; i++) { + const fieldName = fieldNamesArr[i] + const value = _get(item, fieldName) + + if (value == null) { + continue + } + + if (typeof value !== 'string') { + throw new BadRequest(`Expected string data. (lowercase ${fieldName})`) + } + + _set(item, fieldName, value.toLowerCase()) + } + }) +} diff --git a/src/hooks/lowercase-result/lowercase-result.md b/src/hooks/lowercase-result/lowercase-result.md new file mode 100644 index 00000000..bc30197f --- /dev/null +++ b/src/hooks/lowercase-result/lowercase-result.md @@ -0,0 +1,28 @@ +--- +title: lowercaseResult +description: Convert certain field values to lower case. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | --------------------------------------------------------------------- | +| fieldNames | dot notation | The fields in the record(s) whose values are converted to lower case. | + +## Example + +```js +const { lowerCase } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { create: lowerCase('email', 'username', 'div.dept') } }; +``` + +## Details + +Update either `context.data` (before hook) or `context.result[.data]` (after hook). diff --git a/src/hooks/lowercase-result/lowercase-result.test.ts b/src/hooks/lowercase-result/lowercase-result.test.ts new file mode 100755 index 00000000..7f7361ca --- /dev/null +++ b/src/hooks/lowercase-result/lowercase-result.test.ts @@ -0,0 +1,52 @@ +import { assert } from 'vitest' +import { lowercaseResult } from './lowercase-result.js' +import type { HookContext } from '@feathersjs/feathers' + +describe('lowercaseResult', () => { + it('updates hook after::find with pagination', () => { + const context = { + type: 'after', + method: 'find', + result: { + total: 2, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + } as HookContext + + lowercaseResult(['first', 'last'])(context) + assert.deepEqual(context.result.data, [ + { first: 'john', last: 'doe' }, + { first: 'jane', last: 'doe' }, + ]) + }) + + it('updates hook after::find with no pagination', () => { + const context = { + type: 'after', + method: 'find', + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } as HookContext + lowercaseResult(['first', 'last'])(context) + assert.deepEqual(context.result, [ + { first: 'john', last: 'doe' }, + { first: 'jane', last: 'doe' }, + ]) + }) + + it('updates hook after', () => { + const context = { + type: 'after', + method: 'create', + result: { first: 'Jane', last: 'Doe' }, + } as HookContext + lowercaseResult(['first', 'last'])(context) + + assert.deepEqual(context.result, { first: 'jane', last: 'doe' }) + }) +}) diff --git a/src/hooks/lowercase-result/lowercase-result.ts b/src/hooks/lowercase-result/lowercase-result.ts new file mode 100755 index 00000000..de7950ce --- /dev/null +++ b/src/hooks/lowercase-result/lowercase-result.ts @@ -0,0 +1,42 @@ +import _get from 'lodash/get.js' +import _set from 'lodash/set.js' +import { BadRequest } from '@feathersjs/errors' +import { transformResult } from '../transform-result/transform-result.js' +import type { DispatchOption } from '../../types.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +export type LowercaseResultOptions = { + dispatch?: DispatchOption +} + +/** + * Convert certain field values to lower case. + * @see https://hooks-common.feathersjs.com/hooks.html#lowercase + */ +export const lowercaseResult = ( + fieldNames: MaybeArray, + options?: LowercaseResultOptions, +) => { + const fieldNamesArray = toArray(fieldNames) + + return transformResult( + (item: any) => { + for (let i = 0; i < fieldNamesArray.length; i++) { + const fieldName = fieldNamesArray[i] + const value = _get(item, fieldName) + + if (value == null) { + continue + } + + if (typeof value !== 'string') { + throw new BadRequest(`Expected string data. (lowercase ${fieldName})`) + } + + _set(item, fieldName, value.toLowerCase()) + } + }, + { dispatch: options?.dispatch }, + ) +} diff --git a/src/hooks/mongo-keys.ts b/src/hooks/mongo-keys.ts deleted file mode 100755 index 07f7c71c..00000000 --- a/src/hooks/mongo-keys.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import traverse from 'neotraverse/legacy'; -import { checkContext } from '../utils/check-context'; - -/** - * Wrap MongoDB foreign keys in ObjectId. - * - * @see https://hooks-common.feathersjs.com/hooks.html#mongokeys - */ -export function mongoKeys( - ObjectId: new (id?: string | number) => any, - keyFields: string | string[], -) { - keyFields = Array.isArray(keyFields) ? keyFields : [keyFields]; - const keyLeaves: any = []; - - const keysInfo = keyFields.map((field: any) => { - const fieldNames = field.split('.'); - const leaf = fieldNames.slice(-1)[0]; - keyLeaves.push(leaf); - - return { leaf, len: fieldNames.length, path: JSON.stringify(fieldNames) }; - }); - - return (context: H) => { - checkContext(context, 'before', null, 'mongoKeys'); - const query = context.params.query || {}; - - traverse(query).forEach(function (node: any) { - const typeofNode = typeof node; - const key = this.key; - const path = this.path; - - if (keyLeaves.indexOf(key) === -1) return; - if (path.indexOf('$sort') !== -1) return; - - keysInfo.forEach((info: any) => { - if (info.leaf === key && info.len <= path.length) { - const endPath = path.slice(-info.len); - if (JSON.stringify(endPath) === info.path) { - if (typeofNode === 'object' && node !== null && !Array.isArray(node)) { - // { keyPath: { ... } } - const actualProps = Object.keys(node); - const onlyProp = actualProps[0]; - - if (actualProps.length === 1 && onlyProp === '$in') { - // { keyPath: { $in: [...] } } - const newNode = { $in: wrapValue(node[onlyProp]) }; - this.update(newNode); - } - } else if (typeofNode === 'string' || typeofNode === 'number') { - // { keyPath: '111111111111' } - const newNode = wrapValue(node); - this.update(newNode); - } - } - } - }); - }); - - return context; - }; - - function wrapValue(value: any) { - return Array.isArray(value) ? value.map(val => new ObjectId(val)) : new ObjectId(value); - } -} diff --git a/test/hooks/discard-1.test.ts b/src/hooks/omit-data/omit-data-1.test.ts similarity index 57% rename from test/hooks/discard-1.test.ts rename to src/hooks/omit-data/omit-data-1.test.ts index 00c2b946..217cc5c8 100755 --- a/test/hooks/discard-1.test.ts +++ b/src/hooks/omit-data/omit-data-1.test.ts @@ -1,84 +1,44 @@ -import { assert } from 'vitest'; -import { discard } from '../../src'; +import { assert } from 'vitest' +import { omitData } from './omit-data.js' +import type { HookContext } from '@feathersjs/feathers' -describe('common hook discard', () => { +describe('omitData', () => { describe('removes fields', () => { - const beforeJohn = (): any => ({ type: 'before', data: { first: 'John', last: 'Doe' } }); - const beforeUndef = (): any => ({ type: 'before', data: { first: undefined, last: 'Doe' } }); - const beforeNull = (): any => ({ type: 'before', data: { first: null, last: 'Doe' } }); - const afterJane = (): any => ({ type: 'after', result: { first: 'Jane', last: 'Doe' } }); - const afterBoth = (): any => ({ - type: 'after', - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }); - const afterPage = (): any => ({ - type: 'after', - result: { - total: 2, - skip: 0, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }); + const beforeJohn = (): any => ({ type: 'before', data: { first: 'John', last: 'Doe' } }) + const beforeUndef = (): any => ({ type: 'before', data: { first: undefined, last: 'Doe' } }) + const beforeNull = (): any => ({ type: 'before', data: { first: null, last: 'Doe' } }) const decisionTable = [ ['before::create', beforeJohn(), 'create', null, ['first'], { last: 'Doe' }], - [ - 'after::find with paginate', - afterPage(), - 'find', - null, - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - [ - 'after::find no paginate', - afterBoth(), - 'find', - null, - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - ['after', afterJane(), 'create', null, ['last'], { first: 'Jane' }], - ['call internally on server', afterJane(), 'create', undefined, ['last'], { first: 'Jane' }], ['not throw field missing', beforeJohn(), 'create', 'rest', ['first', 'xx'], { last: 'Doe' }], ['not throw field undefined', beforeUndef(), 'create', 'rest', ['first'], { last: 'Doe' }], ['not throw field null', beforeNull(), 'create', 'rest', ['first'], { last: 'Doe' }], - ]; + ] as [string, HookContext, string, string, string[], any][] decisionTable.forEach(([desc, context, method, provider, args, result]) => { it(desc, () => { - context.method = method; + // @ts-expect-error readonly + context.method = method if (provider !== null) { - context.params = context.params || {}; - context.params.provider = provider; + context.params = context.params || {} + context.params.provider = provider } - discard(...args)(context); + omitData(args)(context) assert.deepEqual( context.data ? context.data : context.result.data || context.result, result, - ); - }); - }); - }); + ) + }) + }) + }) describe('handles dot notation', () => { const ctx = (): any => ({ type: 'before', method: 'create', data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }); - const ctx2 = (): any => ({ - type: 'after', - method: 'get', - result: { property: null, foo: 'bar' }, - }); + }) const decisionTable = [ // desc, context, args, result @@ -118,17 +78,16 @@ describe('common hook discard', () => { ['empl.status', 'dept'], { empl: { name: { first: 'John', last: 'Doe' } } }, ], - ['path not obj', ctx2(), ['property.secret'], { property: null, foo: 'bar' }], - ]; + ] as [string, HookContext, string[], any][] decisionTable.forEach(([desc, context, args, result]) => { it(desc, () => { - discard(...args)(context); + omitData(args)(context) assert.deepEqual( context.data ? context.data : context.result.data || context.result, result, - ); - }); - }); - }); -}); + ) + }) + }) + }) +}) diff --git a/src/hooks/omit-data/omit-data.md b/src/hooks/omit-data/omit-data.md new file mode 100644 index 00000000..bb502b37 --- /dev/null +++ b/src/hooks/omit-data/omit-data.md @@ -0,0 +1,33 @@ +--- +title: omitData +description: Delete certain fields from the record(s). +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +> **Note:** The discard hook will remove fields even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), discard(...))`. + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | --------------------------------------------------------- | +| fieldNames | dot notation | One or more fields you want to remove from the record(s). | + +## Example + +```js +const { discard, iff, isProvider } = require('feathers-hooks-common/index.js'); + +module.exports = { + after: { all: iff(isProvider('external'), discard('password', 'address.city')) }, +}; +``` + +## Details + +Delete the fields either from `context.data` (before hook) or `context.result[.data]` (after hook). +They are not modified if they are not an object, so a `null` value is supported. diff --git a/src/hooks/omit-data/omit-data.test.ts b/src/hooks/omit-data/omit-data.test.ts new file mode 100755 index 00000000..438fa215 --- /dev/null +++ b/src/hooks/omit-data/omit-data.test.ts @@ -0,0 +1,94 @@ +import { assert } from 'vitest' +import { omitData } from './omit-data.js' + +let hookBefore: any + +describe('omitData', () => { + describe('removes fields', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe' }, + } + }) + + it('updates hook before::create', () => { + omitData('first')(hookBefore) + assert.deepEqual(hookBefore.data, { last: 'Doe' }) + }) + + it('does not throw if field is missing', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe' }, + } + omitData(['first', 'xx'])(hook) + assert.deepEqual(hook.data, { last: 'Doe' }) + }) + + it('does not throw if field is null', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: null, last: 'Doe' }, + } + omitData('first')(hook) + assert.deepEqual(hook.data, { last: 'Doe' }) + }) + }) + + describe('handles dot notation', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + } + }) + + it('prop with no dots', () => { + omitData('dept')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + }) + }) + + it('prop with 1 dot', () => { + omitData('empl.status')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' } }, + dept: 'Acct', + }) + }) + + it('prop with 2 dots', () => { + omitData('empl.name.first')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + + it('ignores bad or missing paths', () => { + omitData('empl.xx.first')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + + it('ignores bad or missing no dot path', () => { + omitData('xx')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + }) +}) diff --git a/src/hooks/omit-data/omit-data.ts b/src/hooks/omit-data/omit-data.ts new file mode 100755 index 00000000..49c86ebf --- /dev/null +++ b/src/hooks/omit-data/omit-data.ts @@ -0,0 +1,11 @@ +import _omit from 'lodash/omit.js' +import { transformData } from '../transform-data/transform-data.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Delete certain fields from the record(s). + * @see https://hooks-common.feathersjs.com/hooks.html#discard + */ +export const omitData = (fieldNames: MaybeArray) => + transformData((item: any) => _omit(item, toArray(fieldNames))) diff --git a/src/hooks/omit-query/omit-query.md b/src/hooks/omit-query/omit-query.md new file mode 100644 index 00000000..fc0916b0 --- /dev/null +++ b/src/hooks/omit-query/omit-query.md @@ -0,0 +1,30 @@ +--- +title: omitQuery +description: Delete certain fields from the query object. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['all'] + multi: true +--- + +> **Note:** The discardQuery hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), discardQuery(...))`. + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | ----------------------------------------------------- | +| fieldNames | dot notation | One or more fields you want to remove from the query. | + +## Example + +```js +const { discardQuery, iff, isProvider } = require('feathers-hooks-common/index.js'); + +module.exports = { after: { all: iff(isProvider('external'), discardQuery('secret')) } }; +``` + +## Details + +Delete the fields from `context.params.query`. diff --git a/test/hooks/discard-query.test.ts b/src/hooks/omit-query/omit-query.test.ts similarity index 69% rename from test/hooks/discard-query.test.ts rename to src/hooks/omit-query/omit-query.test.ts index e46b96c7..cd391830 100755 --- a/test/hooks/discard-query.test.ts +++ b/src/hooks/omit-query/omit-query.test.ts @@ -1,36 +1,36 @@ -import { assert } from 'vitest'; -import { discardQuery } from '../../src'; +import { assert } from 'vitest' +import { omitQuery } from './omit-query.js' -let hookBefore: any; -let hookAfter: any; +let hookBefore: any +let hookAfter: any -describe('services discardQuery', () => { +describe('omitQuery', () => { describe('updates query', () => { beforeEach(() => { hookBefore = { type: 'before', method: 'create', params: { query: { first: 'John', last: 'Doe' } }, - }; - hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } }; - }); + } + hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } } + }) it('updates hook before::create', () => { - discardQuery('last')(hookBefore); - assert.deepEqual(hookBefore.params, { query: { first: 'John' } }); - }); + omitQuery('last')(hookBefore) + assert.deepEqual(hookBefore.params, { query: { first: 'John' } }) + }) it('throws on hook after', () => { assert.throws(() => { - discardQuery('last')(hookAfter); - }); - }); + omitQuery('last')(hookAfter) + }) + }) it('does not throw if field is missing', () => { - discardQuery('x', 'first')(hookBefore); - assert.deepEqual(hookBefore.params.query, { last: 'Doe' }); - }); - }); + omitQuery(['x', 'first'])(hookBefore) + assert.deepEqual(hookBefore.params.query, { last: 'Doe' }) + }) + }) describe('handles dot notation', () => { beforeEach(() => { @@ -40,46 +40,46 @@ describe('services discardQuery', () => { params: { query: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, }, - }; - }); + } + }) it('prop with no dots', () => { - discardQuery('dept')(hookBefore); + omitQuery('dept')(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - }); - }); + }) + }) it('prop with 1 dot', () => { - discardQuery('empl.status')(hookBefore); + omitQuery('empl.status')(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { first: 'John', last: 'Doe' } }, dept: 'Acct', - }); - }); + }) + }) it('prop with 2 dots', () => { - discardQuery('empl.name.first')(hookBefore); + omitQuery('empl.name.first')(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { last: 'Doe' }, status: 'AA' }, dept: 'Acct', - }); - }); + }) + }) it('ignores bad or missing paths', () => { - discardQuery('empl.xx.first')(hookBefore); + omitQuery('empl.xx.first')(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct', - }); - }); + }) + }) it('ignores bad or missing no dot path', () => { - discardQuery('xx')(hookBefore); + omitQuery('xx')(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct', - }); - }); - }); -}); + }) + }) + }) +}) diff --git a/src/hooks/omit-query/omit-query.ts b/src/hooks/omit-query/omit-query.ts new file mode 100755 index 00000000..061c41b3 --- /dev/null +++ b/src/hooks/omit-query/omit-query.ts @@ -0,0 +1,20 @@ +import type { HookContext } from '@feathersjs/feathers' +import _omit from 'lodash/omit.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Delete certain fields from the query object. + * @see https://hooks-common.feathersjs.com/hooks.html#discardquery + */ +export const omitQuery = + (fieldNames: MaybeArray) => + (context: H) => { + if (!context.params.query) { + return context + } + + context.params.query = _omit(context.params.query, toArray(fieldNames)) + + return context + } diff --git a/src/hooks/omit-result/omit-result-1.test.ts b/src/hooks/omit-result/omit-result-1.test.ts new file mode 100755 index 00000000..a464253e --- /dev/null +++ b/src/hooks/omit-result/omit-result-1.test.ts @@ -0,0 +1,86 @@ +import { assert } from 'vitest' +import { omitResult } from './omit-result.js' + +describe('omitResult', () => { + describe('removes fields', () => { + const afterJane = (): any => ({ type: 'after', result: { first: 'Jane', last: 'Doe' } }) + const afterBoth = (): any => ({ + type: 'after', + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }) + const afterPage = (): any => ({ + type: 'after', + result: { + total: 2, + skip: 0, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + }) + + const decisionTable = [ + [ + 'after::find with paginate', + afterPage(), + 'find', + null, + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + [ + 'after::find no paginate', + afterBoth(), + 'find', + null, + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + ['after', afterJane(), 'create', null, ['last'], { first: 'Jane' }], + ['call internally on server', afterJane(), 'create', undefined, ['last'], { first: 'Jane' }], + ] + + decisionTable.forEach(([desc, context, method, provider, args, result]) => { + it(desc, () => { + context.method = method + if (provider !== null) { + context.params = context.params || {} + context.params.provider = provider + } + + omitResult(args)(context) + assert.deepEqual( + context.data ? context.data : context.result.data || context.result, + result, + ) + }) + }) + }) + + describe('handles dot notation', () => { + const ctx2 = (): any => ({ + type: 'after', + method: 'get', + result: { property: null, foo: 'bar' }, + }) + + const decisionTable = [ + // desc, context, args, result + ['path not obj', ctx2(), ['property.secret'], { property: null, foo: 'bar' }], + ] + + decisionTable.forEach(([desc, context, args, result]) => { + it(desc, () => { + omitResult(args)(context) + assert.deepEqual( + context.data ? context.data : context.result.data || context.result, + result, + ) + }) + }) + }) +}) diff --git a/src/hooks/omit-result/omit-result-2.test.ts b/src/hooks/omit-result/omit-result-2.test.ts new file mode 100755 index 00000000..feaa6bd5 --- /dev/null +++ b/src/hooks/omit-result/omit-result-2.test.ts @@ -0,0 +1,121 @@ +import { assert } from 'vitest' +import { omitResult } from './omit-result.js' + +describe('omitResult', () => { + describe('removes fields', () => { + const afterJane = (): any => ({ type: 'after', result: { first: 'Jane', last: 'Doe' } }) + const afterBoth = (): any => ({ + type: 'after', + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }) + const afterPage = (): any => ({ + type: 'after', + result: { + total: 2, + skip: 0, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + }) + + const decisionTable = [ + // desc, context, method, provider, args, result + [ + 'after::find with paginate', + afterPage(), + 'find', + undefined, + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + [ + 'after::find with paginate', + afterPage(), + 'find', + 'rest', + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + [ + 'after::find with paginate', + afterPage(), + 'find', + 'socketio', + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + [ + 'after::find no paginate', + afterBoth(), + 'find', + undefined, + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + [ + 'after::find no paginate', + afterBoth(), + 'find', + 'rest', + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + [ + 'after::find no paginate', + afterBoth(), + 'find', + 'socketio', + ['last'], + [{ first: 'John' }, { first: 'Jane' }], + ], + ['after', afterJane(), 'create', undefined, ['last'], { first: 'Jane' }], + ['after', afterJane(), 'create', 'rest', ['last'], { first: 'Jane' }], + ['after', afterJane(), 'create', 'socketio', ['last'], { first: 'Jane' }], + ['call internally on server', afterJane(), 'create', undefined, ['last'], { first: 'Jane' }], + ] + + decisionTable.forEach(([desc, context, method, provider, args, result]) => { + it(desc, () => { + context.method = method + if (provider !== null) { + context.params = context.params || {} + context.params.provider = provider + } + + omitResult(args)(context) + assert.deepEqual( + context.data ? context.data : context.result.data || context.result, + result, + ) + }) + }) + }) + + describe('handles dot notation', () => { + const ctx2 = (): any => ({ + type: 'after', + method: 'get', + result: { property: null, foo: 'bar' }, + }) + + const decisionTable = [ + // desc, context, args, result + ['path not obj', ctx2(), ['property.secret'], { property: null, foo: 'bar' }], + ] + + decisionTable.forEach(([desc, context, args, result]) => { + it(desc, () => { + omitResult(args)(context) + assert.deepEqual( + context.data ? context.data : context.result.data || context.result, + result, + ) + }) + }) + }) +}) diff --git a/src/hooks/omit-result/omit-result.md b/src/hooks/omit-result/omit-result.md new file mode 100644 index 00000000..900657fc --- /dev/null +++ b/src/hooks/omit-result/omit-result.md @@ -0,0 +1,9 @@ +--- +title: omitResult +description: Omit certain fields from the result. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- diff --git a/src/hooks/omit-result/omit-result.test.ts b/src/hooks/omit-result/omit-result.test.ts new file mode 100755 index 00000000..2f101235 --- /dev/null +++ b/src/hooks/omit-result/omit-result.test.ts @@ -0,0 +1,109 @@ +import { assert } from 'vitest' +import { omitResult } from './omit-result.js' + +let hookAfter: any +let hookFindPaginate: any +let hookFind: any + +describe('omitResult', () => { + describe('removes fields', () => { + beforeEach(() => { + hookAfter = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane', last: 'Doe' }, + } + hookFindPaginate = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: { + total: 2, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + } + hookFind = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } + }) + + it('updates hook after::find with pagination', () => { + omitResult('last')(hookFindPaginate) + assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after::find with no pagination', () => { + omitResult('last')(hookFind) + assert.deepEqual(hookFind.result, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after', () => { + omitResult('last')(hookAfter) + assert.deepEqual(hookAfter.result, { first: 'Jane' }) + }) + + it('updates when called internally on server', () => { + hookAfter.params.provider = '' + omitResult('last')(hookAfter) + assert.deepEqual(hookAfter.result, { first: 'Jane' }) + }) + }) + + describe('handles dot notation', () => { + it('discards multiple fields', () => { + const hook: any = { + type: 'after', + method: 'get', + result: { + roles: ['super'], + _id: 'a', + email: 'foo', + password: 'bar', + name: 'Rafael', + id: 'b', + }, + query: {}, + } + + omitResult(['email', 'password'])(hook) + + assert.deepEqual(hook.result, { + roles: ['super'], + _id: 'a', + // email: 'foo', + // password: 'bar', + name: 'Rafael', + id: 'b', + } as any) + }) + + it('null prop', () => { + const hook: any = { + type: 'after', + method: 'get', + result: { + property: null, + other: 'bar', + }, + query: {}, + } + + omitResult('property.secret')(hook) + + assert.deepEqual(hook.result, { + property: null, + other: 'bar', + }) + }) + }) +}) diff --git a/src/hooks/omit-result/omit-result.ts b/src/hooks/omit-result/omit-result.ts new file mode 100755 index 00000000..5d24c965 --- /dev/null +++ b/src/hooks/omit-result/omit-result.ts @@ -0,0 +1,16 @@ +import _omit from 'lodash/omit.js' +import { transformResult } from '../transform-result/transform-result.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' +import type { DispatchOption } from '../../types.js' + +export type OmitResultOptions = { + dispatch?: DispatchOption +} + +/** + * Delete certain fields from the record(s). + * @see https://hooks-common.feathersjs.com/hooks.html#discard + */ +export const omitResult = (fieldNames: MaybeArray, options?: OmitResultOptions) => + transformResult((item: any) => _omit(item, toArray(fieldNames)), { dispatch: options?.dispatch }) diff --git a/src/hooks/on-delete/on-delete.test.ts b/src/hooks/on-delete/on-delete.test.ts new file mode 100644 index 00000000..a12c50ae --- /dev/null +++ b/src/hooks/on-delete/on-delete.test.ts @@ -0,0 +1,558 @@ +import assert from 'node:assert' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { onDelete } from './on-delete.js' + +const mockApp = () => { + const app = feathers() + + app.use('users', new MemoryService({ startId: 1, multi: true })) + app.use('todos', new MemoryService({ startId: 1, multi: true })) + app.use('tasks', new MemoryService({ startId: 1, multi: true })) + + const usersService = app.service('users') + const todosService = app.service('todos') + const tasksService = app.service('tasks') + + return { + app, + todosService, + usersService, + tasksService, + } +} + +describe('hook - onDelete', function () { + describe('cascade', function () { + it('removes single item for single item', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }), + ], + }, + }) + + const user = await usersService.create({ + name: 'John Doe', + }) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: user.id, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + await usersService.remove(user.id) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [{ id: 2, title: 'Buy eggs', userId: 2 }]) + }) + + it('removes multiple items for single item', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }), + ], + }, + }) + + const user = await usersService.create({ + name: 'John Doe', + }) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: user.id, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: user.id, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(user.id) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [{ id: 3, title: 'Buy bread', userId: 3 }]) + }) + + it('removes single item for multiple items', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }), + ], + }, + }) + + await usersService.create([{ name: 'John Doe' }, { name: 'Jane Doe' }, { name: 'Jack Doe' }]) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: 1, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(1) + + const users = await usersService.find({ query: {} }) + + assert.deepStrictEqual(users, [ + { id: 2, name: 'Jane Doe' }, + { id: 3, name: 'Jack Doe' }, + ]) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 2, title: 'Buy eggs', userId: 2 }, + { id: 3, title: 'Buy bread', userId: 3 }, + ]) + }) + + it('removes multiple items for multiple items', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }), + ], + }, + }) + + await usersService.create([{ name: 'John Doe' }, { name: 'Jane Doe' }, { name: 'Jack Doe' }]) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: 1, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(null, { query: { id: { $in: [1, 2] } } }) + + const users = await usersService.find({ query: {} }) + + assert.deepStrictEqual(users, [{ id: 3, name: 'Jack Doe' }]) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [{ id: 3, title: 'Buy bread', userId: 3 }]) + }) + + it('does not remove items if not found', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }), + ], + }, + }) + + await usersService.create([{ name: 'John Doe' }, { name: 'Jane Doe' }, { name: 'Jack Doe' }]) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: 2, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(1) + + const users = await usersService.find({ query: {} }) + + assert.deepStrictEqual(users, [ + { id: 2, name: 'Jane Doe' }, + { id: 3, name: 'Jack Doe' }, + ]) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'Buy milk', userId: 2 }, + { id: 2, title: 'Buy eggs', userId: 2 }, + { id: 3, title: 'Buy bread', userId: 3 }, + ]) + }) + + it('can pass an array', async function () { + const { app, usersService, todosService, tasksService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete([ + { + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }, + { + service: 'tasks', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }, + ]), + ], + }, + }) + + const user = await usersService.create({ + name: 'John Doe', + }) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: user.id, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const task = await tasksService.create({ + title: 'Buy milk task', + userId: user.id, + }) + + const task2 = await tasksService.create({ + title: 'Buy eggs task', + userId: 2, + }) + + await usersService.remove(user.id) + + const todos = await todosService.find({ query: {} }) + assert.deepStrictEqual(todos, [{ id: 2, title: 'Buy eggs', userId: 2 }]) + + const tasks = await tasksService.find({ query: {} }) + assert.deepStrictEqual(tasks, [{ id: 2, title: 'Buy eggs task', userId: 2 }]) + }) + }) + + describe('set null', function () { + it('sets null single item for single item', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'set null', + blocking: true, + }), + ], + }, + }) + + const user = await usersService.create({ + name: 'John Doe', + }) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: user.id, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + await usersService.remove(user.id) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'Buy milk', userId: null }, + { id: 2, title: 'Buy eggs', userId: 2 }, + ]) + }) + + it('sets null multiple items for single item', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'set null', + blocking: true, + }), + ], + }, + }) + + const user = await usersService.create({ + name: 'John Doe', + }) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: user.id, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: user.id, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(user.id) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'Buy milk', userId: null }, + { id: 2, title: 'Buy eggs', userId: null }, + { id: 3, title: 'Buy bread', userId: 3 }, + ]) + }) + + it('sets null single item for multiple items', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'set null', + blocking: true, + }), + ], + }, + }) + + await usersService.create([{ name: 'John Doe' }, { name: 'Jane Doe' }, { name: 'Jack Doe' }]) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: 1, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(1) + + const users = await usersService.find({ query: {} }) + + assert.deepStrictEqual(users, [ + { id: 2, name: 'Jane Doe' }, + { id: 3, name: 'Jack Doe' }, + ]) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'Buy milk', userId: null }, + { id: 2, title: 'Buy eggs', userId: 2 }, + { id: 3, title: 'Buy bread', userId: 3 }, + ]) + }) + + it('sets null multiple items for multiple items', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'set null', + blocking: true, + }), + ], + }, + }) + + await usersService.create([{ name: 'John Doe' }, { name: 'Jane Doe' }, { name: 'Jack Doe' }]) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: 1, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(null, { query: { id: { $in: [1, 2] } } }) + + const users = await usersService.find({ query: {} }) + + assert.deepStrictEqual(users, [{ id: 3, name: 'Jack Doe' }]) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'Buy milk', userId: null }, + { id: 2, title: 'Buy eggs', userId: null }, + { id: 3, title: 'Buy bread', userId: 3 }, + ]) + }) + + it('does not set null for items if not found', async function () { + const { app, usersService, todosService } = mockApp() + + usersService.hooks({ + after: { + remove: [ + onDelete({ + service: 'todos', + keyThere: 'userId', + keyHere: 'id', + onDelete: 'cascade', + blocking: true, + }), + ], + }, + }) + + await usersService.create([{ name: 'John Doe' }, { name: 'Jane Doe' }, { name: 'Jack Doe' }]) + + const todo = await todosService.create({ + title: 'Buy milk', + userId: 2, + }) + + const todo2 = await todosService.create({ + title: 'Buy eggs', + userId: 2, + }) + + const todo3 = await todosService.create({ + title: 'Buy bread', + userId: 3, + }) + + await usersService.remove(1) + + const users = await usersService.find({ query: {} }) + + assert.deepStrictEqual(users, [ + { id: 2, name: 'Jane Doe' }, + { id: 3, name: 'Jack Doe' }, + ]) + + const todos = await todosService.find({ query: {} }) + + assert.deepStrictEqual(todos, [ + { id: 1, title: 'Buy milk', userId: 2 }, + { id: 2, title: 'Buy eggs', userId: 2 }, + { id: 3, title: 'Buy bread', userId: 3 }, + ]) + }) + }) +}) diff --git a/src/hooks/on-delete/on-delete.ts b/src/hooks/on-delete/on-delete.ts new file mode 100644 index 00000000..d233087b --- /dev/null +++ b/src/hooks/on-delete/on-delete.ts @@ -0,0 +1,78 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { checkContext, getResultIsArray } from '../../utils/index.js' +import type { KeyOf, MaybeArray } from '../../internal.utils.js' + +export type OnDeleteAction = 'cascade' | 'set null' + +export interface OnDeleteOptions { + service: Path + keyThere: string + keyHere: string + onDelete: OnDeleteAction + /** + * If true, the hook will wait for the service to finish before continuing + * + * @default false + */ + blocking?: boolean +} + +/** + * hook to manipulate related items on delete + */ +export const onDelete = , H extends HookContext = HookContext>( + options: MaybeArray>>, +) => { + const optionsMulti = Array.isArray(options) ? options : [options] + + return async (context: H, next?: NextFunction) => { + checkContext(context, ['after', 'around'], 'remove', 'onDelete') + + if (next) { + await next() + } + + const { result } = getResultIsArray(context) + + if (!result.length) { + return context + } + + const promises: Promise[] = [] + + optionsMulti.forEach(async ({ keyHere, keyThere, onDelete, service, blocking }) => { + let ids = result.map(x => x[keyHere]).filter(x => !!x) + ids = [...new Set(ids)] + + if (!ids || ids.length <= 0) { + return context + } + + const params = { + query: { + ...(ids.length === 1 ? { [keyThere]: ids[0] } : { [keyThere]: { $in: ids } }), + }, + paginate: false, + } + + let promise: Promise | undefined = undefined + + if (onDelete === 'cascade') { + promise = context.app.service(service as string).remove(null, params) + } else if (onDelete === 'set null') { + const data = { [keyThere]: null } + promise = context.app.service(service as string).patch(null, data, params) + } + + if (promise && blocking) { + promises.push(promise) + } + }) + + if (promises.length) { + await Promise.all(promises) + } + + return context + } +} diff --git a/src/hooks/params-for-server/params-for-from-shared.ts b/src/hooks/params-for-server/params-for-from-shared.ts new file mode 100644 index 00000000..eae3bfe5 --- /dev/null +++ b/src/hooks/params-for-server/params-for-from-shared.ts @@ -0,0 +1 @@ +export const FROM_CLIENT_FOR_SERVER_DEFAULT_KEY = '_$client' as const diff --git a/src/hooks/params-for-server/params-for-server.md b/src/hooks/params-for-server/params-for-server.md new file mode 100644 index 00000000..39656020 --- /dev/null +++ b/src/hooks/params-for-server/params-for-server.md @@ -0,0 +1,9 @@ +--- +title: paramsForServer +description: Add or modify parameters for the server. +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- diff --git a/src/hooks/params-for-server/params-for-server.test.ts b/src/hooks/params-for-server/params-for-server.test.ts new file mode 100644 index 00000000..4ee91366 --- /dev/null +++ b/src/hooks/params-for-server/params-for-server.test.ts @@ -0,0 +1,46 @@ +import type { HookContext } from '@feathersjs/feathers' +import { paramsForServer } from './params-for-server.js' + +describe('paramsForServer', () => { + it('should move params to query._$client', () => { + expect( + paramsForServer(['a', 'b'])({ + params: { + a: 1, + b: 2, + query: {}, + }, + } as HookContext), + ).toEqual({ + params: { + query: { + _$client: { + a: 1, + b: 2, + }, + }, + }, + }) + }) + + it('should move params to query._$client and leave remaining', () => { + expect( + paramsForServer('a')({ + params: { + a: 1, + b: 2, + query: {}, + }, + } as HookContext), + ).toEqual({ + params: { + b: 2, + query: { + _$client: { + a: 1, + }, + }, + }, + }) + }) +}) diff --git a/src/hooks/params-for-server/params-for-server.ts b/src/hooks/params-for-server/params-for-server.ts new file mode 100644 index 00000000..91c6b141 --- /dev/null +++ b/src/hooks/params-for-server/params-for-server.ts @@ -0,0 +1,65 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' +import { FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } from './params-for-from-shared.js' + +export type ParamsForServerOptions = { + /** + * @default '_$client' + */ + keyToHide?: string +} + +/** + * a hook to move params to query._$client + * the server only receives 'query' from params. All other params are ignored. + * So, to use `$populateParams` on the server, we need to move the params to query._$client + * the server will move them back to params + */ +export const paramsForServer = ( + whitelist: MaybeArray, + options?: ParamsForServerOptions, +) => { + const whitelistArr = toArray(whitelist) + + const { keyToHide = FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } = options || {} + + return (context: H, next?: NextFunction) => { + // clone params on demand + let clonedParams: any + + Object.keys(context.params).forEach(key => { + if (key === 'query') { + return + } + + if (whitelistArr.includes(key)) { + if (!clonedParams) { + clonedParams = { + ...context.params, + query: { + ...context.params.query, + }, + } + } + + if (!clonedParams.query[keyToHide]) { + clonedParams.query[keyToHide] = {} + } + + clonedParams.query[keyToHide][key] = clonedParams[key] + delete clonedParams[key] + } + }) + + if (clonedParams) { + context.params = clonedParams + } + + if (next) { + return next() + } + + return context + } +} diff --git a/src/hooks/params-from-client.ts b/src/hooks/params-from-client.ts deleted file mode 100755 index 9c0a53b7..00000000 --- a/src/hooks/params-from-client.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Pass context.params from client to server. Server hook. - * @see https://hooks-common.feathersjs.com/hooks.html#paramsfromclient - */ -export function paramsFromClient(...whitelist: string[]) { - return (context: H) => { - const params = context.params; - - if (params?.query?.$client && typeof params.query.$client === 'object') { - const client = params.query.$client; - - whitelist.forEach(key => { - if (key in client) { - // @ts-ignore - params[key] = client[key]; - } - }); - - params.query = Object.assign({}, params.query); - delete params.query.$client; - } - - return context; - }; -} diff --git a/src/hooks/params-from-client/params-from-client.md b/src/hooks/params-from-client/params-from-client.md new file mode 100644 index 00000000..43d1c552 --- /dev/null +++ b/src/hooks/params-from-client/params-from-client.md @@ -0,0 +1,46 @@ +--- +title: paramsFromClient +description: Pass `context.params` from client to server. Server hook. +category: hooks +hook: + type: ['before', 'around'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{Array< String > | String} whitelist` + +| Argument | Type | Default | Description | +| ----------- | :----------: | ------- | ------------------------------------------------------------------------------------------------------------ | +| `whitelist` | dot notation | | Names of the props permitted to be in `context.params`. Other props are ignored. This is a security feature. | + +## Example + +```js +// client +const { paramsForServer } = require('feathers-hooks-common/index.js'); + +service.update( + id, + data, + paramsForServer({ query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' }), +); + +// server +const { paramsFromClient } = require('feathers-hooks-common/index.js'); + +module.exports = { + before: { all: [paramsFromClient('populate', 'serialize', 'otherProp'), myHook] }, +}; + +// myHook's `context.params` will now be +// { query: { dept: 'a' }, populate: 'po-1', serialize: 'po-mgr' } } +``` + +## Details + +By default, only the `context.params.query` object is transferred from a Feathers client to the server, for security among other reasons. However you can explicitly transfer other `context.params` props with the client utility function `paramsForServer` in conjunction with the `paramsFromClient` hook on the server. + +This technique also works for service calls made on the server. diff --git a/src/hooks/params-from-client/params-from-client.test.ts b/src/hooks/params-from-client/params-from-client.test.ts new file mode 100644 index 00000000..4f0a0252 --- /dev/null +++ b/src/hooks/params-from-client/params-from-client.test.ts @@ -0,0 +1,54 @@ +import type { HookContext } from '@feathersjs/feathers' +import { paramsFromClient } from './params-from-client.js' + +describe('paramsFromClient', () => { + it('should move params to query._$client', () => { + expect( + paramsFromClient(['a', 'b'])({ + params: { + query: { + _$client: { + a: 1, + b: 2, + }, + c: 3, + }, + }, + } as HookContext), + ).toEqual({ + params: { + a: 1, + b: 2, + query: { + c: 3, + }, + }, + }) + }) + + it('should move params to query._$client and leave remaining', () => { + expect( + paramsFromClient('a')({ + params: { + query: { + _$client: { + a: 1, + b: 2, + }, + c: 3, + }, + }, + } as HookContext), + ).toEqual({ + params: { + a: 1, + query: { + _$client: { + b: 2, + }, + c: 3, + }, + }, + }) + }) +}) diff --git a/src/hooks/params-from-client/params-from-client.ts b/src/hooks/params-from-client/params-from-client.ts new file mode 100644 index 00000000..ce8b44b2 --- /dev/null +++ b/src/hooks/params-from-client/params-from-client.ts @@ -0,0 +1,58 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' +import { FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } from '../params-for-server/params-for-from-shared.js' + +export type paramsFromClientOptions = { + /** + * @default '_$client' + */ + keyToHide?: string +} + +export const paramsFromClient = ( + whitelist: MaybeArray, + options?: paramsFromClientOptions, +) => { + const whitelistArr = toArray(whitelist) + const { keyToHide = FROM_CLIENT_FOR_SERVER_DEFAULT_KEY } = options || {} + return (context: HookContext, next?: NextFunction) => { + if ( + !context.params?.query?.[keyToHide] || + typeof context.params.query[keyToHide] !== 'object' + ) { + return context + } + + const params = { + ...context.params, + query: { + ...context.params.query, + [keyToHide]: { + ...context.params.query[keyToHide], + }, + }, + } + + const client = params.query[keyToHide] + + whitelistArr.forEach(key => { + if (key in client) { + params[key] = client[key] + delete client[key] + } + }) + + if (Object.keys(client).length === 0) { + delete params.query[keyToHide] + } + + context.params = params + + if (next) { + return next() + } + + return context + } +} diff --git a/src/hooks/pick-data/pick-data.md b/src/hooks/pick-data/pick-data.md new file mode 100644 index 00000000..2762e38f --- /dev/null +++ b/src/hooks/pick-data/pick-data.md @@ -0,0 +1,31 @@ +--- +title: pickData +description: Keep certain fields in the record(s), deleting the rest. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +> **Note:** The keep hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), keep(...))`. + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | -------------------------------------------------- | +| fieldNames | dot notation | The only fields you want to keep in the record(s). | + +## Example + +```js +const { keep } = require('feathers-hooks-common/index.js'); + +module.exports = { after: { create: keep('name', 'dept', 'address.city') } }; +``` + +## Details + +Update either `context.data` (before hook) or `context.result[.data]` (after hook). +Their values are returned if they are not an object, so a `null` value is supported. diff --git a/src/hooks/pick-data/pick-data.test.ts b/src/hooks/pick-data/pick-data.test.ts new file mode 100755 index 00000000..5757f491 --- /dev/null +++ b/src/hooks/pick-data/pick-data.test.ts @@ -0,0 +1,153 @@ +import { assert } from 'vitest' +import { pickData } from './pick-data.js' + +let hookBefore: any + +describe('pickData', () => { + describe('removes fields', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe' }, + } + }) + + it('does not throw if field is missing', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe' }, + } + pickData(['last', 'xx'])(hook) + assert.deepEqual(hook.data, { last: 'Doe' }) + }) + + it('keeps undefined values', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: undefined, last: 'Doe' }, + } + pickData('first')(hook) + assert.deepEqual(hook.data, { first: undefined }) + }) + + it('keeps null values', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: null, last: 'Doe' }, + } + pickData('first')(hook) + assert.deepEqual(hook.data, { first: null }) + }) + + it('keeps false values', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: false, last: 'Doe' }, + } + pickData('first')(hook) + assert.deepEqual(hook.data, { first: false }) + }) + + it('keeps 0 values', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 0, last: 'Doe' }, + } + pickData('first')(hook) + assert.deepEqual(hook.data, { first: 0 }) + }) + + it('keeps empty string values', () => { + const hook: any = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: '', last: 'Doe' }, + } + pickData('first')(hook) + assert.deepEqual(hook.data, { first: '' }) + }) + }) + + describe('handles dot notation', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + } + }) + + it('prop with no dots', () => { + pickData('empl')(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + }) + }) + + it('prop with 1 dot', () => { + pickData(['empl.name', 'dept'])(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' } }, + dept: 'Acct', + }) + }) + + it('prop with 2 dots', () => { + pickData(['empl.name.last', 'empl.status', 'dept'])(hookBefore) + assert.deepEqual(hookBefore.data, { + empl: { name: { last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + + it('ignores bad or missing paths', () => { + pickData(['empl.name.first', 'empl.name.surname'])(hookBefore) + assert.deepEqual(hookBefore.data, { empl: { name: { first: 'John' } } }) + }) + + it('ignores bad or missing no dot path', () => { + pickData('xx')(hookBefore) + assert.deepEqual(hookBefore.data, {}) + }) + }) + + describe('ignore non-object records', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: [ + { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + null, + undefined, + Infinity, + ], + } + }) + + it('before', () => { + pickData('empl')(hookBefore) + assert.deepEqual(hookBefore.data, [ + { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }, + null, + undefined, + Infinity, + ]) + }) + }) +}) diff --git a/src/hooks/pick-data/pick-data.ts b/src/hooks/pick-data/pick-data.ts new file mode 100755 index 00000000..87fd9ce9 --- /dev/null +++ b/src/hooks/pick-data/pick-data.ts @@ -0,0 +1,17 @@ +import _pick from 'lodash/pick.js' +import { transformData } from '../transform-data/transform-data.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Keep certain fields in the record(s), deleting the rest. + * @see https://hooks-common.feathersjs.com/hooks.html#keep + */ +export const pickData = (fieldNames: MaybeArray) => { + const fieldNamesArr = toArray(fieldNames) + return transformData((item: any) => { + if (typeof item !== 'object' || item === null) return item + + return _pick(item, fieldNamesArr) + }) +} diff --git a/src/hooks/pick-query/pick-query.md b/src/hooks/pick-query/pick-query.md new file mode 100644 index 00000000..b77de53c --- /dev/null +++ b/src/hooks/pick-query/pick-query.md @@ -0,0 +1,30 @@ +--- +title: pickQuery +description: Keep certain fields in the query object, deleting the rest. +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +> **Note:** The keepQuery hook will remove any fields not specified even if the service is being called from the server. You may want to condition the hook to run only for external transports, e.g. `iff(isProvider('external'), keepQuery(...))`. + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | ----------------------------------------------------- | +| fieldNames | dot notation | The only fields you want to keep in the query object. | + +## Example + +```js +const { keepQuery } = require('feathers-hooks-common/index.js'); + +module.exports = { after: { create: keepQuery('name', 'address.city') } }; +``` + +## Details + +Updates `context.params.query`. diff --git a/test/hooks/keep-query.test.ts b/src/hooks/pick-query/pick-query.test.ts similarity index 64% rename from test/hooks/keep-query.test.ts rename to src/hooks/pick-query/pick-query.test.ts index 70f3c3aa..b92ec5f9 100755 --- a/test/hooks/keep-query.test.ts +++ b/src/hooks/pick-query/pick-query.test.ts @@ -1,41 +1,41 @@ -import { assert } from 'vitest'; -import { keepQuery } from '../../src'; +import { assert } from 'vitest' +import { pickQuery } from './pick-query.js' -let hookBefore: any; -let hookAfter: any; +let hookBefore: any +let hookAfter: any -describe('services keepQuery', () => { +describe('pickQuery', () => { describe('updates query', () => { beforeEach(() => { hookBefore = { type: 'before', method: 'create', params: { query: { first: 'John', last: 'Doe' } }, - }; - hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } }; - }); + } + hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } } + }) it('updates hook before::create', () => { - keepQuery('first', 'last')(hookBefore); - assert.deepEqual(hookBefore.params, { query: { first: 'John', last: 'Doe' } }); - }); + pickQuery(['first', 'last'])(hookBefore) + assert.deepEqual(hookBefore.params, { query: { first: 'John', last: 'Doe' } }) + }) it('updates hook before::create', () => { - keepQuery('first')(hookBefore); - assert.deepEqual(hookBefore.params, { query: { first: 'John' } }); - }); + pickQuery('first')(hookBefore) + assert.deepEqual(hookBefore.params, { query: { first: 'John' } }) + }) it('throws on hook after', () => { assert.throws(() => { - keepQuery('last')(hookAfter); - }); - }); + pickQuery('last')(hookAfter) + }) + }) it('does not throw if field is missing', () => { - keepQuery('x', 'last')(hookBefore); - assert.deepEqual(hookBefore.params.query, { last: 'Doe' }); - }); - }); + pickQuery(['x', 'last'])(hookBefore) + assert.deepEqual(hookBefore.params.query, { last: 'Doe' }) + }) + }) describe('handles dot notation', () => { beforeEach(() => { @@ -50,42 +50,42 @@ describe('services keepQuery', () => { 'owner.admin': false, }, }, - }; - }); + } + }) it('prop with no dots', () => { - keepQuery('empl')(hookBefore); + pickQuery('empl')(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - }); - }); + }) + }) it('prop with 1 dot', () => { - keepQuery('empl.name', 'dept', 'owner.id', 'owner.admin')(hookBefore); + pickQuery(['empl.name', 'dept', 'owner.id', 'owner.admin'])(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { first: 'John', last: 'Doe' } }, dept: 'Acct', 'owner.id': 1, 'owner.admin': false, - }); - }); + }) + }) it('prop with 2 dots', () => { - keepQuery('empl.name.last', 'empl.status', 'dept')(hookBefore); + pickQuery(['empl.name.last', 'empl.status', 'dept'])(hookBefore) assert.deepEqual(hookBefore.params.query, { empl: { name: { last: 'Doe' }, status: 'AA' }, dept: 'Acct', - }); - }); + }) + }) it('ignores bad or missing paths', () => { - keepQuery('empl.xx.first')(hookBefore); - assert.deepEqual(hookBefore.params.query, {}); - }); + pickQuery('empl.xx.first')(hookBefore) + assert.deepEqual(hookBefore.params.query, {}) + }) it('ignores bad or missing no dot path', () => { - keepQuery('xx')(hookBefore); - assert.deepEqual(hookBefore.params.query, {}); - }); - }); -}); + pickQuery('xx')(hookBefore) + assert.deepEqual(hookBefore.params.query, {}) + }) + }) +}) diff --git a/src/hooks/pick-query/pick-query.ts b/src/hooks/pick-query/pick-query.ts new file mode 100755 index 00000000..fec27ba9 --- /dev/null +++ b/src/hooks/pick-query/pick-query.ts @@ -0,0 +1,23 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import _pick from 'lodash/pick.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Keep certain fields in the query object, deleting the rest. + * @see https://hooks-common.feathersjs.com/hooks.html#keepquery + */ +export const pickQuery = (fieldNames: MaybeArray) => { + const fieldNamesArr = toArray(fieldNames) + return (context: H, next?: NextFunction) => { + if (!context.params.query) { + return context + } + + context.params.query = _pick(context.params.query, fieldNamesArr) + + if (next) return next().then(() => context) + + return context + } +} diff --git a/src/hooks/pick-result/pick-result.md b/src/hooks/pick-result/pick-result.md new file mode 100644 index 00000000..ebd11870 --- /dev/null +++ b/src/hooks/pick-result/pick-result.md @@ -0,0 +1,9 @@ +--- +title: pickResult +description: Pick certain fields from the result. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- diff --git a/src/hooks/pick-result/pick-result.test.ts b/src/hooks/pick-result/pick-result.test.ts new file mode 100755 index 00000000..3ea24504 --- /dev/null +++ b/src/hooks/pick-result/pick-result.test.ts @@ -0,0 +1,77 @@ +import { assert } from 'vitest' +import { pickResult } from './pick-result.js' + +let hookAfter: any +let hookFindPaginate: any +let hookFind: any + +describe('pickResult', () => { + describe('removes fields', () => { + beforeEach(() => { + hookAfter = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane', last: 'Doe' }, + } + hookFindPaginate = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: { + total: 2, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + } + hookFind = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } + }) + + it('updates hook after::find with pagination', () => { + pickResult('first')(hookFindPaginate) + assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after::find with no pagination', () => { + pickResult('first')(hookFind) + assert.deepEqual(hookFind.result, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after', () => { + pickResult('first')(hookAfter) + assert.deepEqual(hookAfter.result, { first: 'Jane' }) + }) + + it('updates when called internally on server', () => { + hookAfter.params.provider = '' + pickResult('first')(hookAfter) + assert.deepEqual(hookAfter.result, { first: 'Jane' }) + }) + }) + + describe('ignore non-object records', () => { + beforeEach(() => { + hookAfter = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: [{ first: 'Jane', last: 'Doe' }, null, undefined, Infinity], + } + }) + + it('after', () => { + pickResult('first')(hookAfter) + assert.deepEqual(hookAfter.result, [{ first: 'Jane' }, null, undefined, Infinity]) + }) + }) +}) diff --git a/src/hooks/pick-result/pick-result.ts b/src/hooks/pick-result/pick-result.ts new file mode 100755 index 00000000..8ee0e37a --- /dev/null +++ b/src/hooks/pick-result/pick-result.ts @@ -0,0 +1,26 @@ +import _pick from 'lodash/pick.js' + +import { transformResult } from '../transform-result/transform-result.js' +import type { DispatchOption } from '../../types.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +export type PickResultOptions = { + dispatch?: DispatchOption +} + +/** + * Keep certain fields in the record(s), deleting the rest. + * @see https://hooks-common.feathersjs.com/hooks.html#keep + */ +export const pickResult = (fieldNames: MaybeArray, options?: PickResultOptions) => { + const fieldNamesArr = toArray(fieldNames) + return transformResult( + (item: any) => { + if (typeof item !== 'object' || item === null) return item + + return _pick(item, fieldNamesArr) + }, + { dispatch: options?.dispatch }, + ) +} diff --git a/src/hooks/populate.ts b/src/hooks/populate.ts deleted file mode 100755 index 65f46350..00000000 --- a/src/hooks/populate.ts +++ /dev/null @@ -1,352 +0,0 @@ -import _get from 'lodash/get.js'; -import _set from 'lodash/set.js'; -import { BadRequest } from '@feathersjs/errors'; - -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; -import type { HookContext } from '@feathersjs/feathers'; - -export interface PopulateOptions { - schema: - | Partial - | ((context: H, options: PopulateOptions) => Partial); - checkPermissions?: (context: H, path: string, permissions: any, depth: number) => boolean; - profile?: boolean; -} - -export interface PopulateSchema { - /** - * The name of the service providing the items, actually its path. - */ - service: string; - /** - * Where to place the items from the join - * dot notation - */ - nameAs: string; - /** - * The name of the field in the parent item for the relation. - * dot notation - */ - parentField: string; - /** - * The name of the field in the child item for the relation. - * Dot notation is allowed and will result in a query like { 'name.first': 'John' } which is not suitable for all DBs. - * You may use query or select to create a query suitable for your DB. - */ - childField: string; - - /** - * Who is allowed to perform this join. See checkPermissions above. - */ - permissions: any; - - /** - * An object to inject into context.params.query. - */ - query: any; - - /** - * A function whose result is injected into the query. - */ - select: (context: HookContext, parentItem: any, depth: number) => any; - - /** - * Force a single joined item to be stored as an array. - */ - asArray: boolean; - - /** - * Controls pagination for this service. - */ - paginate: boolean | number; - - /** - * Perform any populate or fastJoin registered on this service. - */ - useInnerPopulate: boolean; - /** - * Call the service as the server, not with the client’s transport. - */ - provider: string; - include: Partial | Partial[]; -} - -export function populate(options: PopulateOptions) { - // options.schema is like { service: '...', permissions: '...', include: [ ... ] } - - const typeofSchema = typeof options.schema; - if ((typeofSchema !== 'object' || options.schema === null) && typeofSchema !== 'function') { - throw new Error('Options.schema is not an object. (populate)'); - } - - return function (context: H) { - const optionsDefault: PopulateOptions = { - schema: {}, - checkPermissions: () => true, - profile: false, - }; - - // @ts-ignore - if (context.params._populate === 'skip') { - // this service call made from another populate - return context; - } - - return Promise.resolve() - .then(() => { - // 'options.schema' resolves to { permissions: '...', include: [ ... ] } - - const items = getItems(context); - const options1 = Object.assign({}, optionsDefault, options); - const { schema, checkPermissions } = options1; - - const schema1 = typeof schema === 'function' ? schema(context, options1) : schema; - const permissions = schema1.permissions || null; - const baseService = schema1.service; - const provider = 'provider' in schema1 ? schema1.provider : context.params.provider; - - if (typeof checkPermissions !== 'function') { - throw new BadRequest('Permissions param is not a function. (populate)'); - } - - if (baseService && context.path && baseService !== context.path) { - throw new BadRequest(`Schema is for ${baseService} not ${context.path}. (populate)`); - } - - if (permissions && !checkPermissions(context, context.path, permissions, 0)) { - throw new BadRequest('Permissions do not allow this populate. (populate)'); - } - - if (typeof schema1 !== 'object') { - throw new BadRequest('Schema does not resolve to an object. (populate)'); - } - - const include = [].concat((schema1.include || []) as any).map(schema => { - if ('provider' in schema) { - return schema; - } else { - return Object.assign({}, schema, { provider }); - } - }); - - return !include.length ? items : populateItemArray(options1, context, items, include, 0); - }) - .then(items => { - replaceItems(context, items); - return context; - }); - }; -} - -function populateItemArray( - options: any, - context: HookContext, - items: any, - includeSchema: any, - depth: number, -): any { - // 'items' is an item or an array of items - // 'includeSchema' is like [ { nameAs: 'author', ... }, { nameAs: 'readers', ... } ] - - if (items.toJSON || items.toObject) { - throw new BadRequest('Populate requires results to be plain JavaScript objects. (populate)'); - } - - if (!Array.isArray(items)) { - return populateItem(options, context, items, includeSchema, depth + 1); - } - - return Promise.all( - items.map(item => populateItem(options, context, item, includeSchema, depth + 1)), - ); -} - -function populateItem( - options: any, - context: HookContext, - item: any, - includeSchema: any, - depth: number, -): any { - // 'item' is one item - // 'includeSchema' is like [ { nameAs: 'author', ... }, { nameAs: 'readers', ... } ] - - const elapsed: any = {}; - const startAtAllIncludes = new Date().getTime(); - const include = [].concat(includeSchema || []) as any; - if (!Object.prototype.hasOwnProperty.call(item, '_include')) item._include = []; - - return Promise.all( - include.map((childSchema: any) => { - const { query, select, parentField } = childSchema; - - // A related column join is required if neither the query nor select options are provided. - // That requires item[parentField] exist. (The DB handles child[childField] existence.) - if (!query && !select && (!parentField || _get(item, parentField) === undefined)) { - return undefined; - } - - const startAtThisInclude = new Date().getTime(); - return populateAddChild(options, context, item, childSchema, depth).then((result: any) => { - const nameAs = childSchema.nameAs || childSchema.service; - elapsed[nameAs] = getElapsed(options, startAtThisInclude, depth); - - return result; - }); - }), - ).then(children => { - // 'children' is like - // [{ nameAs: 'authorInfo', items: {...} }, { nameAs: readersInfo, items: [{...}, {...}] }] - if (options.profile !== false) { - elapsed.total = getElapsed(options, startAtAllIncludes, depth); - item._elapsed = elapsed; - } - - children.forEach(child => { - if (child) { - _set(item, child.nameAs, child.items); - } - }); - - return item; - }); -} - -function populateAddChild( - options: any, - context: HookContext, - parentItem: any, - childSchema: any, - depth: any, -): any { - /* - @params - 'parentItem' is the item we are adding children to - 'childSchema' is like - { service: 'comments', - permissions: '...', - nameAs: 'comments', - asArray: true, - parentField: 'id', - childField: 'postId', - query: { $limit: 5, $select: ['title', 'content', 'postId'], $sort: { createdAt: -1 } }, - select: (context, parent, depth) => ({ something: { $exists: false }}), - paginate: false, - provider: context.provider, - useInnerPopulate: false, - include: [ ... ] } - @returns { nameAs: string, items: array } - */ - - const { - childField, - paginate, - parentField, - permissions, - query, - select, - service, - useInnerPopulate, - provider, - } = childSchema; - - if (!service) { - throw new BadRequest('Child schema is missing the service property. (populate)'); - } - - // A related column join is required if neither the query nor select options are provided. - if (!query && !select && !(parentField && childField)) { - throw new BadRequest('Child schema is missing parentField or childField property. (populate)'); - } - - if (permissions && !options.checkPermissions(context, service, permissions, depth)) { - throw new BadRequest(`Permissions for ${service} do not allow include. (populate)`); - } - - const nameAs = childSchema.nameAs || service; - if (parentItem._include.indexOf(nameAs) === -1) parentItem._include.push(nameAs); - - return Promise.resolve() - .then(() => (select ? select(context, parentItem, depth) : {})) - .then(selectQuery => { - let sqlQuery = {}; - - if (parentField) { - const parentVal = _get(parentItem, parentField); // will not be undefined - sqlQuery = { [childField]: Array.isArray(parentVal) ? { $in: parentVal } : parentVal }; - } - - const queryObj = Object.assign( - {}, - query, - sqlQuery, - selectQuery, // dynamic options override static ones - ); - - const serviceHandle = context.app.service(service); - - if (!serviceHandle) { - throw new BadRequest(`Service ${service} is not configured. (populate)`); - } - - let paginateObj: any = { paginate: false }; - const paginateOption = paginate; - if (paginateOption === true) { - paginateObj = null; - } - if (typeof paginateOption === 'number') { - paginateObj = { paginate: { default: paginateOption } }; - } - - const params = Object.assign( - {}, - context.params, - paginateObj, - { query: queryObj }, - useInnerPopulate ? {} : { _populate: 'skip' }, - 'provider' in childSchema ? { provider: childSchema.provider } : {}, - ); - - return serviceHandle.find(params); - }) - .then(result => { - result = result.data || result; - - if (result.length === 0) { - return childSchema.asArray ? [] : null; - } - - if (result.length === 1 && !childSchema.asArray) { - result = result[0]; - } - - const include = [].concat(childSchema.include || []).map(schema => { - if ('provider' in schema) { - return schema; - } else { - return Object.assign({}, schema, { provider }); - } - }); - - return childSchema.include && result - ? populateItemArray(options, context, result, include, depth) - : result; - }) - .then(items => ({ nameAs, items })); -} - -// Helpers - -// used process.hrTime before -function milliToNano(num: number) { - return num * 1000000; -} - -function getElapsed(options: PopulateOptions, startTime: number, depth: number) { - if (options.profile === true) { - return milliToNano(new Date().getTime() - startTime + 0.001); - } - - return depth; // for testing _elapsed -} diff --git a/src/hooks/prevent-changes.ts b/src/hooks/prevent-changes.ts deleted file mode 100755 index d921a54c..00000000 --- a/src/hooks/prevent-changes.ts +++ /dev/null @@ -1,41 +0,0 @@ -import _has from 'lodash/has.js'; -import _omit from 'lodash/omit.js'; - -import { checkContext } from '../utils/check-context'; -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Prevent patch service calls from changing certain fields. - * @see https://hooks-common.feathersjs.com/hooks.html#preventchanges - */ -export function preventChanges( - ifThrow: boolean, - ...fieldNames: string[] -) { - if (typeof ifThrow === 'string') { - // eslint-disable-next-line no-console - console.warn('**Deprecated** Use the preventChanges(true, ...fieldNames) syntax instead.'); - fieldNames = [ifThrow, ...fieldNames]; - } - - return (context: H) => { - checkContext(context, 'before', ['patch'], 'preventChanges'); - let data = { ...context.data }; - - fieldNames.forEach(name => { - if (_has(data, name)) { - if (ifThrow) { - throw new BadRequest(`Field ${name} may not be patched. (preventChanges)`); - } - // Delete data.contactPerson.name - // @ts-ignore - data = _omit(data, name); - } - }); - - context.data = data; - - return context; - }; -} diff --git a/src/hooks/prevent-changes/prevent-changes.md b/src/hooks/prevent-changes/prevent-changes.md new file mode 100644 index 00000000..c926ffe2 --- /dev/null +++ b/src/hooks/prevent-changes/prevent-changes.md @@ -0,0 +1,31 @@ +--- +title: preventChanges +description: Prevent patch service calls from changing certain fields. +category: hooks +hook: + type: ['before', 'around'] + method: ['patch'] + multi: true +--- + +## Arguments + +- `{Boolean} ifThrow` +- `{Array < String >} fieldNames` + +| Argument | Type | Default | Description | +| ------------ | :----------: | ------- | ------------------------------------------------------ | +| `ifThrow` | `Boolean` | | Deletes any `fieldNames` if `false`; throws if `true`. | +| `fieldNames` | dot notation | | The fields names which may not be patched. | + +## Example + +```js +const { preventChanges } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { patch: preventChanges(true, 'security.badge') } }; +``` + +## Details + +Consider using validateSchema if you would rather specify which fields are allowed to change. diff --git a/src/hooks/prevent-changes/prevent-changes.test.ts b/src/hooks/prevent-changes/prevent-changes.test.ts new file mode 100755 index 00000000..7e682284 --- /dev/null +++ b/src/hooks/prevent-changes/prevent-changes.test.ts @@ -0,0 +1,93 @@ +import { assert, expect } from 'vitest' +import { preventChanges } from './prevent-changes.js' +import { clone } from '../../common/index.js' + +let hookBefore: any + +describe('preventChanges', () => { + describe('throws if first param is "true"', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'patch', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe', a: { b: undefined, c: { d: { e: 1 } } } }, + } + }) + + it('does not throw if props not found', async () => { + await preventChanges(['name', 'address'], { error: true })(hookBefore) + await preventChanges(['name.x', 'x.y.z'], { error: true })(hookBefore) + }) + + it('throw if props found', async () => { + await expect(() => + preventChanges(['name', 'first'], { error: true })(hookBefore), + ).rejects.toThrow() + await expect(() => + preventChanges(['name', 'a'], { error: true })(hookBefore), + ).rejects.toThrow() + await expect(() => + preventChanges(['name', 'a.b'], { error: true })(hookBefore), + ).rejects.toThrow() + await expect(() => + preventChanges(['name', 'a.c'], { error: true })(hookBefore), + ).rejects.toThrow() + await expect(() => + preventChanges(['name', 'a.c.d.e'], { error: true })(hookBefore), + ).rejects.toThrow() + }) + }) + + describe('deletes if first param is "false"', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'patch', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe', a: { b: 'john', c: { d: { e: 1 } } } }, + } + }) + + it('does not delete if props not found', async () => { + let context: any = await preventChanges(['name', 'address'], { error: false })( + clone(hookBefore), + ) + assert.deepEqual(context, hookBefore) + + context = await preventChanges(['name.x', 'x.y.z'], { error: false })(clone(hookBefore)) + assert.deepEqual(context, hookBefore) + }) + + it('deletes if props found', async () => { + let context: any = await preventChanges(['name', 'first'], { error: false })( + clone(hookBefore), + ) + assert.deepEqual(context.data, { last: 'Doe', a: { b: 'john', c: { d: { e: 1 } } } }, '1') + + context = await preventChanges(['name', 'a'], { error: false })(clone(hookBefore)) + assert.deepEqual(context.data, { first: 'John', last: 'Doe' }, '2') + + context = await preventChanges(['name', 'a.b'], { error: false })(clone(hookBefore)) + assert.deepEqual(context.data, { first: 'John', last: 'Doe', a: { c: { d: { e: 1 } } } }, '3') + + context = await preventChanges(['name', 'a.c'], { error: false })(clone(hookBefore)) + assert.deepEqual(context.data, { first: 'John', last: 'Doe', a: { b: 'john' } }, '4') + + context = await preventChanges(['name', 'a.c.d.e'], { error: false })(clone(hookBefore)) + assert.deepEqual( + context.data, + { first: 'John', last: 'Doe', a: { b: 'john', c: { d: {} } } }, + '5', + ) + + context = await preventChanges(['first', 'last'], { error: false })(clone(hookBefore)) + assert.deepEqual(context.data, { a: { b: 'john', c: { d: { e: 1 } } } }) + + context = await preventChanges(['first', 'a.b', 'a.c.d.e'], { error: false })( + clone(hookBefore), + ) + assert.deepEqual(context.data, { last: 'Doe', a: { c: { d: {} } } }) + }) + }) +}) diff --git a/src/hooks/prevent-changes/prevent-changes.ts b/src/hooks/prevent-changes/prevent-changes.ts new file mode 100755 index 00000000..fd81d4fe --- /dev/null +++ b/src/hooks/prevent-changes/prevent-changes.ts @@ -0,0 +1,40 @@ +import _has from 'lodash/has.js' +import _omit from 'lodash/omit.js' +import type { FeathersError } from '@feathersjs/errors' +import { BadRequest } from '@feathersjs/errors' +import { transformData } from '../transform-data/transform-data.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +export type PreventChangesOptions = { + error?: boolean | ((item: any, name: string) => FeathersError) +} + +/** + * Prevent patch service calls from changing certain fields. + * @see https://hooks-common.feathersjs.com/hooks.html#preventchanges + */ +export const preventChanges = (fieldNames: MaybeArray, options?: PreventChangesOptions) => { + const fieldNamesArr = toArray(fieldNames) + + return transformData(item => { + if (options?.error) { + for (let i = 0; i < fieldNamesArr.length; i++) { + const name = fieldNamesArr[i] + + if (_has(item, name)) { + const error = + typeof options.error === 'function' + ? options.error(item, name) + : new BadRequest(`Field ${name} may not be patched. (preventChanges)`) + + throw error + } + } + } else { + item = _omit(item, fieldNamesArr) + } + + return item + }) +} diff --git a/src/hooks/required.ts b/src/hooks/required.ts deleted file mode 100755 index 24db02c4..00000000 --- a/src/hooks/required.ts +++ /dev/null @@ -1,27 +0,0 @@ -import _get from 'lodash/get.js'; -import { BadRequest } from '@feathersjs/errors'; -import _has from 'lodash/has.js'; - -import { checkContext } from '../utils/check-context'; -import { getItems } from '../utils/get-items'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Check selected fields exist and are not falsey. Numeric 0 is acceptable. - * @see https://hooks-common.feathersjs.com/hooks.html#required - */ -export function required(...fieldNames: string[]) { - return (context: H) => { - checkContext(context, 'before', ['create', 'update', 'patch'], 'required'); - const items = getItems(context); - - (Array.isArray(items) ? items : [items]).forEach(item => { - fieldNames.forEach(name => { - if (!_has(item, name)) throw new BadRequest(`Field ${name} does not exist. (required)`); - const value = _get(item, name); - if (!value && value !== 0 && value !== false) - throw new BadRequest(`Field ${name} is null. (required)`); - }); - }); - }; -} diff --git a/src/hooks/run-parallel/run-parallel.md b/src/hooks/run-parallel/run-parallel.md new file mode 100644 index 00000000..327d2a7a --- /dev/null +++ b/src/hooks/run-parallel/run-parallel.md @@ -0,0 +1,42 @@ +--- +title: runParallel +description: Run a hook in parallel to the other hooks and the service call. +category: hooks +hook: + type: ['before', 'after'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{Function} hookFunc` +- `{Function} clone` +- `{Number} [ depth ]` + +| Argument | Type | Default | Description | +| ---------- | :--------: | :-----: | ------------------------------------------------------------------------------------------------------------------- | +| `hookFunc` | `Function` | | The hook function to run in parallel to the rest of the service call. | +| `clone` | `Function` | | Function to deep clone its only parameter. | +| `depth` | `Number` | 6 | Depth to which `context` is to be cloned. 0 does not clone. A depth of 5 would clone `context.result.data.[].item`. | + +## Example + +```js +const { runParallel } = require('feathers-hooks-common/index.js'); +const clone = require('clone'); + +function sendEmail(...) { + return context => { ... }; +} + +module.exports = { after: { + create: runParallel(sendEmail(...), clone) +} }; +``` + +## Details + +`hookFunc` is scheduled with a `setTimeout`. The next hook starts immediately. + +The hook was provided by bedeoverend. Thank you. diff --git a/test/hooks/run-parallel.test.ts b/src/hooks/run-parallel/run-parallel.test.ts similarity index 51% rename from test/hooks/run-parallel.test.ts rename to src/hooks/run-parallel/run-parallel.test.ts index 719a3fd1..a4640838 100755 --- a/test/hooks/run-parallel.test.ts +++ b/src/hooks/run-parallel/run-parallel.test.ts @@ -1,73 +1,74 @@ -import { assert } from 'vitest'; -import { runParallel } from '../../src'; +import { assert } from 'vitest' +import { runParallel } from './run-parallel.js' -let contextBefore: any; -let that: any; +let contextBefore: any +let that: any function test(tester: any) { return function (this: any, contextCloned: any) { - that = this; - tester(contextCloned); - }; + // eslint-disable-next-line @typescript-eslint/no-this-alias + that = this + tester(contextCloned) + } } describe('services runParallel', () => { beforeEach(() => { - that = undefined; + that = undefined contextBefore = { type: 'before', method: 'create', params: { provider: 'rest' }, data: { first: 'John', last: 'Doe' }, - }; - }); + } + }) it('runs the func', () => new Promise(resolve => { - runParallel(test(tester))(contextBefore); + runParallel(test(tester))(contextBefore) function tester() { - resolve(); + resolve() } - })); + })) it('passes this', () => new Promise(resolve => { - runParallel(test(tester)).call({ bar: true }, contextBefore); + runParallel(test(tester)).call({ bar: true }, contextBefore) function tester() { - assert.strictEqual(that.bar, true); - resolve(); + assert.strictEqual(that.bar, true) + resolve() } - })); + })) it('defaults to uncloned context', () => new Promise(resolve => { - runParallel(test(tester))(contextBefore); - contextBefore._foo = true; + runParallel(test(tester))(contextBefore) + contextBefore._foo = true function tester(contextCloned: any) { - assert.property(contextCloned, '_foo'); - resolve(); + assert.property(contextCloned, '_foo') + resolve() } - })); + })) it('clones', () => new Promise(resolve => { - runParallel(test(tester), structuredClone)(contextBefore); - contextBefore._foo = true; + runParallel(test(tester), structuredClone)(contextBefore) + contextBefore._foo = true function tester(contextCloned: any) { - assert.notProperty(contextCloned, '_foo'); - resolve(); + assert.notProperty(contextCloned, '_foo') + resolve() } - })); + })) it('Throws if no func', () => { assert.throws(() => { - // @ts-expect-error - runParallel()(contextBefore); - }); - }); -}); + // @ts-expect-error TODO + runParallel()(contextBefore) + }) + }) +}) diff --git a/src/hooks/run-parallel.ts b/src/hooks/run-parallel/run-parallel.ts similarity index 62% rename from src/hooks/run-parallel.ts rename to src/hooks/run-parallel/run-parallel.ts index fc837b8a..ca703f74 100755 --- a/src/hooks/run-parallel.ts +++ b/src/hooks/run-parallel/run-parallel.ts @@ -1,6 +1,6 @@ -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import type { HookFunction } from '../types'; +import { BadRequest } from '@feathersjs/errors' +import type { HookContext } from '@feathersjs/feathers' +import type { HookFunction } from '../../types.js' /** * Run a hook in parallel to the other hooks and the service call. @@ -12,13 +12,13 @@ export function runParallel( clone?: (item: H) => H, ) { if (typeof hook !== 'function') { - throw new BadRequest('Function not provided. (runParallel)'); + throw new BadRequest('Function not provided. (runParallel)') } return function (this: any, context: H) { // must use function - const copy = clone ? clone(context) : context; + const copy = clone ? clone(context) : context - setTimeout(() => hook.call(this, copy as any)); - }; + setTimeout(() => hook.call(this, copy as any)) + } } diff --git a/src/hooks/sequelize-convert.ts b/src/hooks/sequelize-convert.ts deleted file mode 100755 index 558eeb4c..00000000 --- a/src/hooks/sequelize-convert.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; - -export interface SequelizeConversion { - js: (sqlValue: any) => any; - sql: (jsValue: any) => any; -} - -export interface SequelizeConverts { - [name: string]: keyof C | 'boolean' | 'date' | 'json'; -} - -const methodsWithBeforeData = ['create', 'update', 'patch']; -const defaultConversions = { - boolean: { - sql: (boolean: any) => (boolean ? 1 : 0), - js: (numb: any) => !!numb, - }, - date: { - sql: (dateNow: any) => dateNow, - js: (sqlDate: any) => new Date(sqlDate).valueOf() || null, - }, - json: { - sql: (obj: any) => JSON.stringify(obj), - js: (str: any) => JSON.parse(str), - }, -}; - -/** - * @see https://hooks-common.feathersjs.com/hooks.html#sequelizeconvert - */ -export function sequelizeConvert< - C extends { [name: string]: SequelizeConversion }, - H extends HookContext = HookContext, ->( - converts: SequelizeConverts | null | undefined | false, - ignores?: string[] | null | undefined | false, - conversions?: C, -) { - const converter = sequelizeConversion(converts, ignores, conversions); - - return (context: H) => { - if (context.type === 'before' && !methodsWithBeforeData.includes(context.method)) - return context; - - const items = getItems(context); - converter(context.type === 'before' ? 'sql' : 'js', items); - replaceItems(context, items); - - return context; - }; -} - -function sequelizeConversion(converts: any, ignores: any, conversions: Record = {}) { - converts = converts || {}; - ignores = ignores || []; - conversions.boolean = conversions.boolean || defaultConversions.boolean; - conversions.date = conversions.date || defaultConversions.date; - conversions.json = conversions.json || defaultConversions.json; - - const props = Object.keys(converts).filter(name => !ignores.includes(name)); - - return (sqlJs: any, recs: any) => { - recs = Array.isArray(recs) ? recs : [recs]; - - recs.forEach((rec: any) => { - props.forEach(name => { - if (name in rec) { - rec[name] = conversions[converts[name].toLowerCase()][sqlJs](rec[name]); - } - }); - }); - }; -} diff --git a/src/hooks/serialize.ts b/src/hooks/serialize.ts deleted file mode 100755 index e9ef09ab..00000000 --- a/src/hooks/serialize.ts +++ /dev/null @@ -1,85 +0,0 @@ -import _get from 'lodash/get.js'; -import _set from 'lodash/set.js'; -import _omit from 'lodash/omit.js'; - -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; -import type { SyncContextFunction } from '../types'; -import type { HookContext } from '@feathersjs/feathers'; - -export interface SerializeSchema { - only?: string | string[]; - exclude?: string | string[]; - computed?: { - [propName: string]: (record: any, context: H) => any; - }; - - [key: string]: - | SerializeSchema - | SerializeSchema['computed'] - | string - | string[] - | undefined; -} - -/** - * Prune values from related records. Calculate new values. - * @see https://hooks-common.feathersjs.com/hooks.html#serialize - */ -export function serialize( - schema1: SerializeSchema | SyncContextFunction, -) { - return (context: H) => { - const schema = typeof schema1 === 'function' ? schema1(context) : schema1; - const schemaDirectives = ['computed', 'exclude', 'only']; - - replaceItems(context, serializeItems(getItems(context), schema)); - return context; - - function serializeItems(items: any, schema: any) { - if (!Array.isArray(items)) { - return serializeItem(items, schema); - } - - return items.map(item => serializeItem(item, schema)); - } - - function serializeItem(item: any, schema: any) { - const computed: Record = {}; - Object.keys(schema.computed || {}).forEach(name => { - computed[name] = schema.computed[name](item, context); // needs closure - }); - - let only = schema.only; - only = typeof only === 'string' ? [only] : only; - if (only) { - const newItem = {}; - only.concat('_include', '_elapsed', item._include || []).forEach((key: any) => { - const value = _get(item, key); - if (value !== undefined) { - _set(newItem, key, value); - } - }); - item = newItem; - } - - let exclude = schema.exclude; - exclude = typeof exclude === 'string' ? [exclude] : exclude; - if (exclude) { - item = _omit(item, exclude); - } - - const _computed = Object.keys(computed); - item = Object.assign({}, item, computed, _computed.length ? { _computed } : {}); - - Object.keys(schema).forEach(key => { - if (!schemaDirectives.includes(key) && typeof item[key] === 'object') { - // needs closure - item[key] = serializeItems(item[key], schema[key]); - } - }); - - return item; - } - }; -} diff --git a/src/hooks/set-field.ts b/src/hooks/set-field.ts deleted file mode 100644 index 80d59081..00000000 --- a/src/hooks/set-field.ts +++ /dev/null @@ -1,50 +0,0 @@ -import _get from 'lodash/get.js'; -import _setWith from 'lodash/setWith.js'; -import _clone from 'lodash/clone.js'; -import _debug from 'debug'; -import { checkContext } from '../utils/check-context'; -import { Forbidden } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; - -export interface SetFieldOptions { - as: string; - from: string; - allowUndefined?: boolean; -} - -const debug = _debug('feathers-hooks-common/setField'); - -/** - * The `setField` hook allows to set a field on the hook context based on the value of another field on the hook context. - * @see https://hooks-common.feathersjs.com/hooks.html#setfield - */ -export function setField({ - as, - from, - allowUndefined = false, -}: SetFieldOptions) { - if (!as || !from) { - throw new Error("'as' and 'from' options have to be set"); - } - - return (context: H) => { - const { params } = context; - - checkContext(context, 'before', null, 'setField'); - - const value = _get(context, from); - - if (value === undefined) { - if (!params.provider || allowUndefined) { - debug(`Skipping call with value ${from} not set`); - return context; - } - - throw new Forbidden(`Expected field ${as} not available`); - } - - debug(`Setting value '${value}' from '${from}' as '${as}'`); - - return _setWith(context, as, value, _clone); - }; -} diff --git a/src/hooks/set-field/set-field.md b/src/hooks/set-field/set-field.md new file mode 100644 index 00000000..17aac04f --- /dev/null +++ b/src/hooks/set-field/set-field.md @@ -0,0 +1,88 @@ +--- +title: setField +description: The `setField` hook allows to set a field on the hook context based on the value of another field on the hook context. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['all'] + multi: true +--- + +### Options + +- `from` _required_ - The property on the hook context to use. Can be an array (e.g. `[ 'params', 'user', 'id' ]`) or a dot separated string (e.g. `'params.user.id'`). +- `as` _required_ - The property on the hook context to set. Can be an array (e.g. `[ 'params', 'query', 'userId' ]`) or a dot separated string (e.g. `'params.query.userId'`). +- `allowUndefined` (default: `false`) - If set to `false`, an error will be thrown if the value of `from` is `undefined` in an external request (`params.provider` is set). On internal calls (or if set to true `true` for external calls) the hook will do nothing. + +> **Important:** This hook should be used after the [authenticate hook](https://docs.feathersjs.com/api/authentication/hook.html#authenticate-options) when accessing user fields (from `params.user`). + +**Note:** When the service enable `multi:true` and `data` is an array data type, this hook may working to an unexpected result + +### Examples + +Limit all external access of the `users` service to the authenticated user: + +> **Note:** For MongoDB, Mongoose and NeDB `params.user.id` needs to be changed to `params.user._id`. For any other custom id accordingly. + +```js +const { authenticate } = require('@feathersjs/authentication'); +const { setField } = require('feathers-hooks-common/index.js'); + +app.service('users').hooks({ + before: { + all: [authenticate('jwt'), setField({ from: 'params.user.id', as: 'params.query.id' })], + }, +}); +``` + +Only allow access to invoices for the users organization: + +```js +const { authenticate } = require('@feathersjs/authentication'); +const { setField } = require('feathers-hooks-common/index.js'); + +app.service('invoices').hooks({ + before: { + all: [ + authenticate('jwt'), + setField({ from: 'params.user.organizationId', as: 'params.query.organizationId' }), + ], + }, +}); +``` + +Set the current user id as `userId` when creating a message and only allow users to edit and remove their own messages: + +```js +const { authenticate } = require('@feathersjs/authentication'); +const { setField } = require('feathers-hooks-common/index.js'); + +const setUserId = setField({ + from: 'params.user.id', + as: 'data.userId' +}); +const limitToUser = setField({ + from: 'params.user.id', + as: 'params.query.userId' +}); + +app.service('messages').hooks({ + before: { + all: [ + authenticate('jwt') + ], + create: [ + setUserId + ], + patch: [ + limitToUser + ], + update: [ + limitToUser + ] + remove: [ + limitToUser + ] + } +}) +``` diff --git a/test/hooks/set-field.test.ts b/src/hooks/set-field/set-field.test.ts similarity index 50% rename from test/hooks/set-field.test.ts rename to src/hooks/set-field/set-field.test.ts index 9c3c6b37..e1a42d7e 100644 --- a/test/hooks/set-field.test.ts +++ b/src/hooks/set-field/set-field.test.ts @@ -1,21 +1,21 @@ -import { assert, expect } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { setField } from '../../src'; +import { assert, expect } from 'vitest' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { setField } from './set-field.js' -import type { Application } from '@feathersjs/feathers'; +import type { Application } from '@feathersjs/feathers' describe('setField', () => { const user = { id: 1, name: 'David', - }; + } - let app: Application; + let app: Application beforeEach(async () => { - app = feathers(); - app.use('/messages', new MemoryService()); + app = feathers() + app.use('/messages', new MemoryService()) app.service('messages').hooks({ before: { all: [ @@ -25,84 +25,57 @@ describe('setField', () => { }), ], }, - }); + }) await app.service('messages').create({ id: 1, text: 'Message 1', userId: 1, - }); + }) await app.service('messages').create({ id: 2, text: 'Message 2', userId: 2, - }); - }); - - it('errors when options not set', () => { - assert.throws(() => - app.service('messages').hooks({ - before: { - // @ts-expect-error - get: setField(), - }, - }), - ); - assert.throws(() => - app.service('messages').hooks({ - before: { - // @ts-expect-error - get: setField({ as: 'me' }), - }, - }), - ); - assert.throws(() => - app.service('messages').hooks({ - before: { - // @ts-expect-error - get: setField({ from: 'you' }), - }, - }), - ); - }); + }) + }) it('find queries with user information, does not modify original objects', async () => { - const query = {}; - // @ts-ignore - const results = await app.service('messages').find({ query, user }); + const query = {} + // @ts-expect-error TODO + const results = await app.service('messages').find({ query, user }) - assert.equal(results.length, 1); - assert.deepEqual(query, {}); - }); + assert.equal(results.length, 1) + assert.deepEqual(query, {}) + }) it('adds user information to get, throws NotFound event if record exists', async () => { await expect(async () => { - // @ts-ignore - await app.service('messages').get(2, { user }); - }).rejects.toThrow(); + // @ts-expect-error TODO + await app.service('messages').get(2, { user }) + }).rejects.toThrow() - // @ts-ignore - const result = await app.service('messages').get(1, { user }); + // @ts-expect-error TODO + const result = await app.service('messages').get(1, { user }) assert.deepEqual(result, { id: 1, text: 'Message 1', userId: 1, - }); - }); + } as any) + }) it('does nothing on internal calls if value does not exists', async () => { - const results = await app.service('messages').find(); + const results = await app.service('messages').find() - assert.equal(results.length, 2); - }); + assert.equal(results.length, 2) + }) it('errors on external calls if value does not exists', async () => { await expect(async () => { await app.service('messages').find({ provider: 'rest', - }); - }).rejects.toThrow(); - }); + }) + }).rejects.toThrow() + }) it('errors when not used as a before hook', async () => { app.service('messages').hooks({ @@ -112,10 +85,10 @@ describe('setField', () => { as: 'params.query.userId', }), }, - }); + }) await expect(async () => { - await app.service('messages').get(1); - }).rejects.toThrow(); - }); -}); + await app.service('messages').get(1) + }).rejects.toThrow() + }) +}) diff --git a/src/hooks/set-field/set-field.ts b/src/hooks/set-field/set-field.ts new file mode 100644 index 00000000..c68629a9 --- /dev/null +++ b/src/hooks/set-field/set-field.ts @@ -0,0 +1,40 @@ +import _get from 'lodash/get.js' +import _setWith from 'lodash/setWith.js' +import _clone from 'lodash/clone.js' +import { checkContext } from '../../utils/index.js' +import { Forbidden } from '@feathersjs/errors' +import type { HookContext, NextFunction } from '@feathersjs/feathers' + +export interface SetFieldOptions { + as: string + from: string + allowUndefined?: boolean +} + +/** + * The `setField` hook allows to set a field on the hook context based on the value of another field on the hook context. + * @see https://hooks-common.feathersjs.com/hooks.html#setfield + */ +export const setField = + ({ as, from, allowUndefined = false }: SetFieldOptions) => + (context: H, next?: NextFunction) => { + const { params } = context + + checkContext(context, ['before', 'around'], null, 'setField') + + const value = _get(context, from) + + if (value === undefined) { + if (!params.provider || allowUndefined) { + return context + } + + throw new Forbidden(`Expected field ${as} not available`) + } + + context = _setWith(context, as, value, _clone) + + if (next) return next() + + return context + } diff --git a/src/hooks/set-now-data/set-now-data.md b/src/hooks/set-now-data/set-now-data.md new file mode 100644 index 00000000..7ef04fd0 --- /dev/null +++ b/src/hooks/set-now-data/set-now-data.md @@ -0,0 +1,28 @@ +--- +title: setNowData +description: Create/update certain fields to the current date-time. +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- + +- Arguments + - `{Array < String >} fieldNames` + +| Name | Type | Description | +| ---------- | ------------ | ---------------------------------------------------------------- | +| fieldNames | dot notation | The fields that you want to add or set to the current date-time. | + +## Example + +```js +const { setNow } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { create: setNow('createdAt', 'updatedAt') } }; +``` + +## Details + +Update either `context.data` (before hook) or `context.result[.data]` (after hook). diff --git a/src/hooks/set-now-data/set-now-data.test.ts b/src/hooks/set-now-data/set-now-data.test.ts new file mode 100755 index 00000000..9a2fe429 --- /dev/null +++ b/src/hooks/set-now-data/set-now-data.test.ts @@ -0,0 +1,135 @@ +import { assert } from 'vitest' +import { setNowData } from './set-now-data.js' + +let hookBefore: any +let hookBefore2: any + +describe('setNowData', () => { + describe('updated fields', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + }) + + it('updates hook before::create', () => { + setNowData('createdAt')(hookBefore) + checkHook(hookBefore.data, { first: 'John', last: 'Doe' }, 'createdAt') + }) + + it('supports field name', () => { + setNowData('createdAt2')(hookBefore) + checkHook(hookBefore.data, { first: 'John', last: 'Doe' }, 'createdAt2') + }) + + it('supports multiple field names', () => { + setNowData(['createdAt1', 'createdAt2'])(hookBefore) + checkHook(hookBefore.data, { first: 'John', last: 'Doe' }, ['createdAt1', 'createdAt2']) + }) + }) + + describe('handles dot notation', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + } + hookBefore2 = { + type: 'before', + method: 'create', + data: { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + created: { where: 'NYC' }, + }, + } + }) + + it('prop with no dots', () => { + setNowData('madeAt')(hookBefore) + checkHook( + hookBefore.data, + { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + 'madeAt', + ) + }) + + it('props with no dots', () => { + setNowData(['madeAt', 'builtAt'])(hookBefore) + checkHook( + hookBefore.data, + { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, + ['madeAt', 'builtAt'], + ) + }) + + it('prop with 1 dot', () => { + setNowData('created.at')(hookBefore) + assert.instanceOf(hookBefore.data.created.at, Date, 'not instance of Date') + assert.equal(Object.keys(hookBefore.data.created).length, 1) + delete hookBefore.data.created + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + + it('prop with 1 dot in existing obj', () => { + setNowData('created.at')(hookBefore2) + assert.instanceOf(hookBefore2.data.created.at, Date, 'not instance of Date') + assert.equal(Object.keys(hookBefore2.data.created).length, 2) + delete hookBefore2.data.created.at + assert.deepEqual(hookBefore2.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + created: { where: 'NYC' }, + }) + }) + + it('prop with 2 dots', () => { + setNowData('created.at.time')(hookBefore) + assert.instanceOf(hookBefore.data.created.at.time, Date, 'not instance of Date') + assert.equal(Object.keys(hookBefore.data.created.at).length, 1) + assert.equal(Object.keys(hookBefore.data.created).length, 1) + delete hookBefore.data.created + assert.deepEqual(hookBefore.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: 'Acct', + }) + }) + }) + + describe('time advances', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + }) + + it('for 2 hooks', () => + new Promise(resolve => { + setNowData('createdAt')(hookBefore) + const firstTime = hookBefore.data.createdAt + + setTimeout(() => { + setNowData('createdAt')(hookBefore) + assert.isAbove(hookBefore.data.createdAt.getTime(), firstTime.getTime()) + resolve() + }, 50) + })) + }) +}) + +// Helpers + +function checkHook(item: any, template: any, dateFields: any) { + const item1 = structuredClone(item) + if (typeof dateFields === 'string') { + dateFields = [dateFields] + } + + dateFields.forEach((dateField: any) => { + assert.instanceOf(item[dateField], Date, 'not instance of Date') + item1[dateField] = undefined + delete item1[dateField] + }) + + assert.deepEqual(item1, template, 'objects differ') +} diff --git a/src/hooks/set-now-data/set-now-data.ts b/src/hooks/set-now-data/set-now-data.ts new file mode 100755 index 00000000..799a8ce5 --- /dev/null +++ b/src/hooks/set-now-data/set-now-data.ts @@ -0,0 +1,21 @@ +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' +import { transformData } from '../transform-data/transform-data.js' +import _set from 'lodash/set.js' + +/** + * Create/update certain fields to the current date-time. + * + * @see https://hooks-common.feathersjs.com/hooks.html#setnow + */ +export const setNowData = (fieldNames: MaybeArray) => { + const fieldNamesArr = toArray(fieldNames) + + return transformData(data => { + for (let i = 0; i < fieldNamesArr.length; i++) { + const key = fieldNamesArr[i] + + _set(data, key, new Date()) + } + }) +} diff --git a/src/hooks/set-now-result/set-now-result.md b/src/hooks/set-now-result/set-now-result.md new file mode 100644 index 00000000..3c5b006f --- /dev/null +++ b/src/hooks/set-now-result/set-now-result.md @@ -0,0 +1,9 @@ +--- + +title: setNowResult +description: Set the current date/time on certain fields in the result. +category: hooks +hook: +type: ['before', 'after', 'around'] +method: ['find', 'get', 'create', 'update', 'patch', 'remove'] +multi: true diff --git a/src/hooks/set-now-result/set-now-result.test.ts b/src/hooks/set-now-result/set-now-result.test.ts new file mode 100755 index 00000000..3dec829a --- /dev/null +++ b/src/hooks/set-now-result/set-now-result.test.ts @@ -0,0 +1,68 @@ +import { assert } from 'vitest' +import { setNowResult } from './set-now-result.js' + +let hookAfter: any +let hookFindPaginate: any +let hookFind: any + +describe('setNowResult', () => { + describe('updated fields', () => { + beforeEach(() => { + hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } } + hookFindPaginate = { + type: 'after', + method: 'find', + result: { + total: 2, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + } + hookFind = { + type: 'after', + method: 'find', + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } + }) + + it('updates hook after::find with pagination', () => { + setNowResult('createdAt')(hookFindPaginate) + + checkHook(hookFindPaginate.result.data[0], { first: 'John', last: 'Doe' }, 'createdAt') + checkHook(hookFindPaginate.result.data[1], { first: 'Jane', last: 'Doe' }, 'createdAt') + }) + + it('updates hook after::find with no pagination', () => { + setNowResult('createdAt')(hookFind) + checkHook(hookFind.result[0], { first: 'John', last: 'Doe' }, 'createdAt') + checkHook(hookFind.result[1], { first: 'Jane', last: 'Doe' }, 'createdAt') + }) + + it('updates hook after', () => { + setNowResult('createdAt')(hookAfter) + checkHook(hookAfter.result, { first: 'Jane', last: 'Doe' }, 'createdAt') + }) + }) +}) + +// Helpers + +function checkHook(item: any, template: any, dateFields: any) { + const item1 = structuredClone(item) + if (typeof dateFields === 'string') { + dateFields = [dateFields] + } + + dateFields.forEach((dateField: any) => { + assert.instanceOf(item[dateField], Date, 'not instance of Date') + item1[dateField] = undefined + delete item1[dateField] + }) + + assert.deepEqual(item1, template, 'objects differ') +} diff --git a/src/hooks/set-now-result/set-now-result.ts b/src/hooks/set-now-result/set-now-result.ts new file mode 100755 index 00000000..602a5165 --- /dev/null +++ b/src/hooks/set-now-result/set-now-result.ts @@ -0,0 +1,29 @@ +import _set from 'lodash/set.js' +import { transformResult } from '../transform-result/transform-result.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' +import type { DispatchOption } from '../../types.js' + +type SetNowResultOptions = { + dispatch?: DispatchOption +} + +/** + * Create/update certain fields to the current date-time. + * + * @see https://hooks-common.feathersjs.com/hooks.html#setnow + */ +export const setNowResult = (fieldNames: MaybeArray, options?: SetNowResultOptions) => { + const fieldNamesArray = toArray(fieldNames) + + return transformResult( + data => { + for (let i = 0, n = fieldNamesArray.length; i < n; i++) { + const key = fieldNamesArray[i] + + _set(data, key, new Date()) + } + }, + { dispatch: options?.dispatch }, + ) +} diff --git a/src/hooks/set-now.ts b/src/hooks/set-now.ts deleted file mode 100755 index 90552147..00000000 --- a/src/hooks/set-now.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import { setFields as _setFields } from '../common'; -import { getItems } from '../utils/get-items'; - -/** - * Create/update certain fields to the current date-time. - * - * @see https://hooks-common.feathersjs.com/hooks.html#setnow - */ -export function setNow(...fieldNames: string[]) { - if (!fieldNames.length) { - throw new BadRequest('Field name is required. (setNow)'); - } - - return (context: H) => { - _setFields(getItems(context), () => new Date(), fieldNames, 'setNow'); - return context; - }; -} diff --git a/src/hooks/set-slug.ts b/src/hooks/set-slug.ts deleted file mode 100755 index d945534c..00000000 --- a/src/hooks/set-slug.ts +++ /dev/null @@ -1,27 +0,0 @@ -import _set from 'lodash/set.js'; -import { GeneralError } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; - -/** - * Fix slugs in URL, e.g. /stores/:storeId. - * - * @see https://hooks-common.feathersjs.com/hooks.html#setslug - */ -export function setSlug(slug: string, fieldName?: string) { - return (context: H) => { - if (typeof fieldName !== 'string') { - fieldName = `query.${slug}`; - } - - if (context.type === 'after') { - throw new GeneralError('Cannot set slug on after hook. (setSlug)'); - } - - if (context.params && context.params.provider === 'rest') { - const value = context.params.route[slug]; - if (typeof value === 'string' && value[0] !== ':') { - _set(context.params, fieldName, value); - } - } - }; -} diff --git a/src/hooks/set-slug/set-slug.md b/src/hooks/set-slug/set-slug.md new file mode 100644 index 00000000..fa6748b7 --- /dev/null +++ b/src/hooks/set-slug/set-slug.md @@ -0,0 +1,42 @@ +--- +title: setSlug +description: Set slugs in URL, e.g. /stores/:storeId. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{String} slug` +- `{String} [ fieldName ]` + +| Argument | Type | Default | Description | +| ----------- | :------: | ------------- | ---------------------------------------------------------------------------------- | +| `slug` | `String` | | The slug as it appears in the route, e.g. `storeId` for`/stores/:storeId/candies`. | +| `fieldName` | `String` | `query[slug]` | The field to contain the slug value. | + +## Example + +```js +const { setSlug } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { all: [hooks.setSlug('storeId')] } }; + +// `context.params.query` will always be normalized, +// e.g. `{ size: 'large', storeId: '123' }` +``` + +## Details + +A service may have a slug in its URL, e.g. `storeId` in `app.use(` `'/stores/:storeId/candies',` `new Service());`. The service gets slightly different values depending on the transport used by the client. + +| transport | `hook.data` `.storeId` | `hook.params` `.query` | code run on client | +| --------- | ---------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- | +| socketio | `undefined` | `{ size: 'large',` `storeId: '123' }` | `candies.create({ name: 'Gummi',qty: 100 },` `{ query: { size: 'large', storeId: '123' } })` | +| rest | `:storeId` | same as above | same as above | +| raw HTTP | `123` | `{ size: 'large' }` | `fetch('/stores/123/candies?size=large', ..` | + +This hook normalizes the difference between the transports. diff --git a/src/hooks/set-slug/set-slug.test.ts b/src/hooks/set-slug/set-slug.test.ts new file mode 100755 index 00000000..95b90643 --- /dev/null +++ b/src/hooks/set-slug/set-slug.test.ts @@ -0,0 +1,53 @@ +import { assert } from 'vitest' + +import { setSlug } from './set-slug.js' + +let hook: any + +describe('services setSlug', () => { + beforeEach(() => { + hook = { type: 'before', method: 'create', params: { provider: 'rest', query: { a: 'a' } } } + }) + + describe('ignore feathers-socketio & feathers-rest clients', () => { + it('ignore feathers-socketio', () => { + hook.params.provider = 'socketio' + setSlug('stockId')(hook) + assert.deepEqual(hook.params.query, { a: 'a' }) + }) + + it('ignore feathers-rest', () => { + hook.params.route = {} + hook.params.route.storeId = ':storeId' + setSlug('stockId')(hook) + assert.deepEqual(hook.params.query, { a: 'a' }) + }) + }) + + describe('handles raw HTTP clients', () => { + it('copies slug to query', () => { + hook.params.route = {} + hook.params.route.storeId = '123' + setSlug('storeId')(hook) + assert.deepEqual(hook.params.query, { a: 'a', storeId: '123' }) + }) + }) + + describe('handles field name', () => { + it('copies slug to query', () => { + hook.params.route = {} + hook.params.route.storeId = '123' + setSlug('storeId', 'slugger')(hook) + assert.equal(hook.params.slugger, '123') + }) + }) + + describe('handles field name with dot notation', () => { + it('copies slug to query', () => { + hook.params.route = {} + hook.params.route.storeId = '123' + setSlug('storeId', 'query.slugger')(hook) + assert.deepEqual(hook.params.query, { a: 'a', slugger: '123' }) + }) + }) +}) diff --git a/src/hooks/set-slug/set-slug.ts b/src/hooks/set-slug/set-slug.ts new file mode 100755 index 00000000..be4cfcf6 --- /dev/null +++ b/src/hooks/set-slug/set-slug.ts @@ -0,0 +1,26 @@ +import _set from 'lodash/set.js' +import type { HookContext, NextFunction } from '@feathersjs/feathers' + +/** + * Fix slugs in URL, e.g. /stores/:storeId. + * + * @see https://hooks-common.feathersjs.com/hooks.html#setslug + */ +export const setSlug = (slug: string, fieldName?: string) => { + if (typeof fieldName !== 'string') { + fieldName = `query.${slug}` + } + + return (context: H, next?: NextFunction) => { + if (context.params && context.params.provider === 'rest') { + const value = context.params.route[slug] + if (typeof value === 'string' && value[0] !== ':') { + _set(context.params, fieldName, value) + } + } + + if (next) return next() + + return context + } +} diff --git a/src/hooks/sifter.ts b/src/hooks/sifter.ts deleted file mode 100755 index ba4f481d..00000000 --- a/src/hooks/sifter.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import type { SyncContextFunction } from '../types'; -import { checkContext } from '../utils/check-context'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; - -export function sifter( - siftFunc: SyncContextFunction<(item: any) => boolean, H>, -) { - return (context: H) => { - checkContext(context, 'after', 'find', 'sifter'); - - if (typeof siftFunc !== 'function') { - throw new BadRequest('The sifter param must be a function. (sifter)'); - } - - const sifter = siftFunc(context); - - if (typeof sifter !== 'function') { - throw new BadRequest('The result of calling the sifter param must be a function. (sifter)'); - } - - replaceItems(context, getItems(context).filter(sifter)); - - return context; - }; -} diff --git a/src/hooks/soft-delete.ts b/src/hooks/soft-delete.ts deleted file mode 100755 index 04551eef..00000000 --- a/src/hooks/soft-delete.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { checkContext } from '../utils/check-context'; - -export type SoftDeleteOptionFunction = ( - context?: H, -) => Promise<{ [key: string]: any }>; - -export interface SoftDeleteOptions { - deletedQuery?: { [key: string]: any } | SoftDeleteOptionFunction; - removeData?: { [key: string]: any } | SoftDeleteOptionFunction; -} - -const defaultQuery = { deleted: { $ne: true } }; -const defaultData = { deleted: true }; -const getValue = (value: any, ...args: any[]) => { - if (typeof value === 'function') { - return Promise.resolve(value(...args)); - } - return Promise.resolve(value); -}; - -/** - * Allow to mark items as deleted instead of removing them. - */ -export function softDelete({ - deletedQuery = defaultQuery, - removeData = defaultData, -}: SoftDeleteOptions = {}) { - return async (context: H) => { - const { service, method, params } = context; - // @ts-ignore - const { disableSoftDelete, query = {} } = params; - - checkContext(context, 'before', null, 'softDelete'); - - if (disableSoftDelete) { - return context; - } - - const deleteQuery = await getValue(deletedQuery, context); - - context.params.query = Object.assign({}, query, deleteQuery); - - if (method === 'remove') { - const data = await getValue(removeData, context); - const result = await service.patch(context.id, data, params); - - context.result = result; - } - - return context; - }; -} diff --git a/src/hooks/soft-delete/soft-delete.md b/src/hooks/soft-delete/soft-delete.md new file mode 100644 index 00000000..3516e01e --- /dev/null +++ b/src/hooks/soft-delete/soft-delete.md @@ -0,0 +1,66 @@ +--- +title: softDelete +description: Flag records as logically deleted instead of physically removing them. Requires a Feathers v4 or later database adapter. +category: hooks +hook: + type: ['before', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- + +## Arguments + +| Argument | Type | Default | Description | | +| -------------- | --------- | ------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------- | +| `deletedQuery` | `Function | Object` | `{ deleted: { $ne: true } }` | An object or async function that takes the query which returns the part of the query to exclude deleted entrie | +| `removeData` | `Function | Object` | `{ deleted: true }` | An object or async function that returns the data used to flag an entry as deleted | + +By default, `softDelete` queries for a `deleted` property not set to `true` (meaning it can either exist or be anything else). + +Setting `params.disableSoftDelete` to `true` allows to skip the `softDelete` hook. + +## Example + +Basic usage: + +```js +const { softDelete } = require('feathers-hooks-common/index.js'); + +// Use standard softDelete which uses `deleted: true` +app.service('people').hooks({ before: { all: [softDelete()] } }); + +// will set `deleted: true` for entry with id 1 +app.service('people').remove(1); + +// Will find all people where `deleted` is not `true` +let people = app.service('people').find(); + +// `get`, `patch`, `update` or `remove` on a deleted entry will throw NotFound +app.service('people').get(1); +``` + +Customizing `deletedQuery` and `removeData` to e.g. use `deletedAt`: + +```js +// Use deletedAt and set when the entry was deleted +app.service('people').hooks({ + before: { + all: [ + hooks.softDelete({ + // context is the normal hook context + deletedQuery: async context => { + return { deletedAt: null }; + }, + removeData: async context => { + return { deletedAt: new Date() }; + }, + }), + ], + create: [ + context => { + context.data.deletedAt = null; + }, + ], + }, +}); +``` diff --git a/src/hooks/soft-delete/soft-delete.test.ts b/src/hooks/soft-delete/soft-delete.test.ts new file mode 100755 index 00000000..5a137019 --- /dev/null +++ b/src/hooks/soft-delete/soft-delete.test.ts @@ -0,0 +1,179 @@ +import { assert, expect } from 'vitest' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { softDelete } from './soft-delete.js' + +const initialUsers = [ + { name: 'Jane Doe', key: 'a' }, + { name: 'Jack Doe', key: 'a' }, + { name: 'Jack Doe', key: 'a', deletedAt: new Date() }, + { name: 'Rick Doe', key: 'b' }, + { name: 'Mick Doe', key: 'b' }, + { name: 'Mick Doe', key: 'b', deletedAt: new Date() }, +] + +describe('softDelete', () => { + let userService: any + + beforeEach(() => { + const app = feathers().use( + '/users', + new MemoryService({ + multi: true, + }), + ) + + userService = app.service('users') + userService.hooks({ + before: { + all: [ + softDelete({ + deletedQuery: { deletedAt: null }, + removeData: { deletedAt: new Date() }, + }), + ], + }, + }) + + userService.create(initialUsers) + }) + + describe('find', () => { + it('does not return deleted items', async () => { + const users = await userService.find() + + assert.deepStrictEqual(users, [ + { name: 'Jane Doe', key: 'a', id: 0 }, + { name: 'Jack Doe', key: 'a', id: 1 }, + { name: 'Rick Doe', key: 'b', id: 3 }, + { name: 'Mick Doe', key: 'b', id: 4 }, + ]) + }) + + it('returns everything with params.disableSoftDelete', async () => { + const users = await userService.find({ + disableSoftDelete: true, + }) + + assert.deepStrictEqual( + users.map((x: any) => x.id), + [0, 1, 2, 3, 4, 5], + ) + }) + }) + + describe('get', () => { + it('returns an undeleted item', async () => { + const user = await userService.get(0) + + assert.deepStrictEqual(user, { + name: 'Jane Doe', + key: 'a', + id: 0, + }) + }) + + it('throws on deleted item', async () => { + await expect(async () => { + await userService.get(2) + }).rejects.toThrow() + }) + + it('returns deleted when params.disableSoftDelete is set', async () => { + const user = await userService.get(2, { + disableSoftDelete: true, + }) + + assert.ok(user.deletedAt) + }) + + it('throws on missing item', async () => { + await expect(async () => { + await userService.get(99) + }).rejects.toThrow() + }) + }) + + describe('update, with id', () => { + it('updates an undeleted item', async () => { + const user = await userService.update(0, { y: 'y' }) + + assert.deepStrictEqual(user, { y: 'y', id: 0 }) + }) + + it.skip('throws on deleted item', async () => { + await expect(async () => { + await userService.update(2, { y: 'y' }) + }).rejects.toThrow() + }) + }) + + describe('patch', () => { + it('patches an undeleted item', async () => { + const user = await userService.patch(0, { y: 'y' }) + + assert.deepStrictEqual(user, { + name: 'Jane Doe', + key: 'a', + id: 0, + y: 'y', + }) + }) + + it('throws on deleted item', async () => { + await expect(() => userService.patch(2, { y: 'y' })).rejects.toThrow() + }) + + it('multi updates on undeleted items', async () => { + const patched = await userService.patch(null, { x: 'x' }) + + assert.deepStrictEqual(patched, [ + { name: 'Jane Doe', key: 'a', id: 0, x: 'x' }, + { name: 'Jack Doe', key: 'a', id: 1, x: 'x' }, + { name: 'Rick Doe', key: 'b', id: 3, x: 'x' }, + { name: 'Mick Doe', key: 'b', id: 4, x: 'x' }, + ]) + }) + }) + + describe('remove, with id', () => { + it('marks item as deleted', async () => { + const user = await userService.remove(0) + + assert.equal(user.id, 0) + assert.equal(!!user.deletedAt, true) + + await expect(() => userService.get(0)).rejects.toThrow() + }) + + it('throws if item already deleted', async () => { + await expect(() => userService.remove(2)).rejects.toThrow() + }) + }) + + describe('remove, without id', () => { + it('marks filtered items as deleted', async () => { + const query = { key: 'a' } + const removedUsers = await userService.remove(null, { query }) + + assert.strictEqual(removedUsers.length, 2) + + const users = await userService.find({ query }) + + assert.strictEqual(users.length, 0) + + const deletedUsers = await userService.find({ + query, + disableSoftDelete: true, + }) + + assert.strictEqual(deletedUsers.length, 3) + }) + + it('handles nothing found', async () => { + const users = await userService.remove(null, { query: { key: 'z' } }) + + assert.strictEqual(users.length, 0) + }) + }) +}) diff --git a/src/hooks/soft-delete/soft-delete.ts b/src/hooks/soft-delete/soft-delete.ts new file mode 100755 index 00000000..d5d8def0 --- /dev/null +++ b/src/hooks/soft-delete/soft-delete.ts @@ -0,0 +1,89 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { checkContext } from '../../utils/index.js' +import type { TransformParamsFn } from '../../types.js' +import { transformParams } from '../../utils/transform-params/transform-params.js' +import type { Promisable } from '../../internal.utils.js' + +export type SoftDeleteOptionFunction = ( + context?: H, +) => Promisable<{ [key: string]: any }> + +export interface SoftDeleteOptions { + /** + * @example { deletedAt: null } + */ + deletedQuery: { [key: string]: any } | SoftDeleteOptionFunction + /** + * @example { deletedAt: new Date() } + */ + removeData: { [key: string]: any } | SoftDeleteOptionFunction + /** + * Transform the params before calling the service method. E.g. remove 'params.provider' or add custom params. + */ + transformParams?: TransformParamsFn + + /** + * Key in `params` to disable the soft delete functionality. + * + * @default 'disableSoftDelete' + */ + disableSoftDeleteKey?: string +} + +/** + * Allow to mark items as deleted instead of removing them. + */ +export const softDelete = (options: SoftDeleteOptions) => { + if (!options?.deletedQuery || !options?.removeData) { + throw new Error( + 'You must provide `deletedQuery` and `removeData` options to the softDelete hook.', + ) + } + + return async (context: H, next?: NextFunction) => { + checkContext(context, ['before', 'around'], null, 'softDelete') + + const { disableSoftDeleteKey = 'disableSoftDelete' } = options + + if (context.params[disableSoftDeleteKey]) { + return context + } + + const { deletedQuery, removeData } = options + + const deleteQuery = await getValue(deletedQuery, context) + + const params = transformParams( + { + ...context.params, + query: { + ...context.params.query, + ...deleteQuery, + }, + }, + options.transformParams, + ) + + context.params = params + + if (context.method === 'remove') { + const data = await getValue(removeData, context) + const result = await context.service.patch(context.id, data, params) + + context.result = result + } + + if (next) { + await next() + } + + return context + } +} + +const getValue = (value: any, ...args: any[]) => { + if (typeof value === 'function') { + return value(...args) + } + return value +} diff --git a/src/hooks/stash-before.ts b/src/hooks/stash-before.ts deleted file mode 100755 index c535c0d6..00000000 --- a/src/hooks/stash-before.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import { checkContext } from '../utils/check-context'; - -/** - * Stash current value of record, usually before mutating it. Performs a get call. - * @see https://hooks-common.feathersjs.com/hooks.html#stashbefore - */ -export function stashBefore(fieldName?: string) { - const beforeField = fieldName || 'before'; - - return (context: H) => { - checkContext(context, 'before', ['get', 'update', 'patch', 'remove'], 'stashBefore'); - - // @ts-ignore - if (context.params.disableStashBefore) { - return context; - } - - if ((context.id === null || context.id === undefined) && !context.params.query) { - throw new BadRequest('Id is required. (stashBefore)'); - } - - const params = - context.method === 'get' - ? context.params - : { - provider: context.params.provider, - // @ts-ignore - authenticated: context.params.authenticated, - // @ts-ignore - user: context.params.user, - }; - - return context.service - .get(context.id, { - ...params, - // @ts-ignore - query: params.query || {}, - // @ts-ignore - disableStashBefore: true, - }) - .then((data: any) => { - // @ts-ignore - context.params[beforeField] = JSON.parse(JSON.stringify(data)); - return context; - }) - .catch(() => context); - }; -} diff --git a/src/hooks/stash-before/stash-before.md b/src/hooks/stash-before/stash-before.md new file mode 100644 index 00000000..c230791c --- /dev/null +++ b/src/hooks/stash-before/stash-before.md @@ -0,0 +1,37 @@ +--- +title: stashBefore +description: Stash current value of record, usually before mutating it. Performs a get call. +category: hooks +hook: + type: ['before', 'around'] + method: ['get', 'update', 'patch', 'remove'] + multi: true +--- + +## Arguments + +- `{String} fieldName` + +| Argument | Type | Default | Description | +| ----------- | :--: | ---------- | ------------------------------------------------------------------------------ | +| `fieldName` | | `'before'` | The name of the `context.params` property to contain the current record value. | + +## Example + +```js +const { stashBefore } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { patch: stashBefore() } }; +``` + +## Details + +The hook performs its own preliminary `get` call. If the original service call is also a `get`, its `context.params` is used for the preliminary `get`. The preliminary `get` will be skipped if `params.disableStashBefore` is truthy. + +For any other method the calling params are formed from the original calling context: + +```js +{ provider: context.params.provider, + authenticated: context.params.authenticated, + user: context.params.user } +``` diff --git a/src/hooks/stash-before/stash-before.test.ts b/src/hooks/stash-before/stash-before.test.ts new file mode 100755 index 00000000..db788e99 --- /dev/null +++ b/src/hooks/stash-before/stash-before.test.ts @@ -0,0 +1,120 @@ +import { assert, expect } from 'vitest' +import type { Application } from '@feathersjs/feathers' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { stashBefore } from './stash-before.js' +import { clone } from '../../common/index.js' + +const startId = 6 +const storeInit = { + 0: { name: 'Jane Doe', key: 'a', id: 0 }, + 1: { name: 'Jack Doe', key: 'a', id: 1 }, + 2: { name: 'John Doe', key: 'a', id: 2 }, + 3: { name: 'Rick Doe', key: 'b', id: 3 }, + 4: { name: 'Dick Doe', key: 'b', id: 4 }, + 5: { name: 'Dork Doe', key: 'b', id: 5 }, +} + +let store +let finalParams: any +let innerCallParams: any + +function services(app: Application) { + app.configure(users) +} + +function users(app: Application) { + store = clone(storeInit) + + app.use( + 'users', + new MemoryService({ + store, + startId, + multi: true, + }), + ) + + app.service('users').hooks({ + before: { + all: [ + (context: any) => { + if (context.params.disableStashBefore === true) { + innerCallParams = context.params + } + }, + stashBefore(), + (context: any) => { + finalParams = context.params + }, + ], + }, + }) +} + +describe('stash-before', () => { + let app: Application<{ users: MemoryService }> + let users: any + + beforeEach(() => { + innerCallParams = finalParams = null + + app = feathers().configure(services) + + users = app.service('users') + }) + + it(`stashes on 'update'`, async () => { + await users.update(0, {}) + + assert.deepEqual(finalParams.before, storeInit[0]) + }) + + it(`stashes on 'patch'`, async () => { + await users.patch(0, {}) + + assert.deepEqual(finalParams.before, storeInit[0]) + }) + + it(`stashes on 'remove'`, async () => { + await users.remove(0) + + assert.deepEqual(finalParams.before, storeInit[0]) + }) + + it("throws on 'create'", async () => { + await expect(users.create({})).rejects.toThrow() + }) + + it("throws on 'find'", async () => { + await expect(users.find({})).rejects.toThrow() + }) + + it("throws on 'get'", async () => { + await expect(users.get(0)).rejects.toThrow() + }) + + it('stashes on patch with custom params', async () => { + await users.patch(0, {}, { provider: 'socketio', eyecatcher: -1 }) + + assert.equal(finalParams.provider, 'socketio') + assert.equal(finalParams.eyecatcher, -1) + + assert.equal(innerCallParams.provider, 'socketio') + assert.property(innerCallParams, 'eyecatcher') + }) + + it('stashes multi patch', async () => { + const items = [storeInit[0], storeInit[1], storeInit[2]] + await users.patch(null, { key: 'c' }, { query: { id: { $in: items.map(x => x.id) } } }) + + assert.deepEqual(finalParams.before, items) + }) + + it('stashes multi remove', async () => { + const items = [storeInit[0], storeInit[1], storeInit[2]] + await users.remove(null, { query: { id: { $in: items.map(x => x.id) } } }) + + assert.deepEqual(finalParams.before, items) + }) +}) diff --git a/src/hooks/stash-before/stash-before.ts b/src/hooks/stash-before/stash-before.ts new file mode 100755 index 00000000..d3e23eb4 --- /dev/null +++ b/src/hooks/stash-before/stash-before.ts @@ -0,0 +1,41 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { checkContext } from '../../utils/index.js' + +/** + * Stash current value of record, usually before mutating it. Performs a get call. + * @see https://hooks-common.feathersjs.com/hooks.html#stashbefore + */ +export function stashBefore(fieldName?: string) { + const beforeField = fieldName || 'before' + + return async (context: H, next?: NextFunction) => { + if (context.params.disableStashBefore) { + return context + } + + checkContext(context, ['before', 'around'], ['update', 'patch', 'remove'], 'stashBefore') + + const isMulti = context.id == null + + const params = { + ...context.params, + disableStashBefore: true, + ...(isMulti ? { paginate: false } : {}), + } + + await (!isMulti ? context.service.get(context.id, params) : context.service.find(params)) + .then((result: any) => { + context.params[beforeField] = result + return context + }) + .catch(() => { + return context + }) + + if (next) { + return await next() + } + + return context + } +} diff --git a/src/hooks/throw-if-is-multi/throw-if-is-multi.md b/src/hooks/throw-if-is-multi/throw-if-is-multi.md new file mode 100644 index 00000000..4430acfe --- /dev/null +++ b/src/hooks/throw-if-is-multi/throw-if-is-multi.md @@ -0,0 +1,9 @@ +--- +title: throwIfIsMulti +description: Throw an error if the hook is called with multiple records. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- diff --git a/src/hooks/throw-if-is-multi/throw-if-is-multi.test.ts b/src/hooks/throw-if-is-multi/throw-if-is-multi.test.ts new file mode 100644 index 00000000..c1d9812f --- /dev/null +++ b/src/hooks/throw-if-is-multi/throw-if-is-multi.test.ts @@ -0,0 +1,146 @@ +import { BadRequest } from '@feathersjs/errors' +import { throwIfIsMulti } from './throw-if-is-multi.js' +import type { HookContext } from '@feathersjs/feathers' + +describe('throwIfIsMulti', () => { + describe('general', () => { + it('does not throw on find', async () => { + const context = { + method: 'find', + params: { query: { name: 'item1' } }, + } as HookContext + + await throwIfIsMulti()(context) + }) + + it('does not throw on get', async () => { + const context = { + method: 'get', + id: 'item1', + } as HookContext + await throwIfIsMulti()(context) + }) + + it('does not throw on single create', async () => { + const context = { + method: 'create', + data: { name: 'item1' }, + } as HookContext + + await throwIfIsMulti()(context) + }) + + it('does not throw on single update', async () => { + const context = { + method: 'update', + id: 'item1', + data: { name: 'item1' }, + } as HookContext + + await throwIfIsMulti()(context) + }) + + it('does not throw on single patch', async () => { + const context = { + method: 'patch', + id: 'item1', + data: { name: 'item1' }, + } as HookContext + + await throwIfIsMulti()(context) + }) + + it('does not throw on single remove', async () => { + const context = { + method: 'remove', + id: 'item1', + } as HookContext + + await throwIfIsMulti()(context) + }) + }) + + it('throws on multi create by default', async () => { + const context = { + method: 'create', + data: [{ name: 'item1' }, { name: 'item2' }], + } as HookContext + + await expect(() => throwIfIsMulti()(context)).rejects.toThrow(BadRequest) + }) + + it('throws on multi patch by default', async () => { + const context = { + method: 'patch', + id: null, + data: { name: 'item1' }, + } as any as HookContext + + await expect(() => throwIfIsMulti()(context)).rejects.toThrow(BadRequest) + }) + + it('throws on multi remove by default', async () => { + const context = { + method: 'remove', + id: null, + } as any as HookContext + + await expect(() => throwIfIsMulti()(context)).rejects.toThrow(BadRequest) + }) + + describe('with filter', () => { + it('filter function has context as argument', async () => { + const filterFn = vi.fn(() => true) + const context = { + method: 'create', + data: [{ name: 'item1' }, { name: 'item2' }], + } as HookContext + await expect(() => throwIfIsMulti({ filter: filterFn })(context)).rejects.toThrow(BadRequest) + expect(filterFn).toHaveBeenCalledWith(context) + }) + + it('does not throw on multi create if filter returns false', async () => { + const context = { + method: 'create', + data: [{ name: 'item1' }, { name: 'item2' }], + } as HookContext + + await expect(() => throwIfIsMulti()(context)).rejects.toThrow(BadRequest) + + // sync + await expect( + throwIfIsMulti({ + filter: () => false, + })(context), + ).resolves.not.toThrow() + + // async + await expect( + throwIfIsMulti({ + filter: async () => false, + })(context), + ).resolves.not.toThrow() + }) + + it('throws on multi create if filter returns true', async () => { + const context = { + method: 'create', + data: [{ name: 'item1' }, { name: 'item2' }], + } as HookContext + + // sync + await expect(() => + throwIfIsMulti({ + filter: () => true, + })(context), + ).rejects.toThrow() + + // async + await expect(() => + throwIfIsMulti({ + filter: async () => true, + })(context), + ).rejects.toThrow() + }) + }) +}) diff --git a/src/hooks/throw-if-is-multi/throw-if-is-multi.ts b/src/hooks/throw-if-is-multi/throw-if-is-multi.ts new file mode 100644 index 00000000..eb68c46b --- /dev/null +++ b/src/hooks/throw-if-is-multi/throw-if-is-multi.ts @@ -0,0 +1,23 @@ +import type { HookContext } from '@feathersjs/feathers' +import type { PredicateFn } from '../../types.js' +import { type FeathersError } from '@feathersjs/errors' +import { every, isMulti } from '../../predicates/index.js' +import { throwIf } from '../throw-if/throw-if.js' + +export type ThrowIfIsMultiOptions = { + filter?: PredicateFn + error?: (context: HookContext) => FeathersError +} + +export const throwIfIsMulti = ( + options?: ThrowIfIsMultiOptions, +) => + throwIf( + every( + every(isMulti, context => context.method !== 'find'), + options?.filter, + ), + { + error: options?.error, + }, + ) diff --git a/src/hooks/throw-if-is-provider/throw-if-is-provider.md b/src/hooks/throw-if-is-provider/throw-if-is-provider.md new file mode 100644 index 00000000..7c0dbfaf --- /dev/null +++ b/src/hooks/throw-if-is-provider/throw-if-is-provider.md @@ -0,0 +1,9 @@ +--- +title: throwIfIsProvider +description: Throw an error if the hook is called with a specific provider. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- diff --git a/src/hooks/throw-if-is-provider/throw-if-is-provider.test.ts b/src/hooks/throw-if-is-provider/throw-if-is-provider.test.ts new file mode 100644 index 00000000..c1ef8bf9 --- /dev/null +++ b/src/hooks/throw-if-is-provider/throw-if-is-provider.test.ts @@ -0,0 +1,37 @@ +import type { HookContext } from '@feathersjs/feathers' +import { throwIfIsProvider } from './throw-if-is-provider.js' +import { MethodNotAllowed } from '@feathersjs/errors' + +describe('throwIfIsProvider', () => { + it('should throw if provider matches', async () => { + const context = { + method: 'create', + params: { provider: 'rest' }, + } as HookContext + + await expect(() => throwIfIsProvider(['rest', 'socketio'])(context)).rejects.toThrow( + MethodNotAllowed, + ) + }) + + it('should not throw on provider mismatch', async () => { + const context = { + method: 'create', + params: { provider: 'rest' }, + } as HookContext + await expect(throwIfIsProvider(['socketio'])(context)).resolves.not.toThrow() + }) + + it('can use options.filter', async () => { + const context = { + method: 'create', + params: { provider: 'rest' }, + } as HookContext + + await expect( + throwIfIsProvider(['rest', 'socketio'], { + filter: ctx => ctx.method === 'find', + })(context), + ).resolves.not.toThrow("Provider 'rest' can not call 'create'.") + }) +}) diff --git a/src/hooks/throw-if-is-provider/throw-if-is-provider.ts b/src/hooks/throw-if-is-provider/throw-if-is-provider.ts new file mode 100644 index 00000000..4d7f6caa --- /dev/null +++ b/src/hooks/throw-if-is-provider/throw-if-is-provider.ts @@ -0,0 +1,25 @@ +import type { HookContext } from '@feathersjs/feathers' +import type { PredicateFn, TransportName } from '../../types.js' +import type { ThrowIfOptions } from '../throw-if/throw-if.js' +import { throwIf } from '../throw-if/throw-if.js' +import { toArray } from 'lodash' +import { every, isProvider } from '../../predicates/index.js' +import { MethodNotAllowed } from '@feathersjs/errors' + +const defaultError = (context: HookContext) => + new MethodNotAllowed(`Provider '${context.params.provider}' can not call '${context.method}'.`) + +export type ThrowIfIsIsProviderOptions = ThrowIfOptions & { + filter?: PredicateFn +} + +export const throwIfIsProvider = ( + transports: TransportName | TransportName[], + options?: ThrowIfIsIsProviderOptions, +) => { + const disallowTransports = toArray(transports) + + return throwIf(every(isProvider(...(disallowTransports as any)), options?.filter), { + error: options?.error ?? defaultError, + }) +} diff --git a/src/hooks/throw-if/throw-if.md b/src/hooks/throw-if/throw-if.md new file mode 100644 index 00000000..56b35554 --- /dev/null +++ b/src/hooks/throw-if/throw-if.md @@ -0,0 +1,9 @@ +--- +title: throwIf +description: Throw an error if the hook is called with certain conditions. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['create', 'update', 'patch'] + multi: true +--- diff --git a/src/hooks/throw-if/throw-if.test.ts b/src/hooks/throw-if/throw-if.test.ts new file mode 100644 index 00000000..e3c46e97 --- /dev/null +++ b/src/hooks/throw-if/throw-if.test.ts @@ -0,0 +1,23 @@ +import { BadRequest, GeneralError } from '@feathersjs/errors' +import { throwIf } from './throw-if.js' +import type { HookContext } from '@feathersjs/feathers' + +describe('throwIf', () => { + it('throws BadRequest if no error function is provided', async () => { + await expect(() => throwIf(() => true)({} as HookContext)).rejects.toThrow(BadRequest) + }) + + it('should throw an error if the predicate returns true', async () => { + await expect(() => + throwIf(() => true, { error: () => new GeneralError('Test error') })({} as HookContext), + ).rejects.toThrow(GeneralError) + }) + + it('async predicate should throw an error if it returns true', async () => { + await expect(() => + throwIf(async () => true, { error: () => new GeneralError('Async test error') })( + {} as HookContext, + ), + ).rejects.toThrow(GeneralError) + }) +}) diff --git a/src/hooks/throw-if/throw-if.ts b/src/hooks/throw-if/throw-if.ts new file mode 100644 index 00000000..3607ac67 --- /dev/null +++ b/src/hooks/throw-if/throw-if.ts @@ -0,0 +1,27 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { PredicateFn } from '../../types.js' +import { BadRequest } from '@feathersjs/errors' +import type { FeathersError } from '@feathersjs/errors' + +export type ThrowIfOptions = { + error?: (context: HookContext) => FeathersError +} + +export const throwIf = ( + predicate: PredicateFn, + options?: ThrowIfOptions, +) => { + return async (context: H, next?: NextFunction) => { + const result = await predicate(context) + + if (result) { + throw options?.error ? options.error(context) : new BadRequest('Invalid operation') + } + + if (next) { + await next() + } + + return context + } +} diff --git a/src/hooks/transform-data/transform-data.md b/src/hooks/transform-data/transform-data.md new file mode 100644 index 00000000..163ff5ee --- /dev/null +++ b/src/hooks/transform-data/transform-data.md @@ -0,0 +1,81 @@ +--- +title: transformData +description: Make changes to data or result items. Very flexible. +category: hooks +hook: + type: ['before', 'around'] + method: ['create', 'update', 'patch', 'remove'] + multi: true + source: +--- + +## Arguments + +- `{Function} func` + +| Argument | Type | Default | Description | +| -------- | :--------: | --------------------------- | --------------------------------------------- | +| `func` | `Function` | `(item,` `context) =>` `{}` | Function modifies `item` in place. See below. | + +- **returns** + +The mutated `item`. Returning `undefined` means the `item` in the parameters was mutated in place. returns result `undefined || item` + +## Example + +```js +const { alterItems } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { + all: [ + alterItems(rec => { delete rec.password; }) // Like `discard('password')`. + alterItems(rec => rec.email = email.lowerCase()), // Like `lowerCase('email')`. + ], +} }; +``` + +Async mutations can be handled with async/await: + +```js +alterItems(rec => { + rec.userRecord = (async () => await service.get(...) )() +}) +``` + +You can also perform async mutations using Promises by returning a Promise that is resolved once all mutations are complete: + +```js +alterItems(rec => new Promise(resolve => { + service.get(...).then(result => { + rec.userRecord = result; + resolve(); +}}); +``` + +You can also perform async mutations using Promises by returning a Promise that is resolved once all mutations are complete: + +```js +alterItems(async rec => { + rec.userRecord = await service.get(...); +}) +``` + +## Details + +The declarative nature of most of the common hooks, e.g. `discard('password')`, requires you to remember the names of a fair number of hooks, their parameters, and any possible nuances. + +The `alterItems` hook offers an imperative alternative where you directly alter the items. It allows you to reduce the number of trivial hooks you have to register, and you are aware of exactly what your `alterItems` hooks do. + +`func` is called for each item in `context.data` (before hook) or `context.result[.data]` (after hook). It receives the parameters + +- `{Object} item` +- `{Object} context` + +| Argument | Type | Description | +| --------- | :------: | ---------------------------------------------------------------------- | +| `item` | `Object` | The item. The function modifies it in place. | +| `context` | `Object` | The current context. It contains any alterations made to items so far. | + +- **Returns** + + `func` may alternatively return a replacement `item` rather than `undefined`. This is a convenience feature which permits, for example, use of functions from the [Lodash](https://lodash.com/) library, as such functions tend to return new objects. diff --git a/src/hooks/transform-data/transform-data.test.ts b/src/hooks/transform-data/transform-data.test.ts new file mode 100755 index 00000000..4b4f375d --- /dev/null +++ b/src/hooks/transform-data/transform-data.test.ts @@ -0,0 +1,94 @@ +import { assert } from 'vitest' +import { transformData } from './transform-data.js' + +let hookBefore: any +let hookCreateMulti: any + +describe('transformData', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe' }, + } + hookCreateMulti = { + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } + }) + + it('context is 2nd param', () => { + let contextParam + transformData((_rec: any, context: any) => { + contextParam = context + })(hookBefore) + assert.deepEqual(contextParam, hookBefore) + }) + + it('updates hook before::create', () => { + transformData((rec: any) => { + rec.state = 'UT' + })(hookBefore) + assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }) + }) + + it('updates hook before::create::multi', () => { + transformData((rec: any) => { + rec.state = 'UT' + })(hookCreateMulti) + assert.deepEqual(hookCreateMulti.data, [ + { first: 'John', last: 'Doe', state: 'UT' }, + { first: 'Jane', last: 'Doe', state: 'UT' }, + ]) + }) + + it('updates hook before::create with new item returned', () => { + transformData((rec: any) => Object.assign({}, rec, { state: 'UT' }))(hookBefore) + assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }) + }) + + it('returns a promise that contains context', async () => { + const promise = transformData((rec: any) => { + rec.state = 'UT' + return Promise.resolve() + })(hookBefore) + + assert.ok(promise instanceof Promise) + + const result = await promise + + assert.deepEqual(result, hookBefore) + }) + + it('updates hook before::create with new item returned', async () => { + await transformData((rec: any) => Promise.resolve(Object.assign({}, rec, { state: 'UT' })))( + hookBefore, + ) + + assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }) + }) + + it('updates hook before::create async', async () => { + const alterFunc = (rec: any) => { + rec.state = 'UT' + return Promise.resolve() + } + await transformData(alterFunc)(hookBefore) + + assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }) + }) + + it('updates hook before::create async with new item returned', async () => { + const alterFunc = (rec: any) => Promise.resolve(Object.assign({}, rec, { state: 'UT' })) + + await transformData(alterFunc)(hookBefore) + + assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }) + }) +}) diff --git a/src/hooks/transform-data/transform-data.ts b/src/hooks/transform-data/transform-data.ts new file mode 100755 index 00000000..687b9f74 --- /dev/null +++ b/src/hooks/transform-data/transform-data.ts @@ -0,0 +1,27 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { replaceData } from '../../utils/replace-data/replace-data.js' +import { isPromise } from '../../common/index.js' + +/** + * Make changes to data items. Very flexible. + * @see https://hooks-common.feathersjs.com/hooks.html#alteritems + */ +export const transformData = + (cb: (record: T, context: H) => any) => + async (context: H, next?: NextFunction) => { + await replaceData(context, (item: any) => { + const result = cb(item, context) + + if (isPromise(result)) { + return result.then((res: any) => res ?? item) + } else { + return result ?? item + } + }) + + if (next) { + return next() + } + + return context + } diff --git a/src/hooks/transform-result/transform-result.md b/src/hooks/transform-result/transform-result.md new file mode 100644 index 00000000..6448ee93 --- /dev/null +++ b/src/hooks/transform-result/transform-result.md @@ -0,0 +1,9 @@ +--- +title: transformResult +description: Transform the result of a service method. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- diff --git a/src/hooks/transform-result/transform-result.test.ts b/src/hooks/transform-result/transform-result.test.ts new file mode 100755 index 00000000..7988ff99 --- /dev/null +++ b/src/hooks/transform-result/transform-result.test.ts @@ -0,0 +1,204 @@ +import { assert } from 'vitest' +import { transformResult } from './transform-result.js' +import type { HookContext } from '@feathersjs/feathers' + +let hookAfter: any +let hookFindPaginate: any +let hookFind: any + +describe('transformResult', () => { + beforeEach(() => { + hookAfter = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane', last: 'Doe' }, + } + hookFindPaginate = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: { + total: 2, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + }, + } + hookFind = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } + }) + + it('updates hook after::find with pagination', () => { + transformResult((rec: any) => { + delete rec.last + })(hookFindPaginate) + + assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after::find with no pagination', () => { + transformResult((rec: any) => { + rec.new = rec.first + })(hookFind) + + assert.deepEqual(hookFind.result, [ + { first: 'John', last: 'Doe', new: 'John' }, + { first: 'Jane', last: 'Doe', new: 'Jane' }, + ]) + }) + + it('updates hook after', () => { + transformResult((rec: any) => { + rec.new = rec.first + })(hookAfter) + + assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }) + }) + + it('updates hook after::find with pagination with new item returned', () => { + transformResult((rec: any) => Object.assign({}, { first: rec.first }))(hookFindPaginate) + + assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after::find with pagination with new item returned', () => { + transformResult((rec: any) => Object.assign({}, rec, { new: rec.first }))(hookFind) + + assert.deepEqual(hookFind.result, [ + { first: 'John', last: 'Doe', new: 'John' }, + { first: 'Jane', last: 'Doe', new: 'Jane' }, + ]) + }) + + it('updates hook after with new item returned', () => { + transformResult((rec: any) => Object.assign({}, rec, { new: rec.first }))(hookAfter) + + assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }) + }) + + it('updates hook after::create', async () => { + await transformResult((rec: any) => { + rec.new = rec.first + return Promise.resolve() + })(hookAfter) + + assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }) + }) + + it('updates hook after::create with new item returned', async () => { + await transformResult((rec: any) => + Promise.resolve(Object.assign({}, rec, { new: rec.first })), + )(hookAfter) + + assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }) + }) + + it('updates hook after::find with pagination', async () => { + await transformResult((rec: any) => { + delete rec.last + return Promise.resolve() + })(hookFindPaginate) + + assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after::find with no pagination', async () => { + await transformResult((rec: any) => { + rec.new = rec.first + return Promise.resolve() + })(hookFind) + + assert.deepEqual(hookFind.result, [ + { first: 'John', last: 'Doe', new: 'John' }, + { first: 'Jane', last: 'Doe', new: 'Jane' }, + ]) + }) + + it('updates hook after::find with pagination with new item returned', async () => { + await transformResult((rec: any) => Promise.resolve(Object.assign({}, { first: rec.first })))( + hookFindPaginate, + ) + + assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]) + }) + + it('updates hook after::find with no pagination with new item returned', async () => { + await transformResult((rec: any) => + Promise.resolve(Object.assign({}, rec, { new: rec.first })), + )(hookFind) + + assert.deepEqual(hookFind.result, [ + { first: 'John', last: 'Doe', new: 'John' }, + { first: 'Jane', last: 'Doe', new: 'Jane' }, + ]) + }) + + it('updates dispatch', () => { + const context = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane', last: 'Doe' }, + dispatch: { first: 'Jack', last: 'Doe' }, + } as HookContext + + transformResult( + (rec: any) => { + rec.new = rec.first + }, + { dispatch: true }, + )(context) + + assert.deepEqual(context.result, { first: 'Jane', last: 'Doe' }) + assert.deepEqual(context.dispatch, { first: 'Jack', last: 'Doe', new: 'Jack' }) + }) + + it('updates dispatch even though it is not defined', () => { + const context = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane', last: 'Doe' }, + dispatch: undefined, + } as HookContext + + transformResult( + (rec: any) => { + rec.new = rec.first + }, + { dispatch: true }, + )(context) + + assert.deepEqual(context.result, { first: 'Jane', last: 'Doe' }) + assert.deepEqual(context.dispatch, { first: 'Jane', last: 'Doe', new: 'Jane' }) + }) + + it('updates dispatch and result', () => { + const context = { + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane', last: 'Doe' }, + dispatch: { first: 'Jack', last: 'Doe' }, + } as HookContext + + transformResult( + (rec: any) => { + rec.new = rec.first + }, + { dispatch: 'both' }, + )(context) + + assert.deepEqual(context.result, { first: 'Jane', last: 'Doe', new: 'Jane' }) + assert.deepEqual(context.dispatch, { first: 'Jack', last: 'Doe', new: 'Jack' }) + }) +}) diff --git a/src/hooks/transform-result/transform-result.ts b/src/hooks/transform-result/transform-result.ts new file mode 100755 index 00000000..88b64aeb --- /dev/null +++ b/src/hooks/transform-result/transform-result.ts @@ -0,0 +1,35 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { isPromise } from '../../common/index.js' +import { replaceResult } from '../../utils/replace-result/replace-result.js' +import type { DispatchOption } from '../../types.js' + +export type TransformResultOptions = { + dispatch?: DispatchOption +} + +/** + * Make changes to result items. Very flexible. + * @see https://hooks-common.feathersjs.com/hooks.html#alteritems + */ +export const transformResult = + ( + cb: (record: T, context: H) => any, + options?: TransformResultOptions, + ) => + (context: H, next?: NextFunction) => + replaceResult( + context, + (item: any) => { + const result = cb(item, context) + + if (isPromise(result)) { + return result.then((res: any) => res ?? item) + } else { + return result ?? item + } + }, + { + next, + dispatch: options?.dispatch, + }, + ) diff --git a/src/hooks/traverse/traverse.md b/src/hooks/traverse/traverse.md new file mode 100644 index 00000000..0e20fb62 --- /dev/null +++ b/src/hooks/traverse/traverse.md @@ -0,0 +1,50 @@ +--- +title: traverse +description: Transform fields & objects in place in the record(s) using a recursive walk. Powerful. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- + +## Arguments + +- `{Function} transformer` +- `{Function} [ getObject ]` + +| Argument | Type | Default | Description | +| ------------- | :--------: | ----------------------------------------- | ----------------------------------------------------------------------------- | +| `transformer` | `Function` | | Called for every node in every record(s). May change the node in place. | +| `getObject` | `Function` | `context.data` or `context.result[.data]` | Function with signature `context => {}` which returns the object to traverse. | + +## Example + +```js +const { traverse } = require('feathers-hooks-common/index.js'); + +// Trim strings +const trimmer = function (node) { + if (typeof node === 'string') { + this.update(node.trim()); + } +}; + +// REST HTTP request may use the string 'null' in its query string. +// Replace these strings with the value null. +const nuller = function (node) { + if (node === 'null') { + this.update(null); + } +}; + +module.exports = { + before: { create: traverse(trimmer), find: traverse(nuller, context => context.params.query) }, +}; +``` + +## Details + +Traverse and transform objects in place by visiting every node on a recursive walk. Any object in the hook may be traversed, including the query object. + +> [traverse (NPM)](https://npmjs.com/package/traverse) documents the extensive methods and context available to the transformer function. diff --git a/src/hooks/traverse/traverse.test.ts b/src/hooks/traverse/traverse.test.ts new file mode 100755 index 00000000..3d9a689c --- /dev/null +++ b/src/hooks/traverse/traverse.test.ts @@ -0,0 +1,112 @@ +import { assert } from 'vitest' +import { traverse } from './traverse.js' +import { clone } from '../../common/index.js' + +describe('traverse', () => { + let hookBefore: any + let hookBeforeArray: any + let trimmer: any + let hookAfter: any + let hookAfterArray: any + + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + data: { a: ' a b ' }, + params: { query: { b: ' b b ' } }, + } + + hookBeforeArray = { + type: 'before', + method: 'create', + data: [{ a: ' a b ' }, { c: ' c ' }], + params: { query: { b: ' b b ' }, something: { c: ' c', d: 'd ' } }, + } + + hookAfter = { + type: 'after', + method: 'create', + data: { q: 1 }, + params: { query: { b: ' b b ' } }, + result: { a: ' a b ' }, + } + + hookAfterArray = { + type: 'after', + method: 'create', + data: { q: 1 }, + params: { query: { b: ' b b ' } }, + result: [{ a: ' a b ' }, { c: ' c ' }], + } + + trimmer = function (this: any, node: any) { + if (typeof node === 'string') { + this.update(node.trim()) + } + } + }) + + it('transforms hook.data single item', () => { + const result = clone(hookBefore) + result.data = { a: 'a b' } + + traverse(trimmer)(hookBefore) + + assert.deepEqual(hookBefore, result) + }) + + it('transforms hook.data array of items', () => { + const result = clone(hookBeforeArray) + result.data = [{ a: 'a b' }, { c: 'c' }] + + traverse(trimmer)(hookBeforeArray) + + assert.deepEqual(hookBeforeArray, result) + }) + + it('transforms hook.result single item', () => { + const result = clone(hookAfter) + result.result = { a: 'a b' } + + traverse(trimmer)(hookAfter) + + assert.deepEqual(hookAfter, result) + }) + + it('transforms hook.result array of items', () => { + const result = clone(hookAfterArray) + result.result = [{ a: 'a b' }, { c: 'c' }] + + traverse(trimmer)(hookAfterArray) + + assert.deepEqual(hookAfterArray, result) + }) + + it('transforms hook.params.query', () => { + const result = clone(hookBefore) + result.params.query = { b: 'b b' } + + traverse(trimmer, (hook: any) => hook.params.query)(hookBefore) + + assert.deepEqual(hookBefore, result) + }) + + it('transforms multiple objects within a hook', () => { + const result = clone(hookBeforeArray) + result.params = { query: { b: 'b b' }, something: { c: 'c', d: 'd' } } + + traverse(trimmer, (hook: any) => [hook.params.query, hook.params.something])(hookBeforeArray) + + assert.deepEqual(hookBeforeArray, result) + }) + + it('transforms objects', () => { + const obj: any = { query: { b: 'b b' }, something: { c: 'c', d: 'd' } } + const result = clone(obj) + + traverse(trimmer, obj)(hookBeforeArray) + + assert.deepEqual(obj, result) + }) +}) diff --git a/src/hooks/traverse.ts b/src/hooks/traverse/traverse.ts similarity index 54% rename from src/hooks/traverse.ts rename to src/hooks/traverse/traverse.ts index 7666f25c..6571efd9 100755 --- a/src/hooks/traverse.ts +++ b/src/hooks/traverse/traverse.ts @@ -1,7 +1,7 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { traverse as _traverse } from '../common'; -import type { SyncContextFunction } from '../types'; -import { getItems } from '../utils/get-items'; +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { traverse as _traverse } from '../../common/index.js' +import type { SyncContextFunction } from '../../types.js' +import { getItems } from '../../utils/index.js' /** * Transform fields & objects in place in the record(s) using a recursive walk. Powerful. @@ -12,11 +12,16 @@ export function traverse( transformer: (transformContext: any) => any, getObject?: SyncContextFunction, ) { - return (context: H) => { + return (context: H, next?: NextFunction) => { const items = - typeof getObject === 'function' ? getObject(context) : getObject || getItems(context); + typeof getObject === 'function' ? getObject(context) : getObject || getItems(context) - _traverse(items, transformer); - return context; - }; + _traverse(items, transformer) + + if (next) { + return next() + } + + return context + } } diff --git a/src/hooks/trim-data/trim-data.md b/src/hooks/trim-data/trim-data.md new file mode 100644 index 00000000..7fa9d7d6 --- /dev/null +++ b/src/hooks/trim-data/trim-data.md @@ -0,0 +1,9 @@ +--- +title: trimData +description: Trim whitespace from string fields in the result. +category: hooks +hook: + type: ['before', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- diff --git a/src/hooks/trim-data/trim-data.test.ts b/src/hooks/trim-data/trim-data.test.ts new file mode 100755 index 00000000..7aa97e7b --- /dev/null +++ b/src/hooks/trim-data/trim-data.test.ts @@ -0,0 +1,76 @@ +import { assert } from 'vitest' +import type { HookContext } from '@feathersjs/feathers' +import { trimData } from './trim-data.js' + +describe('trimData', () => { + it('updates hook before::create', () => { + const context = { + type: 'before', + method: 'create', + data: { first: ' John', last: 'Doe ' }, + } as HookContext + trimData(['first', 'last'])(context) + assert.deepEqual(context.data, { first: 'John', last: 'Doe' }) + }) + + it('does not throw if field is missing', () => { + const context = { type: 'before', method: 'create', data: { last: ' Doe ' } } as HookContext + trimData(['first', 'last'])(context) + assert.deepEqual(context.data, { last: 'Doe' }) + }) + + it('does not throw if field is undefined', () => { + const context = { + type: 'before', + method: 'create', + data: { first: undefined, last: ' Doe' }, + } as HookContext + trimData(['first', 'last'])(context) + assert.deepEqual(context.data, { first: undefined, last: 'Doe' }) + }) + + it('does not throw if field is null', () => { + const context = { + type: 'before', + method: 'create', + data: { first: null, last: 'Doe ' }, + } as HookContext + trimData(['first', 'last'])(context) + assert.deepEqual(context.data, { first: null, last: 'Doe' }) + }) + + it('throws if field is not a string', async () => { + const context = { + type: 'before', + method: 'create', + data: { first: 1, last: 'Doe' }, + } as HookContext + await expect(async () => { + await trimData(['first', 'last'])(context) + }).rejects.toThrow('Expected string data. (trim first)') + }) + + it('prop with 1 dot', () => { + const context = { + data: { empl: { name: { first: 'John', last: 'Doe' }, status: ' AA' }, dept: ' Acct' }, + } as HookContext + trimData('empl.status')(context) + + assert.deepEqual(context.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: ' Acct', + }) + }) + + it('prop with 2 dots', () => { + const context = { + data: { empl: { name: { first: ' John', last: 'Doe' }, status: 'AA' }, dept: ' Acct' }, + } as HookContext + trimData('empl.name.first')(context) + + assert.deepEqual(context.data, { + empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, + dept: ' Acct', + }) + }) +}) diff --git a/src/hooks/trim-data/trim-data.ts b/src/hooks/trim-data/trim-data.ts new file mode 100755 index 00000000..ab29f9e1 --- /dev/null +++ b/src/hooks/trim-data/trim-data.ts @@ -0,0 +1,31 @@ +import _get from 'lodash/get.js' +import _set from 'lodash/set.js' +import { BadRequest } from '@feathersjs/errors' +import { transformData } from '../transform-data/transform-data.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +/** + * Trim certain field values. + * @see https://hooks-common.feathersjs.com/hooks.html#trimData + */ +export const trimData = (fieldNames: MaybeArray) => { + const fieldNamesArr = toArray(fieldNames) + + return transformData(item => { + for (let i = 0; i < fieldNamesArr.length; i++) { + const fieldName = fieldNamesArr[i] + const value = _get(item, fieldName) + + if (value == null) { + continue + } + + if (typeof value !== 'string') { + throw new BadRequest(`Expected string data. (trim ${fieldName})`) + } + + _set(item, fieldName, value.trim()) + } + }) +} diff --git a/src/hooks/trim-result/trim-result.md b/src/hooks/trim-result/trim-result.md new file mode 100644 index 00000000..c2791993 --- /dev/null +++ b/src/hooks/trim-result/trim-result.md @@ -0,0 +1,9 @@ +--- +title: trimResult +description: Trim string properties in the result. +category: hooks +hook: + type: ['before', 'after', 'around'] + method: ['find', 'get', 'create', 'update', 'patch', 'remove'] + multi: true +--- diff --git a/src/hooks/trim-result/trim-result.test.ts b/src/hooks/trim-result/trim-result.test.ts new file mode 100755 index 00000000..6957fda3 --- /dev/null +++ b/src/hooks/trim-result/trim-result.test.ts @@ -0,0 +1,63 @@ +import { assert } from 'vitest' +import { trimResult } from './trim-result.js' +import type { HookContext } from '@feathersjs/feathers' + +describe('lowercaseResult', () => { + it('updates hook after::find with pagination', () => { + const context = { + type: 'after', + method: 'find', + result: { + total: 2, + data: [ + { first: 'John ', last: ' Doe' }, + { first: ' Jane ', last: 'Doe ' }, + ], + }, + } as HookContext + + trimResult(['first', 'last'])(context) + assert.deepEqual(context.result.data, [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ]) + }) + + it('updates hook after::find with no pagination', () => { + const context = { + type: 'after', + method: 'find', + result: [ + { first: ' John', last: 'Doe ' }, + { first: ' Jane ', last: ' Doe' }, + ], + } as HookContext + trimResult(['first', 'last'])(context) + assert.deepEqual(context.result, [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ]) + }) + + it('single result', () => { + const context = { + type: 'after', + method: 'create', + result: { first: ' Jane', last: 'Doe ' }, + } as HookContext + trimResult(['first', 'last'])(context) + + assert.deepEqual(context.result, { first: 'Jane', last: 'Doe' }) + }) + + it('single result dot notation', () => { + const context = { + type: 'after', + method: 'create', + result: { first: { name: ' Jane' }, last: 'Doe ' }, + } as HookContext + trimResult('first.name')(context) + + assert.deepEqual(context.result, { first: { name: 'Jane' }, last: 'Doe ' }) + }) +}) diff --git a/src/hooks/trim-result/trim-result.ts b/src/hooks/trim-result/trim-result.ts new file mode 100755 index 00000000..d13c4bf0 --- /dev/null +++ b/src/hooks/trim-result/trim-result.ts @@ -0,0 +1,39 @@ +import _get from 'lodash/get.js' +import _set from 'lodash/set.js' +import { BadRequest } from '@feathersjs/errors' +import { transformResult } from '../transform-result/transform-result.js' +import type { DispatchOption } from '../../types.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +export type TrimResultOptions = { + dispatch?: DispatchOption +} + +/** + * Convert certain field values to lower case. + * @see https://hooks-common.feathersjs.com/hooks.html#trimResult + */ +export const trimResult = (fieldNames: MaybeArray, options?: TrimResultOptions) => { + const fieldNamesArray = toArray(fieldNames) + + return transformResult( + (item: any) => { + for (let i = 0; i < fieldNamesArray.length; i++) { + const fieldName = fieldNamesArray[i] + const value = _get(item, fieldName) + + if (value == null) { + continue + } + + if (typeof value !== 'string') { + throw new BadRequest(`Expected string data. (lowercase ${fieldName})`) + } + + _set(item, fieldName, value.trim()) + } + }, + { dispatch: options?.dispatch }, + ) +} diff --git a/src/hooks/unless/unless.md b/src/hooks/unless/unless.md new file mode 100644 index 00000000..3bca03fe --- /dev/null +++ b/src/hooks/unless/unless.md @@ -0,0 +1,42 @@ +--- +title: unless +description: Execute a series of hooks if a sync or async predicate is falsey. +category: hooks +hook: + type: ['before', 'after'] + method: ['all'] + multi: true +--- + +## Arguments + +- `{Boolean | Promise | Function} predicate` +- `{Array< Function >} hookFuncs` + +| Argument | Type | Default | Description | +| ----------- | :--------------------------------: | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `predicate` | `Boolean`, `Promise` or `Function` | | Run `hookFunc` if the `predicate` is false. If a function, `predicate` is called with the `context` as its param. It returns either a boolean or a Promise that evaluates to a boolean. | +| `hookFuncs` | `Array<` `Function >` | | Sync or async hook functions to run if `true`. They may include other conditional hooks. | + +## Example + +```js +const { isProvider, unless } = require('feathers-hooks-common/index.js'); + +module.exports = { + before: { + create: unless( + isProvider('server'), + hookA, + unless(isProvider('rest'), hook1, hook2, hook3), + hookB, + ), + }, +}; +``` + +## Details + +Resolve the predicate to a boolean. Run the hooks sequentially if the result is falsey. + +The predicate and hook functions will not be called with `this` set to the service, as is normal for hook functions. Use `hook.service` instead. diff --git a/src/hooks/unless/unless.test.ts b/src/hooks/unless/unless.test.ts new file mode 100755 index 00000000..ea4b8c82 --- /dev/null +++ b/src/hooks/unless/unless.test.ts @@ -0,0 +1,382 @@ +import type { HookContext } from '@feathersjs/feathers' +import { assert } from 'vitest' +import { unless } from './unless.js' +import { clone, isPromise } from '../../common/index.js' + +let hook: any +let hookBefore: any +let hookAfter: any +let hookFcnSyncCalls: any +let hookFcnAsyncCalls: any +let hookFcnCalls: any +let predicateHook: any +let predicateOptions: any +let predicateValue: any + +const predicateSync = (hook: any) => { + predicateHook = clone(hook) + return false +} + +const predicateSync2 = (options: any) => (hook: any) => { + predicateOptions = clone(options) + predicateHook = clone(hook) + return false +} + +const predicateAsync = (hook: any) => { + predicateHook = clone(hook) + return new Promise(resolve => resolve(false)) +} + +const predicateAsync2 = (options: any) => (hook: any) => { + predicateOptions = clone(options) + predicateHook = clone(hook) + return new Promise(resolve => resolve(false)) +} + +const predicateAsyncFunny = (hook: HookContext) => { + predicateHook = clone(hook) + return new Promise(resolve => { + predicateValue = null + return resolve(predicateValue) + }) +} + +const hookFcnSync = (hook: HookContext): HookContext => { + hookFcnSyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + return hook +} + +const hookFcnAsync = (hook: HookContext) => + new Promise(resolve => { + hookFcnAsyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + resolve(hook) + }) + +const hookFcn = (hook: HookContext): HookContext => { + hookFcnCalls = +1 + + return hook +} + +describe('sync predicate, sync hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls sync hook function if falsey non-function', () => { + unless( + false, + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call sync hook function if truthy non-function', () => { + const result = unless(true, hookFcnSync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } else { + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + } + }) + + it('calls sync hook function if sync predicate falsey', () => { + unless( + () => false, + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call sync hook function if sync predicate truthy', () => { + const result = unless(() => true, hookFcnSync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } else { + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + } + }) +}) + +describe('sync predicate, async hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls async hook function if sync predicate falsey', async () => { + const result = unless(false, hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call async hook function if sync predicate truthy', () => { + const result = unless(true, hookFcnAsync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } + + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnAsyncCalls, 0) + assert.deepEqual(hook, hookBefore) + }) + + it('calls async hook function if sync predicate returns falsey', async () => { + const result = unless(() => false, hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) +}) + +describe('async predicate, sync hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls sync hook function if aync predicate falsey', async () => { + const result = unless(() => new Promise(resolve => resolve(false)), hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) + + it('does not call sync hook function if async predicate truthy', async () => { + const result = unless(() => new Promise(resolve => resolve(true)), hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + }) + }) +}) + +describe('async predicate, async hook', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('calls async hook function if aync predicate falsey', async () => { + const result = unless(() => new Promise(resolve => resolve(false)), hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnAsyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) + + it('does not call async hook function if async predicate truthy', async () => { + const result = unless(() => new Promise(resolve => resolve(true)), hookFcnAsync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + result.then((result1: any) => { + assert.deepEqual(result1, hookBefore) + assert.equal(hookFcnAsyncCalls, 0) + assert.deepEqual(hook, hookBefore) + }) + }) +}) + +describe('sync predicate', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + predicateHook = null + predicateOptions = null + }) + + it('does not need to access hook', () => { + unless( + () => false, + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('is passed hook as param', () => { + unless( + predicateSync, + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('a higher order predicate can pass more options', () => { + unless( + predicateSync2({ z: 'z' }), + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(predicateOptions, { z: 'z' }) + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) +}) + +describe('async predicate', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + predicateHook = null + predicateOptions = null + predicateValue = null + }) + + it('is passed hook as param', async () => { + const result = unless(predicateAsync, hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) + + it('is resolved', async () => { + // @ts-expect-error TODO + const result = unless(predicateAsyncFunny, hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + + assert.equal(predicateValue, null) + }) + }) + + it('a higher order predicate can pass more options', async () => { + const result = unless(predicateAsync2({ y: 'y' }), hookFcnSync)(hook) + + if (!isPromise(result)) { + assert.fail('promise unexpectedly not returned') + } + + await result.then((result1: any) => { + assert.deepEqual(predicateOptions, { y: 'y' }) + assert.deepEqual(predicateHook, hookBefore) + assert.deepEqual(result1, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(result1, hookAfter) + }) + }) +}) + +describe('runs multiple hooks', () => { + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } } + hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + hookFcnAsyncCalls = 0 + }) + + it('runs successfully', async () => { + await unless( + false, + hookFcnSync, + hookFcnAsync, + hookFcn, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.equal(hookFcnAsyncCalls, 1) + assert.equal(hookFcnCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) +}) diff --git a/src/hooks/unless.ts b/src/hooks/unless/unless.ts similarity index 55% rename from src/hooks/unless.ts rename to src/hooks/unless/unless.ts index 29bdf8f5..cb735a7b 100755 --- a/src/hooks/unless.ts +++ b/src/hooks/unless/unless.ts @@ -1,6 +1,6 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { iffElse } from '..'; -import type { PredicateFn, HookFunction } from '../types'; +import type { HookContext } from '@feathersjs/feathers' +import { iffElse } from '../iff-else/iff-else.js' +import type { PredicateFn, HookFunction } from '../../types.js' /** * Execute a series of hooks if a sync or async predicate is falsey. @@ -11,6 +11,5 @@ export function unless( predicate: boolean | PredicateFn, ...hooks: HookFunction[] ) { - // @ts-ignore - return iffElse(predicate, undefined, hooks.slice()); + return iffElse(predicate, undefined, [...hooks]) } diff --git a/src/hooks/validate-schema.ts b/src/hooks/validate-schema.ts deleted file mode 100755 index fb89e1c7..00000000 --- a/src/hooks/validate-schema.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import type { AjvOrNewable, ValidateSchemaOptions } from './validate'; -import { getItems } from '../utils/get-items'; - -/** - * Validate data using JSON-Schema. - * @see https://hooks-common.feathersjs.com/hooks.html#validateschema - */ -export function validateSchema( - schema: object | string, - ajvOrAjv: AjvOrNewable, - // @ts-ignore - options: ValidateSchemaOptions = { allErrors: true }, -) { - const addNewError = options?.addNewError || addNewErrorDflt; - // delete options.addNewError; - // TODO: Any better way to tell if ajvOrAjv is an instance or a constructor? - let ajv: any; - let Ajv; - // @ts-ignore - if (typeof ajvOrAjv.addKeyword !== 'function') { - Ajv = ajvOrAjv; - // @ts-ignore - ajv = new Ajv(options); - } else { - ajv = ajvOrAjv; - } - const validate = typeof schema === 'string' ? ajv.getSchema(schema) : ajv.compile(schema); // for fastest execution - - return (context: H) => { - const items = getItems(context); - const itemsArray = Array.isArray(items) ? items : [items]; - const itemsLen = itemsArray.length; - let errorMessages: any = null; - let invalid = false; - - if (validate.schema.$async) { - return Promise.all( - itemsArray.map((item, index) => { - return validate(item).catch((err: any) => { - if (!(err instanceof ajv.constructor.ValidationError)) throw err; - - invalid = true; - - addErrors(err.errors, index); - }); - }), - ).then(() => { - if (invalid) { - throw new BadRequest('Data does not match schema', { errors: errorMessages }); - } - }); - } - - itemsArray.forEach((item, index) => { - if (!validate(item)) { - invalid = true; - - addErrors(validate.errors, index); - } - }); - - if (invalid) { - throw new BadRequest('Data does not match schema', { errors: errorMessages }); - } - - function addErrors(errors: any, index: any) { - errors.forEach((ajvError: any) => { - errorMessages = addNewError(errorMessages, ajvError, itemsLen, index); - }); - } - - return context; - }; -} - -function addNewErrorDflt(errorMessages: any, ajvError: any, itemsLen: any, index: any) { - const leader = itemsLen === 1 ? '' : `in row ${index + 1} of ${itemsLen}, `; - let message; - - if (ajvError.dataPath) { - message = `'${leader}${ajvError.dataPath.substring(1)}' ${ajvError.message}`; - } else { - message = `${leader}${ajvError.message}`; - } - - if (ajvError.params && ajvError.params.additionalProperty) { - message += `: '${ajvError.params.additionalProperty}'`; - } - - return (errorMessages || []).concat(message); -} diff --git a/src/hooks/validate.ts b/src/hooks/validate.ts deleted file mode 100755 index 72b07fd3..00000000 --- a/src/hooks/validate.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { BadRequest } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import type { Ajv, ErrorObject as ajvErrorObject, Options as AjvOptions } from 'ajv'; -import { isPromise } from '../common'; -import { checkContext } from '../utils/check-context'; -import { getItems } from '../utils/get-items'; -import { replaceItems } from '../utils/replace-items'; - -export type SyncValidatorFn = ( - values: any, - context: H, -) => { [key: string]: string } | null; -export type AsyncValidatorFn = ( - values: any, - context: H, -) => Promise; -export type ValidatorFn = - | SyncValidatorFn - | AsyncValidatorFn; - -export type AjvOrNewable = Ajv | (new (options?: AjvOptions) => Ajv); - -export interface ValidateSchemaOptions extends AjvOptions { - /** - * The hook will throw if the data does not match the JSON-Schema. error.errors will, by default, contain an array - * of error messages. You may change this with a custom formatting function. Its a reducing function which works - * similarly to Array.reduce(). - */ - addNewError: ( - currentFormattedMessages: any, - ajvErrorObject: ajvErrorObject, - itemsLen: number, - itemIndex: number, - ) => any; -} - -/** - * Validate data using a validation function. - * @see https://hooks-common.feathersjs.com/hooks.html#validate - */ -export function validate(validator: ValidatorFn) { - return (context: H) => { - checkContext(context, 'before', ['create', 'update', 'patch'], 'validate'); - - if (typeof validator !== 'function') { - throw new BadRequest('Expected validator function. (validate)'); - } - - const results = validator(getItems(context), context); - - if (isPromise(results)) { - return results.then((convertedValues: any) => { - if (convertedValues) { - // if values have been sanitized - replaceItems(context, convertedValues); - } - - return context; - }); - } - - // Sync function returns errors. It cannot sanitize. - if (results && Object.keys(results).length) { - // @ts-ignore - throw new BadRequest({ errors: results }); - } - - return context; - }; -} diff --git a/src/index.ts b/src/index.ts index 4319455c..9ad8afc0 100755 --- a/src/index.ts +++ b/src/index.ts @@ -1,51 +1,5 @@ -export * from './hooks/act-on-dispatch'; -export * from './hooks/alter-items'; -export * from './hooks/cache'; -export * from './utils/check-context-if'; -export * from './hooks/debug'; -export * from './hooks/de-populate'; -export * from './hooks/disable-pagination'; -export * from './hooks/disallow'; -export * from './hooks/discard'; -export * from './hooks/discard-query'; -export * from './hooks/fast-join'; -export * from './hooks/fgraphql'; -export * from './hooks/iff'; -export * from './hooks/iff-else'; -export * from './hooks/keep'; -export * from './hooks/keep-in-array'; -export * from './hooks/keep-query'; -export * from './hooks/keep-query-in-array'; -export * from './hooks/lower-case'; -export * from './hooks/mongo-keys'; -export * from './hooks/params-from-client'; -export * from './hooks/populate'; -export * from './hooks/prevent-changes'; -export * from './hooks/required'; -export * from './utils/run-hook'; -export * from './hooks/run-parallel'; -export * from './hooks/sequelize-convert'; -export * from './hooks/serialize'; -export * from './hooks/set-field'; -export * from './hooks/set-now'; -export * from './hooks/set-slug'; -export * from './hooks/sifter'; -export * from './hooks/soft-delete'; -export * from './hooks/stash-before'; -export * from './hooks/traverse'; -export * from './hooks/unless'; -export * from './hooks/validate'; -export * from './hooks/validate-schema'; +export * from './hooks/index.js' +export * from './utils/index.js' +export * from './predicates/index.js' -export * from './utils/calling-params'; -export * from './utils/check-context'; -export * from './utils/combine'; -export * from './utils/every'; -export * from './utils/get-items'; -export * from './utils/is-not'; -export * from './utils/is-provider'; -export * from './utils/params-for-server'; -export * from './utils/replace-items'; -export * from './utils/some'; - -export * from './types'; +export * from './types.js' diff --git a/src/internal.utils.ts b/src/internal.utils.ts new file mode 100644 index 00000000..dedcc085 --- /dev/null +++ b/src/internal.utils.ts @@ -0,0 +1,9 @@ +export const hasOwnProperty = (obj: Record, ...keys: string[]): boolean => { + return keys.some(x => Object.prototype.hasOwnProperty.call(obj, x)) +} + +export type MaybeArray = T | T[] +export const toArray = (value: T | T[]): T[] => (Array.isArray(value) ? value : [value]) + +export type Promisable = T | Promise +export type KeyOf = Extract diff --git a/src/predicates/every/every.md b/src/predicates/every/every.md new file mode 100644 index 00000000..78c9ee41 --- /dev/null +++ b/src/predicates/every/every.md @@ -0,0 +1,35 @@ +--- +title: every +description: Return the and of a series of sync or async predicate functions. +category: predicates +--- + +## Arguments + +- `{Array< Function >} predicates` + +| Argument | Type | Default | Description | +| ------------ | :-----------------: | ------- | ----------------------------------------------------------------------------- | +| `predicates` | `Array< Function >` | | Functions which take the current hook as a param and return a boolean result. | + +**Returns** + +- `{Boolean} result` + +| Name | Type | Description | +| ------ | ------- | ----------------------------- | +| result | Boolean | The logical and of predicates | + +## Example + +```js +const { iff, every } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { + create: iff(every(hook1, hook2, ...), hookA, hookB, ...) +} }; +``` + +## Details + +`every` is a predicate function for use in conditional hooks. The predicate functions are run in parallel, and `true` is returned if every predicate returns a truthy value. diff --git a/test/utils/every.test.ts b/src/predicates/every/every.test.ts similarity index 54% rename from test/utils/every.test.ts rename to src/predicates/every/every.test.ts index 13b5fbcb..399fad87 100755 --- a/test/utils/every.test.ts +++ b/src/predicates/every/every.test.ts @@ -1,14 +1,61 @@ -import { assert } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { iff, every, isNot } from '../../src'; +import { assert } from 'vitest' +import type { HookContext } from '@feathersjs/feathers' +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { iff } from '../../hooks/index.js' +import { every } from './every.js' +import { not } from '../not/not.js' -describe('util every', () => { - let app: any; +describe('predicates/every', () => { + it('returns true synchronously when empty', () => { + assert.equal(every()({} as HookContext), true) + }) + + it('returns true when all are undefined', () => { + expect(every(undefined, undefined, undefined)({} as HookContext)).toBe(true) + }) + + it('returns false synchronously when at least 1 hook is false', () => { + expect( + every( + () => true, + () => Promise.resolve(false), + () => Promise.resolve(true), + () => false, + )({} as HookContext), + ).toBe(false) + }) + + it('returns true when all hooks are truthy', async () => { + await expect( + every( + () => true, + () => Promise.resolve(true), + () => Promise.resolve(true), + )({} as HookContext), + ).resolves.toBe(true) + }) + + it('rejects with the error', async () => { + await expect( + async () => await every(() => Promise.reject(new Error('errored')))({} as HookContext), + ).rejects.toThrow('errored') + }) + + it('does not run all predicates when one is false', () => { + const fn = vi.fn(() => { + return false + }) + + expect(every(fn, fn, fn)({} as HookContext)).toBe(false) + expect(fn).toHaveBeenCalledTimes(1) + }) + + let app: any beforeEach(() => { - app = feathers().use('/users', new MemoryService()); - }); + app = feathers().use('/users', new MemoryService()) + }) describe('when all hooks are truthy', () => { beforeEach(() => { @@ -18,7 +65,7 @@ describe('util every', () => { iff( every( (_hook: any) => true, - // @ts-ignore + // @ts-expect-error TODO (_hook: any) => 1, (_hook: any) => {}, (_hook: any) => Promise.resolve(true), @@ -27,18 +74,18 @@ describe('util every', () => { ), ], }, - }); - }); + }) + }) it('returns true', () => { return app .service('users') .find() .then((result: any) => { - assert.deepEqual(result, []); - }); - }); - }); + assert.deepEqual(result, []) + }) + }) + }) describe('when a hook throws an error', () => { beforeEach(() => { @@ -49,7 +96,7 @@ describe('util every', () => { every( (_hook: any) => true, (_hook: any) => { - throw new Error('Hook 2 errored'); + throw new Error('Hook 2 errored') }, (_hook: any) => true, ), @@ -57,18 +104,18 @@ describe('util every', () => { ), ], }, - }); - }); + }) + }) it('rejects with the error', () => { return app .service('users') .find() .catch((error: any) => { - assert.equal(error.message, 'Hook 2 errored'); - }); - }); - }); + assert.equal(error.message, 'Hook 2 errored') + }) + }) + }) describe('when a hook rejects with an error', () => { beforeEach(() => { @@ -85,18 +132,18 @@ describe('util every', () => { ), ], }, - }); - }); + }) + }) it('rejects with the error', () => { return app .service('users') .find() .catch((error: any) => { - assert.equal(error.message, 'Hook 2 errored'); - }); - }); - }); + assert.equal(error.message, 'Hook 2 errored') + }) + }) + }) describe('when at least one hook is falsey', () => { beforeEach(() => { @@ -104,13 +151,13 @@ describe('util every', () => { before: { all: [ iff( - isNot( + not( every( (_hook: any) => true, (_hook: any) => Promise.resolve(true), (_hook: any) => Promise.resolve(false), (_hook: any) => false, - // @ts-ignore + // @ts-expect-error TODO (_hook: any) => 0, (_hook: any) => null, (_hook: any) => undefined, @@ -121,16 +168,16 @@ describe('util every', () => { ), ], }, - }); - }); + }) + }) it('returns false', () => { return app .service('users') .find() .catch((error: any) => { - assert.equal(error.message, 'A hook returned false'); - }); - }); - }); -}); + assert.equal(error.message, 'A hook returned false') + }) + }) + }) +}) diff --git a/src/predicates/every/every.ts b/src/predicates/every/every.ts new file mode 100755 index 00000000..aebb6a6b --- /dev/null +++ b/src/predicates/every/every.ts @@ -0,0 +1,52 @@ +import type { HookContext } from '@feathersjs/feathers' +import type { PredicateFn } from '../../types.js' +import { isPromise } from '../../common/index.js' + +/** + * Return the and of a series of sync or async predicate functions. + * @see https://hooks-common.feathersjs.com/utilities.html#every + */ +export const every = + ( + ...predicates: (PredicateFn | undefined)[] + ): PredicateFn => + (context: H): boolean | Promise => { + if (!predicates.length) { + // same as Array.prototype.every + // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every#description + return true + } + + const promises: Promise[] = [] + + let everyUndefined = true + + for (const predicate of predicates) { + if (!predicate) { + // skip undefined predicates + continue + } else { + everyUndefined = false + } + + const result = predicate(context) + if (result === false) { + return false + } else if (isPromise(result)) { + promises.push(result) + } + } + + if (everyUndefined) { + // all predicates are undefined -> same as Array.prototype.every + // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every#description + return true + } + + if (!promises.length) { + // no promises returned -> all predicates are sync and true + return true + } + + return Promise.all(promises).then(results => results.every(result => !!result)) + } diff --git a/src/predicates/index.ts b/src/predicates/index.ts new file mode 100644 index 00000000..e54ce11d --- /dev/null +++ b/src/predicates/index.ts @@ -0,0 +1,7 @@ +export * from './every/every.js' +export * from './is-context/is-context.js' +export * from './is-multi/is-multi.js' +export * from './is-paginated/is-paginated.js' +export * from './is-provider/is-provider.js' +export * from './not/not.js' +export * from './some/some.js' diff --git a/src/predicates/is-context/is-context.ts b/src/predicates/is-context/is-context.ts new file mode 100644 index 00000000..2ddbee50 --- /dev/null +++ b/src/predicates/is-context/is-context.ts @@ -0,0 +1,40 @@ +import type { HookType } from '@feathersjs/feathers' +import type { MethodName } from '../../types.js' +import type { MaybeArray } from '../../internal.utils.js' +import { toArray } from '../../internal.utils.js' + +export type IsContextOptions = { + path?: MaybeArray + type?: MaybeArray + method?: MaybeArray +} + +export const isContext = + (options: IsContextOptions) => + (context: any): boolean => { + if (options.path != null) { + const path = toArray(options.path) + + if (!path.some(x => context.path.includes(x))) { + return false + } + } + + if (options.type != null) { + const type = toArray(options.type) + + if (!type.some(x => context.type === x)) { + return false + } + } + + if (options.method != null) { + const method = toArray(options.method) + + if (!method.some(x => context.method === x)) { + return false + } + } + + return true + } diff --git a/src/predicates/is-multi/is-multi.test.ts b/src/predicates/is-multi/is-multi.test.ts new file mode 100644 index 00000000..c51505aa --- /dev/null +++ b/src/predicates/is-multi/is-multi.test.ts @@ -0,0 +1,49 @@ +import type { HookContext } from '@feathersjs/feathers' +import { isMulti } from './is-multi.js' + +describe('predicates/isMulti', () => { + it('returns true', function () { + const makeContext = (type: string, method: string) => { + const context = { + method, + type, + } as HookContext + if (method === 'create') { + context.data = [] + } + if (method === 'patch' || method === 'remove') { + context.id = null as any + } + return context + } + ;['before', 'after', 'around'].forEach(type => { + ;['find', 'create', 'patch', 'remove'].forEach(method => { + const context = makeContext(type, method) + assert.strictEqual(isMulti(context), true, `'${type}:${method}': returns true`) + }) + }) + }) + + it('returns false', function () { + const makeContext = (type: string, method: string) => { + const context = { + method, + type, + } as HookContext + if (method === 'create') { + context.data = {} + } + if (method === 'patch' || method === 'remove' || method === 'update') { + context.id = 0 + } + + return context + } + ;['before', 'after', 'around'].forEach(type => { + ;['get', 'create', 'update', 'patch', 'remove'].forEach(method => { + const context = makeContext(type, method) + assert.strictEqual(isMulti(context), false, `'${type}:${method}': returns false`) + }) + }) + }) +}) diff --git a/src/predicates/is-multi/is-multi.ts b/src/predicates/is-multi/is-multi.ts new file mode 100644 index 00000000..cf9b3cb6 --- /dev/null +++ b/src/predicates/is-multi/is-multi.ts @@ -0,0 +1,25 @@ +import type { HookContext } from '@feathersjs/feathers' + +/** + * util to check if a hook is a multi hook: + * - find: true + * - get: false + * - create: `context.data` is an array + * - update: false + * - patch: `context.id == null` + * - remove: `context.id == null` + */ +export const isMulti = (context: H): boolean => { + const { method } = context + if (method === 'find') { + return true + } else if (method === 'patch' || method === 'remove') { + return context.id == null + } else if (method === 'create') { + return Array.isArray(context.data) + } else if (method === 'get' || method === 'update') { + return false + } + + return false +} diff --git a/src/predicates/is-paginated/is-paginated.test.ts b/src/predicates/is-paginated/is-paginated.test.ts new file mode 100644 index 00000000..c303cc2f --- /dev/null +++ b/src/predicates/is-paginated/is-paginated.test.ts @@ -0,0 +1,72 @@ +import type { HookContext } from '@feathersjs/feathers' +import { isPaginated } from './is-paginated.js' + +describe('predicates/isPaginated', () => { + it('returns true for service.options.paginate', function () { + const serviceOptions = { + paginate: { + default: 10, + max: 50, + }, + } + + const paginate = isPaginated({ + params: {}, + service: { + options: serviceOptions, + }, + method: 'find', + } as HookContext) + + assert.deepStrictEqual(paginate, true) + }) + + it('returns false for params.paginate: false', function () { + const serviceOptions = { + paginate: { + default: 10, + max: 50, + }, + } + + const paginate = isPaginated({ + params: { paginate: false }, + service: { + options: serviceOptions, + }, + } as HookContext) + + assert.deepStrictEqual(paginate, false) + }) + + it('returns true for context.adapter.paginate', function () { + const serviceOptions = { + paginate: false, + } + + const paginate = isPaginated({ + params: { adapter: { paginate: { default: 20, max: 100 } } }, + service: { + options: serviceOptions, + }, + method: 'find', + } as HookContext) + + assert.deepStrictEqual(paginate, true) + }) + + it('returns false for no paginate', function () { + const serviceOptions = { + paginate: false, + } + + const paginate = isPaginated({ + params: {}, + service: { + options: serviceOptions, + }, + } as HookContext) + + assert.deepStrictEqual(paginate, false) + }) +}) diff --git a/src/predicates/is-paginated/is-paginated.ts b/src/predicates/is-paginated/is-paginated.ts new file mode 100644 index 00000000..e10efbd7 --- /dev/null +++ b/src/predicates/is-paginated/is-paginated.ts @@ -0,0 +1,15 @@ +import type { HookContext } from '@feathersjs/feathers' +import { getPaginate } from '../../utils/get-paginate/get-paginate.js' + +/** + * util to check if a hook is a paginated hook using `getPaginate` + */ +export const isPaginated = (context: H): boolean => { + if (context.params.paginate === false || context.method !== 'find') { + return false + } + + const paginate = getPaginate(context) + + return !!paginate +} diff --git a/src/predicates/is-provider/is-provider.md b/src/predicates/is-provider/is-provider.md new file mode 100644 index 00000000..56dbcb6c --- /dev/null +++ b/src/predicates/is-provider/is-provider.md @@ -0,0 +1,40 @@ +--- +title: isProvider +description: Check which transport provided the service call. +category: predicates +--- + +## Arguments + +- `{Array< String >} transports` + +| Name | Type | Default | Description | +| ------------ | :---------------: | ------- | --------------------------------- | +| `transports` | `Array< String >` | | The transports you want to allow. | + +| `transports` | Value | Description | +| ------------ | :---------------------------------: | ----------- | +| `socketio` | Allow calls by Socket.IO transport. | +| `rest` | Allow calls by REST transport. | +| `external` | Allow calls other than from server. | +| `server` | Allow calls from server. | + +**Returns** + +- `{Boolean} result` + +| Name | Type | Description | +| ------ | ------- | ---------------------------------------------- | +| result | Boolean | If the call was made by one of the transports. | + +## Example + +```js +const { iff, isProvider, discard } = require('feathers-hooks-common/index.js'); + +module.exports = { after: { create: iff(isProvider('external'), discard('password')) } }; +``` + +## Details + +`isProvider` is a predicate function for use in conditional hooks. Its determines which transport provided the service call by checking `context.params.provider`. diff --git a/src/predicates/is-provider/is-provider.test.ts b/src/predicates/is-provider/is-provider.test.ts new file mode 100755 index 00000000..a2ae55a4 --- /dev/null +++ b/src/predicates/is-provider/is-provider.test.ts @@ -0,0 +1,134 @@ +import { assert } from 'vitest' +import { isProvider } from './is-provider.js' +import { iff } from '../../hooks/index.js' +import { clone, isPromise } from '../../common/index.js' + +let hookServer: any +let hookSocketio: any + +let hook: any +let hookBefore: any +let hookAfter: any +let hookFcnSyncCalls: any + +const hookFcnSync = (hook: any) => { + hookFcnSyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + return hook +} + +describe('predicates/isProvider', () => { + beforeEach(() => { + hookServer = { type: 'before', method: 'create', params: { provider: '' } } + hookSocketio = { type: 'before', method: 'create', params: { provider: 'socketio' } } + }) + + it('returns a function', () => { + const fcn = isProvider('server') + + assert.isFunction(fcn) + }) + + it('gets passed the hook', () => { + const hook = clone(hookServer) + const result = isProvider('server')(hook) + + assert.equal(result, true) + }) + + it('throws on no args', () => { + assert.throws(() => isProvider()) + }) + + it('finds provider with 1 arg', () => { + const hook = clone(hookSocketio) + const result = isProvider('socketio')(hook) + + assert.equal(result, true) + }) + + it('finds provider with 2 args', () => { + const hook = clone(hookSocketio) + const result = isProvider('rest', 'socketio')(hook) + + assert.equal(result, true) + }) + + it('finds server', () => { + const hook = clone(hookServer) + const result = isProvider('rest', 'socketio', 'server')(hook) + + assert.equal(result, true) + }) + + it('finds external', () => { + const hook = clone(hookSocketio) + const result = isProvider('rest', 'server', 'external')(hook) + + assert.equal(result, true) + }) + + it('fails properly if not provider', () => { + const hook = clone(hookServer) + const result = isProvider('socketio')(hook) + + assert.equal(result, false) + }) + + it('fails properly if not external', () => { + const hook = clone(hookServer) + const result = isProvider('external')(hook) + + assert.equal(result, false) + }) + + it('fails properly if not server', () => { + const hook = clone(hookSocketio) + const result = isProvider('server')(hook) + + assert.equal(result, false) + }) +}) + +describe('services isProvider - works with iff', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + data: { first: 'John' }, + params: { provider: 'rest' }, + } + hookAfter = { + type: 'before', + method: 'create', + data: { first: 'john' }, + params: { provider: 'rest' }, + } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + }) + + it('calls sync hook function if truthy', () => { + iff( + isProvider('rest'), + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call sync hook function if falsey', () => { + const result = iff(isProvider('server'), hookFcnSync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } else { + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + } + }) +}) diff --git a/src/utils/is-provider.ts b/src/predicates/is-provider/is-provider.ts similarity index 65% rename from src/utils/is-provider.ts rename to src/predicates/is-provider/is-provider.ts index fe695042..723e7e61 100755 --- a/src/utils/is-provider.ts +++ b/src/predicates/is-provider/is-provider.ts @@ -1,6 +1,6 @@ -import { MethodNotAllowed } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import type { TransportName } from '../types'; +import { MethodNotAllowed } from '@feathersjs/errors' +import type { HookContext } from '@feathersjs/feathers' +import type { TransportName } from '../../types.js' /** * Check which transport provided the service call. @@ -8,17 +8,17 @@ import type { TransportName } from '../types'; */ export function isProvider(...providers: TransportName[]) { if (!providers.length) { - throw new MethodNotAllowed('Calling isProvider predicate incorrectly.'); + throw new MethodNotAllowed('Calling isProvider predicate incorrectly.') } - return (context: H) => { - const hookProvider = context.params.provider; + return (context: H): boolean => { + const hookProvider = context.params.provider return providers.some( provider => provider === hookProvider || (provider === 'server' && !hookProvider) || (provider === 'external' && !!hookProvider), - ); - }; + ) + } } diff --git a/src/predicates/not/not.md b/src/predicates/not/not.md new file mode 100644 index 00000000..43d04024 --- /dev/null +++ b/src/predicates/not/not.md @@ -0,0 +1,36 @@ +--- +title: not +description: Negate a sync or async predicate function. +category: predicates +--- + +## Arguments + +- `{Function | Boolean} predicate` + +| Argument | Type | Default | Description | +| ----------- | :------------------: | ------- | --------------------------------------------------------------------------------------------- | +| `predicate` | `Function` `Boolean` | | A sync or async function which take the current hook as a param and returns a boolean result. | + +**Returns** + +- `{Boolean} result` + +| Name | Type | Description | +| ------ | ------- | -------------------- | +| result | Boolean | The not of predicate | + +## Example + +```js +const { iff, isNot, isProvider, discard } = require('feathers-hooks-common/index.js'); +const isRequestor = () => context => new Promise(resolve, reject) => ... ); + +module.exports = { after: { + create: iff(isNot(isRequestor()), discard('password')) +} }; +``` + +## Details + +`isNot` is a predicate function for use in conditional hooks. diff --git a/src/predicates/not/not.test.ts b/src/predicates/not/not.test.ts new file mode 100755 index 00000000..8102f803 --- /dev/null +++ b/src/predicates/not/not.test.ts @@ -0,0 +1,124 @@ +import { assert } from 'vitest' +import { iff } from '../../hooks/index.js' +import { clone, isPromise } from '../../common/index.js' +import { not } from './not.js' +import { isProvider } from '../is-provider/is-provider.js' + +let hookServer: any +let hook: any +let hookBefore: any +let hookAfter: any +let hookFcnSyncCalls: any +let predicateCalls: any + +const predicateSync = (value: any) => () => { + predicateCalls = +1 + return value +} + +const predicateAsync = + (value: T) => + () => + new Promise(resolve => { + predicateCalls = +1 + return resolve(value) + }) + +const hookFcnSync = (hook: any) => { + hookFcnSyncCalls = +1 + hook.data.first = hook.data.first.toLowerCase() + + return hook +} + +describe('predicates/not', () => { + beforeEach(() => { + hookServer = { type: 'before', method: 'create', params: { provider: '' } } + predicateCalls = 0 + }) + + it('negates a sync function 1', () => { + const hook = clone(hookServer) + const result = not(predicateSync(true))(hook) + + assert.equal(predicateCalls, 1) + assert.equal(result, false) + }) + + it('negates a sync function 2', () => { + const hook = clone(hookServer) + const result = not(predicateSync(false))(hook) + + assert.equal(predicateCalls, 1) + assert.equal(result, true) + }) + + it('negates an async function 1', async () => { + const hook = clone(hookServer) + + await not(predicateAsync(true))(hook) + // @ts-expect-error TODO + .then((result: any) => { + assert.equal(predicateCalls, 1) + assert.equal(result, false) + }) + .catch(() => { + assert.fail('unexpected catch') + }) + }) + + it('negates an async function 2', async () => { + const hook = clone(hookServer) + await not(predicateAsync(false))(hook) + // @ts-expect-error TODO + .then((result: any) => { + assert.equal(predicateCalls, 1) + assert.equal(result, true) + }) + .catch(() => { + assert.fail('unexpected catch') + }) + }) +}) + +describe('services not - works with iff and isProvider', () => { + beforeEach(() => { + hookBefore = { + type: 'before', + method: 'create', + data: { first: 'John' }, + params: { provider: 'rest' }, + } + hookAfter = { + type: 'before', + method: 'create', + data: { first: 'john' }, + params: { provider: 'rest' }, + } + hook = clone(hookBefore) + hookFcnSyncCalls = 0 + }) + + it('calls sync hook function if truthy', () => { + iff( + not(isProvider('server')), + hookFcnSync, + )(hook).then((hook: any) => { + assert.deepEqual(hook, hookAfter) + assert.equal(hookFcnSyncCalls, 1) + assert.deepEqual(hook, hookAfter) + }) + }) + + it('does not call sync hook function if falsey', () => { + const result = iff(not(isProvider('rest')), hookFcnSync)(hook) + + if (isPromise(result)) { + assert.fail('promise unexpectedly returned') + } else { + assert.deepEqual(result, hookBefore) + assert.equal(hookFcnSyncCalls, 0) + assert.deepEqual(hook, hookBefore) + } + }) +}) diff --git a/src/predicates/not/not.ts b/src/predicates/not/not.ts new file mode 100755 index 00000000..b4889d66 --- /dev/null +++ b/src/predicates/not/not.ts @@ -0,0 +1,20 @@ +import type { HookContext } from '@feathersjs/feathers' +import { isPromise } from '../../common/index.js' +import type { PredicateFn } from '../../types.js' + +/** + * Negate a predicate function. + * + * @see https://hooks-common.feathersjs.com/utilities.html#isnot + */ +export const not = + (predicate: PredicateFn): PredicateFn => + (context: H) => { + const result = predicate(context) + + if (!isPromise(result)) { + return !result + } + + return result.then(result1 => !result1) + } diff --git a/src/predicates/some/some.md b/src/predicates/some/some.md new file mode 100644 index 00000000..d4f60ff3 --- /dev/null +++ b/src/predicates/some/some.md @@ -0,0 +1,35 @@ +--- +title: some +description: Return the or of a series of sync or async predicate functions. +category: predicates +--- + +## Arguments + +- `{Array< Function >} predicates` + +| Argument | Type | Default | Description | +| ------------ | :-----------------: | ------- | ----------------------------------------------------------------------------- | +| `predicates` | `Array< Function >` | | Functions which take the current hook as a param and return a boolean result. | + +**Returns** + +- `{Boolean} result` + +| Name | Type | Description | +| ------ | ------- | ---------------------------- | +| result | Boolean | The logical or of predicates | + +## Example + +```js +const { iff, some } = require('feathers-hooks-common/index.js'); + +module.exports = { before: { + create: iff(some(hook1, hook2, ...), hookA, hookB, ...) +} }; +``` + +## Details + +`some` is a predicate function for use in conditional hooks. The predicate functions are run in parallel, and `true` is returned if any predicate returns a truthy value. diff --git a/src/predicates/some/some.test.ts b/src/predicates/some/some.test.ts new file mode 100755 index 00000000..3e6126c4 --- /dev/null +++ b/src/predicates/some/some.test.ts @@ -0,0 +1,63 @@ +import { expect } from 'vitest' +import type { HookContext } from '@feathersjs/feathers' +import { some } from './some.js' + +describe('predicates/some', () => { + it('returns true synchronously when empty', () => { + expect(some()({} as HookContext)).toBe(true) + }) + + it('returns true when all are undefined', () => { + expect(some(undefined, undefined, undefined)({} as HookContext)).toBe(true) + }) + + it('returns true synchronously when at least 1 hook is true', () => { + expect( + some( + () => false, + () => false, + () => Promise.resolve(false), + () => Promise.resolve(true), + () => true, + )({} as HookContext), + ).toBe(true) + }) + + it('returns true when at least 1 async hook is true', async () => { + expect( + some( + () => false, + () => Promise.resolve(false), + () => Promise.resolve(true), + )({} as HookContext), + ).resolves.toBe(true) + }) + + it('rejects with the error', async () => { + await expect( + async () => await some(() => Promise.reject(new Error('errored')))({} as HookContext), + ).rejects.toThrow('errored') + }) + + it('does not run all predicates when one is true', () => { + const fn = vi.fn(() => { + return true + }) + + expect(some(fn, fn, fn)({} as HookContext)).toBe(true) + expect(fn).toHaveBeenCalledTimes(1) + }) + + it('when all hooks are falsey', async () => { + await expect( + some( + () => false, + () => Promise.resolve(false), + // @ts-expect-error test case + () => null, + () => undefined, + () => 0, + )({} as HookContext), + ).resolves.toBe(false) + }) +}) diff --git a/src/predicates/some/some.ts b/src/predicates/some/some.ts new file mode 100755 index 00000000..e829eb63 --- /dev/null +++ b/src/predicates/some/some.ts @@ -0,0 +1,55 @@ +import type { HookContext } from '@feathersjs/feathers' +import type { PredicateFn } from '../../types.js' +import { isPromise } from '../../common/index.js' + +/** + * Return the or of a series of sync or async predicate functions. + * @see https://hooks-common.feathersjs.com/utilities.html#some + */ +export const some = + ( + ...predicates: (PredicateFn | undefined)[] + ): PredicateFn => + (context: H): boolean | Promise => { + if (!predicates.length) { + // same as Array.prototype.some + // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#description + return true + } + + const promises: Promise[] = [] + + let everyUndefined = true + + for (const predicate of predicates) { + if (!predicate) { + // skip undefined predicates + continue + } else { + everyUndefined = false + } + + const result = predicate(context) + + if (result === true) { + return true + } else if (result === false) { + continue + } else if (isPromise(result)) { + promises.push(result) + } + } + + if (everyUndefined) { + // all predicates are undefined -> same as Array.prototype.some + // see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some#description + return true + } + + if (!promises.length) { + // no promises returned -> all predicates are sync and false + return false + } + + return Promise.all(promises).then(results => results.some(result => !!result)) + } diff --git a/src/resolvers/hooks/index.ts b/src/resolvers/hooks/index.ts new file mode 100644 index 00000000..598ef09f --- /dev/null +++ b/src/resolvers/hooks/index.ts @@ -0,0 +1,4 @@ +export * from './resolve-data.js' +export * from './resolve-query.js' +export * from './resolve-result.js' +export * from './resolve.js' diff --git a/src/resolvers/hooks/resolve-data.test.ts b/src/resolvers/hooks/resolve-data.test.ts new file mode 100644 index 00000000..162ddbd1 --- /dev/null +++ b/src/resolvers/hooks/resolve-data.test.ts @@ -0,0 +1,131 @@ +import assert from 'node:assert' +import { BadRequest } from '@feathersjs/errors' +import { resolveData } from './resolve-data.js' +import type { HookContext } from '@feathersjs/feathers' + +type User = { + firstName: string + lastName: string + password: string +} + +describe('resolve-data', () => { + it('simple resolver', async () => { + const context = { + data: { + firstName: 'Dave', + lastName: 'L.', + }, + } as unknown as HookContext + + const u = await resolveData({ + password: async (): Promise => undefined, + + name: async (_value, user, ctx, status) => { + assert.deepStrictEqual(ctx, context) + assert.deepStrictEqual(status.path, ['name']) + assert.strictEqual(typeof status.stack[0], 'function') + + return `${user.firstName} ${user.lastName}` + }, + })(context) + + assert.deepStrictEqual(u.data, { + firstName: 'Dave', + lastName: 'L.', + name: 'Dave L.', + }) + }) + + it('array resolver', async () => { + const context = { + data: [ + { + firstName: 'Dave', + lastName: 'L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + }, + ], + } as unknown as HookContext + + const u = await resolveData({ + password: async (): Promise => undefined, + + name: async (_value, user, ctx, status) => { + assert.deepStrictEqual(ctx, context) + assert.deepStrictEqual(status.path, ['name']) + assert.strictEqual(typeof status.stack[0], 'function') + + return `${user.firstName} ${user.lastName}` + }, + })(context) + + assert.deepStrictEqual(u.data, [ + { + firstName: 'Dave', + lastName: 'L.', + name: 'Dave L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + name: 'Fred F.', + }, + ]) + }) + + it('resolving with errors', async () => { + const resolver = resolveData<{ name: string; age: number }>({ + name: async value => { + if (value === 'Dave') { + throw new Error(`No ${value}s allowed`) + } + + return value + }, + age: async value => { + if (value && value < 18) { + throw new BadRequest('Invalid age') + } + + return value + }, + }) + + await assert.rejects( + () => + resolver({ + data: { + name: 'Dave', + age: 16, + }, + } as HookContext), + { + name: 'BadRequest', + message: 'Error resolving data', + code: 400, + className: 'bad-request', + data: { + name: { message: 'No Daves allowed' }, + age: { + name: 'BadRequest', + message: 'Invalid age', + code: 400, + className: 'bad-request', + }, + }, + }, + ) + }) + + it('empty resolver returns original data', async () => { + const resolver = resolveData({}) + const data = { message: 'Hello' } + const resolved = await resolver({ data } as HookContext) + + assert.strictEqual(data, resolved.data) + }) +}) diff --git a/src/resolvers/hooks/resolve-data.ts b/src/resolvers/hooks/resolve-data.ts new file mode 100644 index 00000000..fbc9ae73 --- /dev/null +++ b/src/resolvers/hooks/resolve-data.ts @@ -0,0 +1,18 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { ResolverObject } from './resolvers.internal.js' +import { resolve } from './resolvers.internal.js' +import { replaceData } from '../../utils/index.js' + +export const resolveData = + , H extends HookContext = HookContext>( + resolverProperties: ResolverObject, + ) => + async (context: H, next?: NextFunction) => { + await replaceData(context, item => resolve(resolverProperties, item, context)) + + if (next) { + return next() + } + + return context + } diff --git a/src/resolvers/hooks/resolve-query.ts b/src/resolvers/hooks/resolve-query.ts new file mode 100644 index 00000000..65824b02 --- /dev/null +++ b/src/resolvers/hooks/resolve-query.ts @@ -0,0 +1,20 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { type ResolverObject, resolve } from './resolvers.internal.js' + +export const resolveQuery = + (resolverProperties: ResolverObject) => + async (context: H, next?: NextFunction) => { + const queryIngoing = context?.params?.query || {} + const query = await resolve(resolverProperties, queryIngoing, context) + + context.params = { + ...context.params, + query, + } + + if (next) { + return next() + } + + return context + } diff --git a/src/resolvers/hooks/resolve-result.test.ts b/src/resolvers/hooks/resolve-result.test.ts new file mode 100644 index 00000000..bae835c0 --- /dev/null +++ b/src/resolvers/hooks/resolve-result.test.ts @@ -0,0 +1,215 @@ +import assert from 'node:assert' +import { BadRequest } from '@feathersjs/errors' +import { resolveResult } from './resolve-result.js' +import type { HookContext } from '@feathersjs/feathers' + +type User = { + firstName: string + lastName: string + password: string +} + +describe('resolve-result', () => { + it('simple resolver', async () => { + const context = { + result: { + firstName: 'Dave', + lastName: 'L.', + }, + } as unknown as HookContext + + const u = await resolveResult({ + password: async (): Promise => undefined, + + name: async (_value, user, ctx, status) => { + assert.deepStrictEqual(ctx, context) + assert.deepStrictEqual(status.path, ['name']) + assert.strictEqual(typeof status.stack[0], 'function') + + return `${user.firstName} ${user.lastName}` + }, + })(context) + + assert.deepStrictEqual(u.result, { + firstName: 'Dave', + lastName: 'L.', + name: 'Dave L.', + }) + }) + + it('array result on create', async () => { + const context = { + method: 'create', + result: [ + { + firstName: 'Dave', + lastName: 'L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + }, + ], + } as unknown as HookContext + + const u = await resolveResult({ + password: async (): Promise => undefined, + + name: async (_value, user, ctx, status) => { + assert.deepStrictEqual(ctx, context) + assert.deepStrictEqual(status.path, ['name']) + assert.strictEqual(typeof status.stack[0], 'function') + + return `${user.firstName} ${user.lastName}` + }, + })(context) + + assert.deepStrictEqual(u.result, [ + { + firstName: 'Dave', + lastName: 'L.', + name: 'Dave L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + name: 'Fred F.', + }, + ]) + }) + + it('array result on find', async () => { + const context = { + method: 'find', + result: [ + { + firstName: 'Dave', + lastName: 'L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + }, + ], + } as unknown as HookContext + + const u = await resolveResult({ + password: async (): Promise => undefined, + + name: async (_value, user, ctx, status) => { + assert.deepStrictEqual(ctx, context) + assert.deepStrictEqual(status.path, ['name']) + assert.strictEqual(typeof status.stack[0], 'function') + + return `${user.firstName} ${user.lastName}` + }, + })(context) + + assert.deepStrictEqual(u.result, [ + { + firstName: 'Dave', + lastName: 'L.', + name: 'Dave L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + name: 'Fred F.', + }, + ]) + }) + + it('paginated result', async () => { + const context = { + method: 'find', + result: { + data: [ + { + firstName: 'Dave', + lastName: 'L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + }, + ], + }, + } as unknown as HookContext + + const u = await resolveResult({ + password: async (): Promise => undefined, + + name: async (_value, user, ctx, status) => { + assert.deepStrictEqual(ctx, context) + assert.deepStrictEqual(status.path, ['name']) + assert.strictEqual(typeof status.stack[0], 'function') + + return `${user.firstName} ${user.lastName}` + }, + })(context) + + assert.deepStrictEqual(u.result.data, [ + { + firstName: 'Dave', + lastName: 'L.', + name: 'Dave L.', + }, + { + firstName: 'Fred', + lastName: 'F.', + name: 'Fred F.', + }, + ]) + }) + + it('resolving with errors', async () => { + const resolver = resolveResult<{ name: string; age: number }>({ + name: async value => { + if (value === 'Dave') { + throw new Error(`No ${value}s allowed`) + } + + return value + }, + age: async value => { + if (value && value < 18) { + throw new BadRequest('Invalid age') + } + + return value + }, + }) + + await assert.rejects( + () => + resolver({ + result: { + name: 'Dave', + age: 16, + }, + } as HookContext), + { + name: 'BadRequest', + message: 'Error resolving data', + code: 400, + className: 'bad-request', + data: { + name: { message: 'No Daves allowed' }, + age: { + name: 'BadRequest', + message: 'Invalid age', + code: 400, + className: 'bad-request', + }, + }, + }, + ) + }) + + it('empty resolver returns original data', async () => { + const result = { message: 'Hello' } + const resolved = await resolveResult({})({ result } as HookContext) + + assert.strictEqual(result, resolved.result) + }) +}) diff --git a/src/resolvers/hooks/resolve-result.ts b/src/resolvers/hooks/resolve-result.ts new file mode 100644 index 00000000..64dc4a66 --- /dev/null +++ b/src/resolvers/hooks/resolve-result.ts @@ -0,0 +1,17 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { resolve, type ResolverObject } from './resolvers.internal.js' +import { replaceResult } from '../../utils/index.js' + +export const resolveResult = , H extends HookContext = HookContext>( + resolverProperties: ResolverObject, +) => { + return async (context: H, next?: NextFunction) => { + if (next) { + await next() + } + + await replaceResult(context, item => resolve(resolverProperties, item, context)) + + return context + } +} diff --git a/src/resolvers/hooks/resolve.ts b/src/resolvers/hooks/resolve.ts new file mode 100644 index 00000000..7942e131 --- /dev/null +++ b/src/resolvers/hooks/resolve.ts @@ -0,0 +1,51 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import type { ResolverObject } from './resolvers.internal.js' +import { resolveData } from './resolve-data.js' +import { resolveQuery } from './resolve-query.js' + +export const resolve = < + T extends Record, + H extends HookContext = HookContext, +>(resolverProperties: { + data?: ResolverObject + query?: ResolverObject + result?: ResolverObject +}) => { + const dataResolver = resolverProperties.data ? resolveData(resolverProperties.data) : undefined + const queryResolver = resolverProperties.query + ? resolveQuery(resolverProperties.query) + : undefined + const resultResolver = resolverProperties.result + ? resolveData(resolverProperties.result) + : undefined + + if (!dataResolver && !queryResolver && !resultResolver) { + throw new Error('At least one resolver must be provided (data, query, or result)') + } + + return async (context: H, next?: NextFunction) => { + if (queryResolver || dataResolver) { + const promisesBefore: Promise[] = [] + + if (queryResolver) { + promisesBefore.push(queryResolver(context, next)) + } + + if (dataResolver) { + promisesBefore.push(dataResolver(context, next)) + } + + await Promise.all(promisesBefore) + } + + if (next) { + await next() + } + + if (resultResolver) { + await resultResolver(context, next) + } + + return context + } +} diff --git a/src/resolvers/hooks/resolvers.internal.ts b/src/resolvers/hooks/resolvers.internal.ts new file mode 100644 index 00000000..4d6b4f32 --- /dev/null +++ b/src/resolvers/hooks/resolvers.internal.ts @@ -0,0 +1,114 @@ +import { BadRequest } from '@feathersjs/errors' +import type { Promisable } from '../../internal.utils.js' + +export type ResolverProperty = ( + value: V | undefined, + obj: T, + context: C, + status: ResolverOptions, +) => Promisable + +export type ResolverObject = { + [key in string]: ResolverProperty< + T, + key extends keyof T ? T[key] : undefined, + C, + key extends keyof T ? T[key] : any + > +} + +export interface ResolverOptions { + path: string[] + stack: ResolverProperty[] + select?: string[] +} + +const resolveProperty = async ( + resolver: ResolverProperty, + name: K, + data: D, + context: C, + status: Partial> = {}, +): Promise => { + const value = (data as any)[name] + const { path = [], stack = [] } = status || {} + + // This prevents circular dependencies + if (stack.includes(resolver)) { + return undefined as any + } + + const resolverStatus = { + ...status, + path: [...path, name as string], + stack: [...stack, resolver], + } + + return await resolver(value, data as any, context, resolverStatus) +} + +export const resolve = async , C>( + resolverProperties: ResolverObject, + data: D, + context: C, + options?: Partial>, +): Promise => { + let propertyNames = Object.keys(resolverProperties) as any as (keyof T)[] + + if (options?.select) { + // If select is defined, filter the properties to only those that are selected + propertyNames = propertyNames.filter(name => options.select!.includes(name as string)) + } + + if (!propertyNames.length) { + // If no properties are defined, return the data as is + return data as any as T + } + + const propertyList = [...new Set(Object.keys(data).concat(propertyNames as string[]))] + + const result: any = {} + const errors: any = {} + let hasErrors = false + + // Not the most elegant but better performance + await Promise.all( + propertyList.map(async name => { + const value = (data as any)[name] + + if (name in resolverProperties) { + const resolverProperty = resolverProperties[name] + try { + const resolved = await resolveProperty( + resolverProperty as any, + name as any, + data, + context, + options, + ) + + if (resolved !== undefined) { + result[name] = resolved + } + } catch (error: any) { + // TODO add error stacks + const convertedError = + typeof error.toJSON === 'function' + ? error.toJSON() + : { message: error.message || error } + + errors[name] = convertedError + hasErrors = true + } + } else if (value !== undefined) { + result[name] = value + } + }), + ) + + if (hasErrors) { + throw new BadRequest('Error resolving data', errors) + } + + return result +} diff --git a/src/resolvers/index.ts b/src/resolvers/index.ts new file mode 100644 index 00000000..fd038e47 --- /dev/null +++ b/src/resolvers/index.ts @@ -0,0 +1 @@ +export * from './hooks/index.js' diff --git a/src/types.ts b/src/types.ts index ff328a60..2e458744 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,28 +1,30 @@ -import type { HookContext } from '@feathersjs/feathers'; +import type { HookContext, Params } from '@feathersjs/feathers' -export const hookTypes = ['around', 'before', 'after', 'error'] as const; -export type HookType = typeof hookTypes[number]; +export const hookTypes = ['around', 'before', 'after', 'error'] as const +export type HookType = (typeof hookTypes)[number] -export const methodNames = ['find', 'get', 'create', 'update', 'patch', 'remove'] as const; -export type MethodName = typeof methodNames[number]; +export const methodNames = ['find', 'get', 'create', 'update', 'patch', 'remove'] as const +export type MethodName = (typeof methodNames)[number] | ({} & string) // allow custom methods -export type TransportName = 'socketio' | 'rest' | 'external' | 'server'; +export type TransportName = 'socketio' | 'rest' | 'external' | 'server' -export type SyncContextFunction = (context: H) => T; +export type SyncContextFunction = (context: H) => T export type AsyncContextFunction = ( - context: H -) => Promise; -export type ContextFunction = ( - context: H -) => T | Promise; - -export type SyncPredicateFn = SyncContextFunction; -export type AsyncPredicateFn = AsyncContextFunction< - boolean, - H ->; -export type PredicateFn = ContextFunction; + context: H, +) => Promise +export type ContextFunction = (context: H) => T | Promise + +export type SyncPredicateFn = (context: H) => boolean +export type AsyncPredicateFn = (context: H) => Promise + +export type PredicateFn = ( + context: H, +) => boolean | Promise export declare type HookFunction = ( - context: H -) => Promise | H | void; + context: H, +) => Promise | H | void + +export type TransformParamsFn

= (params: P) => P | void + +export type DispatchOption = boolean | 'both' diff --git a/test/utils/calling-params-1.test.ts b/src/utils/calling-params/calling-params-1.test.ts similarity index 72% rename from test/utils/calling-params-1.test.ts rename to src/utils/calling-params/calling-params-1.test.ts index cd50d5db..85e0760a 100755 --- a/test/utils/calling-params-1.test.ts +++ b/src/utils/calling-params/calling-params-1.test.ts @@ -1,10 +1,10 @@ -import { assert } from 'vitest'; -import { callingParamsDefaults, callingParams } from '../../src'; +import { assert } from 'vitest' +import { callingParamsDefaults, callingParams } from './calling-params.js' -let context1: any; -let context2: any; -let context3: any; -let context4: any; +let context1: any +let context2: any +let context3: any +let context4: any describe('util calling-params-1.test.js', () => { describe('has defaults', () => { @@ -18,7 +18,7 @@ describe('util calling-params-1.test.js', () => { authenticated: true, provider: 'socketio', }, - }; + } context2 = { params: { query: { aaa: 'bbb' }, @@ -27,7 +27,7 @@ describe('util calling-params-1.test.js', () => { user: { name: 'Matt' }, authenticated: true, }, - }; + } context3 = { params: { query: { aaa: 'bbb' }, @@ -37,7 +37,7 @@ describe('util calling-params-1.test.js', () => { authenticated: true, provider: undefined, }, - }; + } context4 = { params: { query: { aaa: 'bbb' }, @@ -47,33 +47,33 @@ describe('util calling-params-1.test.js', () => { authenticated: true, provider: null, }, - }; - }); + } + }) it('standard defaults', () => { - const res = callingParams()(context1); - // @ts-ignore - assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true, provider: 'socketio' }); - }); + const res = callingParams()(context1) + // @ts-expect-error TODO + assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true, provider: 'socketio' }) + }) it('ignores missing', () => { - const res = callingParams()(context2); - // @ts-ignore - assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true }); - }); + const res = callingParams()(context2) + // @ts-expect-error TODO + assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true }) + }) it('ignores undefined', () => { - const res = callingParams()(context3); - // @ts-ignore - assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true }); - }); + const res = callingParams()(context3) + // @ts-expect-error TODO + assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true }) + }) it('does not ignore null', () => { - const res = callingParams()(context4); - // @ts-ignore - assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true, provider: null }); - }); - }); + const res = callingParams()(context4) + // @ts-expect-error TODO + assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true, provider: null }) + }) + }) describe('can reset defaults', () => { beforeEach(() => { @@ -86,50 +86,50 @@ describe('util calling-params-1.test.js', () => { authenticated: true, provider: 'socketio', }, - }; + } - callingParamsDefaults(['provider', 'authenticated', 'user'], {}); - }); + callingParamsDefaults(['provider', 'authenticated', 'user'], {}) + }) it('check reset to standard defaults', () => { - const res = callingParams()(context1); - // @ts-ignore - assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true, provider: 'socketio' }); - }); + const res = callingParams()(context1) + // @ts-expect-error TODO + assert.deepEqual(res, { user: { name: 'Matt' }, authenticated: true, provider: 'socketio' }) + }) it('change default propNames', () => { - callingParamsDefaults(['foo', 'user.name', 'query.aaa']); - const res = callingParams()(context1); - // @ts-ignore - assert.deepEqual(res, { foo: 'bar', user: { name: 'Matt' }, query: { aaa: 'bbb' } }); - }); + callingParamsDefaults(['foo', 'user.name', 'query.aaa']) + const res = callingParams()(context1) + // @ts-expect-error TODO + assert.deepEqual(res, { foo: 'bar', user: { name: 'Matt' }, query: { aaa: 'bbb' } }) + }) it('change default props', () => { - // @ts-ignore - callingParamsDefaults(null, { bar: 'foo' }); - const res = callingParams()(context1); + // @ts-expect-error TODO + callingParamsDefaults(null, { bar: 'foo' }) + const res = callingParams()(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO user: { name: 'Matt' }, authenticated: true, provider: 'socketio', bar: 'foo', - }); - }); + }) + }) it('change both defaults', () => { - callingParamsDefaults(['foo', 'user.name', 'query.aaa'], { bar: 'foo', qqq: 'rrr' }); - const res = callingParams()(context1); + callingParamsDefaults(['foo', 'user.name', 'query.aaa'], { bar: 'foo', qqq: 'rrr' }) + const res = callingParams()(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO foo: 'bar', user: { name: 'Matt' }, query: { aaa: 'bbb' }, bar: 'foo', qqq: 'rrr', - }); - }); - }); + }) + }) + }) describe('can call', () => { beforeEach(() => { @@ -142,103 +142,103 @@ describe('util calling-params-1.test.js', () => { authenticated: true, provider: 'socketio', }, - }; + } - callingParamsDefaults(['provider', 'authenticated', 'user'], {}); - }); + callingParamsDefaults(['provider', 'authenticated', 'user'], {}) + }) it('default call made by common hooks', () => { - const res = callingParams()(context1); + const res = callingParams()(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO authenticated: true, provider: 'socketio', user: { name: 'Matt' }, - }); - }); + }) + }) it('with query', () => { const res = callingParams({ query: { id: 1 }, - })(context1); + })(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO authenticated: true, provider: 'socketio', user: { name: 'Matt' }, query: { id: 1 }, - }); - }); + }) + }) it('with propNames', () => { const res = callingParams({ propNames: ['foo', 'baz', 'query.aa', 'query.cc'], - })(context1); + })(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO authenticated: true, provider: 'socketio', user: { name: 'Matt' }, foo: 'bar', baz: 'faz', query: { aa: 'a1' }, - }); - }); + }) + }) it('disable 1 hook', () => { const res = callingParams({ hooksToDisable: ['populate'], - })(context1); + })(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO authenticated: true, provider: 'socketio', user: { name: 'Matt' }, _populate: 'skip', - }); - }); + }) + }) it('disable multiple hooks', () => { const res = callingParams({ hooksToDisable: ['populate', 'fastJoin', 'softDelete', 'stashBefore'], - })(context1); + })(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO authenticated: true, provider: 'socketio', user: { name: 'Matt' }, _populate: 'skip', disableStashBefore: true, query: { $disableSoftDelete: true }, - }); - }); + }) + }) it('ignore defaults', () => { let res = callingParams({ ignoreDefaults: true, - })(context1); - assert.deepEqual(res, {}); + })(context1) + assert.deepEqual(res, {}) res = callingParams({ propNames: ['foo', 'baz', 'query.aa', 'query.cc'], ignoreDefaults: true, - })(context1); + })(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO foo: 'bar', baz: 'faz', query: { aa: 'a1' }, - }); - }); + }) + }) it('with multiple options', () => { const res = callingParams({ query: { id: 1 }, propNames: ['foo', 'baz', 'query.aa', 'query.cc'], hooksToDisable: ['populate', 'fastJoin', 'softDelete', 'stashBefore'], - })(context1); + })(context1) assert.deepEqual(res, { - // @ts-ignore + // @ts-expect-error TODO disableStashBefore: true, query: { id: 1, aa: 'a1', $disableSoftDelete: true }, foo: 'bar', @@ -247,7 +247,7 @@ describe('util calling-params-1.test.js', () => { user: { name: 'Matt' }, authenticated: true, provider: 'socketio', - }); - }); - }); -}); + }) + }) + }) +}) diff --git a/test/utils/calling-params-2.test.ts b/src/utils/calling-params/calling-params-2.test.ts similarity index 66% rename from test/utils/calling-params-2.test.ts rename to src/utils/calling-params/calling-params-2.test.ts index 9303e094..c7df200e 100755 --- a/test/utils/calling-params-2.test.ts +++ b/src/utils/calling-params/calling-params-2.test.ts @@ -1,7 +1,7 @@ -import { assert } from 'vitest'; -import { makeCallingParams } from '../../src'; +import { assert } from 'vitest' +import { makeCallingParams } from './calling-params.js' -let context: any; +let context: any describe('util calling-params-2.test.js', () => { beforeEach(() => { @@ -14,59 +14,59 @@ describe('util calling-params-2.test.js', () => { authenticated: true, provider: 'socketio', }, - }; - }); + } + }) it('retains default context', () => { - const res: any = makeCallingParams(context); + const res: any = makeCallingParams(context) assert.deepEqual(res, { _populate: 'skip', user: { name: 'Matt' }, authenticated: true, provider: 'socketio', - }); - }); + }) + }) it('sets query', () => { - const res: any = makeCallingParams(context, { a: 1 }); + const res: any = makeCallingParams(context, { a: 1 }) assert.deepEqual(res, { query: { a: 1 }, _populate: 'skip', user: { name: 'Matt' }, authenticated: true, provider: 'socketio', - }); - }); + }) + }) it('sets include string', () => { - const res: any = makeCallingParams(context, null, 'foo'); - assert.deepEqual(res, { foo: 'bar', _populate: 'skip' }); - }); + const res: any = makeCallingParams(context, null, 'foo') + assert.deepEqual(res, { foo: 'bar', _populate: 'skip' }) + }) it('sets include array', () => { - const res: any = makeCallingParams(context, null, ['foo', 'baz']); - assert.deepEqual(res, { foo: 'bar', baz: 'faz', _populate: 'skip' }); - }); + const res: any = makeCallingParams(context, null, ['foo', 'baz']) + assert.deepEqual(res, { foo: 'bar', baz: 'faz', _populate: 'skip' }) + }) it('sets include skip missing names', () => { - const res: any = makeCallingParams(context, null, ['foo', 'baz', 'x']); - assert.deepEqual(res, { foo: 'bar', baz: 'faz', _populate: 'skip' }); - }); + const res: any = makeCallingParams(context, null, ['foo', 'baz', 'x']) + assert.deepEqual(res, { foo: 'bar', baz: 'faz', _populate: 'skip' }) + }) it('injects', () => { - // @ts-ignore - const res: any = makeCallingParams(context, null, null, { aa: 2 }); - assert.deepEqual(res, { aa: 2, _populate: 'skip' }); - }); + // @ts-expect-error TODO + const res: any = makeCallingParams(context, null, null, { aa: 2 }) + assert.deepEqual(res, { aa: 2, _populate: 'skip' }) + }) it('injects overwrites _populate', () => { - // @ts-ignore - const res: any = makeCallingParams(context, null, null, { _populate: false }); - assert.deepEqual(res, { _populate: false }); - }); + // @ts-expect-error TODO + const res: any = makeCallingParams(context, null, null, { _populate: false }) + assert.deepEqual(res, { _populate: false }) + }) it('all work together', () => { - const res: any = makeCallingParams(context, { a: 1 }, ['foo', 'baz', 'x'], { aa: 2 }); - assert.deepEqual(res, { query: { a: 1 }, foo: 'bar', baz: 'faz', aa: 2, _populate: 'skip' }); - }); -}); + const res: any = makeCallingParams(context, { a: 1 }, ['foo', 'baz', 'x'], { aa: 2 }) + assert.deepEqual(res, { query: { a: 1 }, foo: 'bar', baz: 'faz', aa: 2, _populate: 'skip' }) + }) +}) diff --git a/src/utils/calling-params.ts b/src/utils/calling-params/calling-params.ts similarity index 64% rename from src/utils/calling-params.ts rename to src/utils/calling-params/calling-params.ts index fdd58d31..1de76d3f 100755 --- a/src/utils/calling-params.ts +++ b/src/utils/calling-params/calling-params.ts @@ -1,6 +1,6 @@ -import type { HookContext, Params } from '@feathersjs/feathers'; -import _get from 'lodash/get.js'; -import _set from 'lodash/set.js'; +import type { HookContext, Params } from '@feathersjs/feathers' +import _get from 'lodash/get.js' +import _set from 'lodash/set.js' export type Disablable = | 'populate' @@ -8,37 +8,37 @@ export type Disablable = | 'ignoreDeletedAt' | 'softDelete' | 'softDelete2' - | 'stashBefore'; + | 'stashBefore' export interface CallingParamsOptions { /** * The params.query for the calling params. */ - query?: any; + query?: any /** * The names of the props in context.params to include in the new params. */ - propNames?: string[]; + propNames?: string[] /** * Additional props to add to the new params. */ - newProps?: any; + newProps?: any /** * The names of hooks to disable during the service call. populate, fastJoin, softDelete and stashBefore are supported. */ - hooksToDisable?: Disablable[] | Disablable; + hooksToDisable?: Disablable[] | Disablable /** * Ignore the defaults propNames and newProps. */ - ignoreDefaults?: boolean; + ignoreDefaults?: boolean } -const stndAuthProps = ['provider', 'authenticated', 'user']; // feathers-authentication +const stndAuthProps = ['provider', 'authenticated', 'user'] // feathers-authentication // App wide defaults const defaults = { propNames: stndAuthProps, newProps: {}, -}; +} /** * Set defaults for building params for service calls with callingParams. (Utility function.) @@ -46,11 +46,11 @@ const defaults = { */ export function callingParamsDefaults(propNames: string[], newProps?: any): void { if (propNames) { - defaults.propNames = Array.isArray(propNames) ? propNames : [propNames]; + defaults.propNames = Array.isArray(propNames) ? propNames : [propNames] } if (newProps) { - defaults.newProps = newProps; + defaults.newProps = newProps } } @@ -58,62 +58,62 @@ export function callingParamsDefaults(propNames: string[], newProps?: any): void * Build params for a service call. (Utility function.) * @see https://hooks-common.feathersjs.com/utilities.html#callingparams */ -export function callingParams({ - query, - propNames = [], - newProps = {}, - hooksToDisable = [], - ignoreDefaults, -}: CallingParamsOptions = {}) { - return (context: H) => { - propNames = Array.isArray(propNames) ? propNames : [propNames]; - hooksToDisable = Array.isArray(hooksToDisable) ? hooksToDisable : [hooksToDisable]; +export const callingParams = + ({ + query, + propNames = [], + newProps = {}, + hooksToDisable = [], + ignoreDefaults, + }: CallingParamsOptions = {}) => + (context: H) => { + propNames = Array.isArray(propNames) ? propNames : [propNames] + hooksToDisable = Array.isArray(hooksToDisable) ? hooksToDisable : [hooksToDisable] - const newParams: Params = query ? { query } : {}; - const allPropNames = ignoreDefaults ? propNames : [...defaults.propNames, ...propNames]; + const newParams: Params = query ? { query } : {} + const allPropNames = ignoreDefaults ? propNames : [...defaults.propNames, ...propNames] allPropNames.forEach(name => { if (name) { // for makeCallingParams compatibility - const value = _get(context.params, name); + const value = _get(context.params, name) if (value !== undefined) { - _set(newParams, name, value); + _set(newParams, name, value) } } - }); + }) - Object.assign(newParams, ignoreDefaults ? {} : defaults.newProps, newProps); + Object.assign(newParams, ignoreDefaults ? {} : defaults.newProps, newProps) hooksToDisable.forEach(name => { switch (name) { case 'populate': // fall through case 'fastJoin': - // @ts-ignore - newParams._populate = 'skip'; - break; + // @ts-expect-error TODO + newParams._populate = 'skip' + break case 'softDelete': - newParams.query = newParams.query || {}; - newParams.query.$disableSoftDelete = true; - break; + newParams.query = newParams.query || {} + newParams.query.$disableSoftDelete = true + break case 'softDelete2': - // @ts-ignore - newParams.$disableSoftDelete2 = true; - break; + // @ts-expect-error TODO + newParams.$disableSoftDelete2 = true + break case 'ignoreDeletedAt': - // @ts-ignore - newParams.$ignoreDeletedAt = true; - break; + // @ts-expect-error TODO + newParams.$ignoreDeletedAt = true + break case 'stashBefore': - // @ts-ignore - newParams.disableStashBefore = true; - break; + // @ts-expect-error TODO + newParams.disableStashBefore = true + break } - }); + }) - return newParams; - }; -} + return newParams + } /** * You should prefer using the callingParams utility to makeCallingParams. @@ -136,5 +136,5 @@ export function makeCallingParams( : [include], newProps: Object.assign({}, { _populate: 'skip' }, inject), ignoreDefaults: true, - })(context); + })(context) } diff --git a/src/utils/check-context-if.ts b/src/utils/check-context-if.ts index 23b3f2ef..c195c3d7 100755 --- a/src/utils/check-context-if.ts +++ b/src/utils/check-context-if.ts @@ -1,6 +1,6 @@ -import type { HookContext } from '@feathersjs/feathers'; -import type { MethodName, HookType } from '../types'; -import { checkContext } from './check-context'; +import type { HookContext } from '@feathersjs/feathers' +import type { MethodName, HookType } from '../types.js' +import { checkContext } from './check-context/check-context.js' // TODO: Add checkContextIf to docs /** @@ -16,8 +16,8 @@ export function checkContextIf( label?: string, ) { if (Array.isArray(type) ? !type.includes(context.type) : type !== context.type) { - return; + return } - checkContext(context, type, methods, label); + checkContext(context, type, methods, label) } diff --git a/src/utils/check-context.ts b/src/utils/check-context.ts deleted file mode 100755 index 54fc9e45..00000000 --- a/src/utils/check-context.ts +++ /dev/null @@ -1,35 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { methodNames } from '../types'; -import type { HookType, MethodName } from '../types'; - -/** - * Restrict a hook to run for certain methods and method types. (Utility function.) - * @see https://hooks-common.feathersjs.com/utilities.html#checkcontext - */ -export function checkContext( - context: H, - type?: HookType | HookType[] | null, - methods?: MethodName | MethodName[] | null, - label = 'anonymous', -): void { - if (type) { - const types = Array.isArray(type) ? type : [type]; // safe enough for allowed values - if (!types.includes(context.type)) { - throw new Error(`The '${label}' hook can only be used as a '${type}' hook.`); - } - } - - if (!methods) { - return; - } - if (!methodNames.includes(context.method as any)) { - return; - } // allow custom methods - - const methodsArr = Array.isArray(methods) ? methods : [methods]; // safe enough for allowed values - - if (methodsArr.length > 0 && !methodsArr.includes(context.method as any)) { - const msg = JSON.stringify(methodsArr); - throw new Error(`The '${label}' hook can only be used on the '${msg}' service method(s).`); - } -} diff --git a/src/utils/check-context/check-context.md b/src/utils/check-context/check-context.md new file mode 100644 index 00000000..775a570c --- /dev/null +++ b/src/utils/check-context/check-context.md @@ -0,0 +1,43 @@ +--- +title: checkContext +description: Restrict a hook to run for certain methods and method types. +category: utils +--- + +## Arguments + +- `{Object} context` +- `{String | Array< String >} [ type ]` +- `{String | Array< String >} [ methods ]` +- `{String} [ label ]` + +| Argument | Type | Default | Description | +| --------- | :------: | ---------------- | --------------------------------- | --------------------------------------------------------------- | +| `context` | `Object` | | The hook context. | +| `type` | `String | Array< String >` | all types | The service type allowed - before, after, error. | +| `methods` | `String | Array< String >` | all methods | The service methods allowed - find, get, update, patch, remove. | +| `label` | `String` | `'anonymous'` | Name of hook to use with `throw`. | + +## Example + +```js +const { checkContext } = require('feathers-hooks-common/index.js'); + +function myHook(context) { + checkContext(context, 'after', ['create', 'remove']); + ... +} + +module.exports = { before: { + create: [ myHook ] // throws +} }; + +// checkContext(hook, 'before', ['update', 'patch'], 'hookName'); +// checkContext(hook, null, ['update', 'patch']); +// checkContext(hook, 'before', null, 'hookName'); +// checkContext(hook, 'before'); +``` + +## Details + +Its important to ensure the hook is being used as intended. `checkContext` let's you restrict the hook to a hook type and a set of service methods. diff --git a/src/utils/check-context/check-context.test.ts b/src/utils/check-context/check-context.test.ts new file mode 100755 index 00000000..5bc81079 --- /dev/null +++ b/src/utils/check-context/check-context.test.ts @@ -0,0 +1,77 @@ +import { expect } from 'vitest' + +import { checkContext } from './check-context.js' +import type { HookContext } from '@feathersjs/feathers' + +const make = (type: any, method: any) => ({ type, method }) as HookContext + +describe('util checkContext', () => { + it('handles "any" type and method', () => { + expect(() => checkContext(make('before', 'create'))).not.toThrow() + }) + + it('handles expected type', () => { + expect(() => checkContext(make('before', 'create'), 'before')).not.toThrow() + }) + + it('handles unexpected type', () => { + expect(() => checkContext(make('after', 'create'), 'before')).toThrow() + }) + + it('handles undefined type', () => { + expect(() => checkContext(make('after', 'create'), undefined, 'create')).not.toThrow() + }) + + it('handles null type', () => { + expect(() => checkContext(make('after', 'create'), null, 'create')).not.toThrow() + }) + + it('handles expected type as array', () => { + expect(() => checkContext(make('before', 'create'), ['before', 'after'])).not.toThrow() + }) + + it('handles unexpected type as array', () => { + expect(() => checkContext(make('error', 'create'), ['before', 'after'])).toThrow() + }) + + it('handles expected method as string', () => { + expect(() => checkContext(make('before', 'create'), null, 'create')).not.toThrow() + }) + + it('handles unexpected method as string', () => { + expect(() => checkContext(make('before', 'patch'), null, 'create')).toThrow() + }) + + it('handles expected method as array', () => { + expect(() => + checkContext(make('before', 'create'), null, ['create', 'update', 'remove']), + ).not.toThrow() + }) + + it('handles unexpected method as array', () => { + expect(() => + checkContext(make('before', 'patch'), null, ['create', 'update', 'remove']), + ).toThrow() + }) + + it('handles undefined method', () => { + expect(() => checkContext(make('before', 'patch'), null, undefined)).not.toThrow() + }) + + it('handles null method', () => { + expect(() => checkContext(make('before', 'patch'), null, null)).not.toThrow() + }) + + it('handles expected type and method as array', () => { + expect(() => + checkContext(make('before', 'create'), ['before', 'after'], ['create', 'update', 'remove']), + ).not.toThrow() + }) + + it('allows custom methods', () => { + expect(() => checkContext(make('before', 'custom'), 'before', 'create')).toThrow() + expect(() => + checkContext(make('before', 'custom'), 'before', ['create', 'custom']), + ).not.toThrow() + }) +}) diff --git a/src/utils/check-context/check-context.ts b/src/utils/check-context/check-context.ts new file mode 100755 index 00000000..09126cc6 --- /dev/null +++ b/src/utils/check-context/check-context.ts @@ -0,0 +1,23 @@ +import type { HookContext } from '@feathersjs/feathers' +import type { HookType, MethodName } from '../../types.js' +import { isContext } from '../../predicates/is-context/is-context.js' + +/** + * Restrict a hook to run for certain methods and method types. (Utility function.) + * @see https://hooks-common.feathersjs.com/utilities.html#checkcontext + */ +export function checkContext( + context: H, + type?: HookType | HookType[] | null, + methods?: MethodName | MethodName[] | null, + label = 'anonymous', +): void { + if ( + !isContext({ + method: methods ?? undefined, + type: type ?? undefined, + })(context) + ) { + throw new Error(`The '${label}' hook has invalid context.`) + } +} diff --git a/src/utils/every.ts b/src/utils/every.ts deleted file mode 100755 index ad9d6055..00000000 --- a/src/utils/every.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import type { AsyncPredicateFn, PredicateFn } from '../types'; - -/** - * Return the and of a series of sync or async predicate functions. - * @see https://hooks-common.feathersjs.com/utilities.html#every - */ -export function every( - ...predicates: PredicateFn[] -): AsyncPredicateFn { - return async function (this: any, ...fnArgs: any[]) { - // @ts-ignore - const promises = predicates.map(fn => fn.apply(this, fnArgs)); - - const results = await Promise.all(promises); - return await Promise.resolve(results.every(result => !!result)); - }; -} diff --git a/src/utils/get-data-is-array/get-data-is-array.md b/src/utils/get-data-is-array/get-data-is-array.md new file mode 100644 index 00000000..a8ee3b66 --- /dev/null +++ b/src/utils/get-data-is-array/get-data-is-array.md @@ -0,0 +1,4 @@ +--- +title: getDataIsArray +category: utils +--- diff --git a/src/utils/get-data-is-array/get-data-is-array.test.ts b/src/utils/get-data-is-array/get-data-is-array.test.ts new file mode 100644 index 00000000..d7350fa5 --- /dev/null +++ b/src/utils/get-data-is-array/get-data-is-array.test.ts @@ -0,0 +1,31 @@ +import { getDataIsArray } from './get-data-is-array.js' + +describe('getDataIsArray', () => { + it('falsy data', () => { + expect(getDataIsArray({ data: null } as any)).toEqual({ + isArray: false, + data: [], + }) + + expect(getDataIsArray({ data: undefined } as any)).toEqual({ + isArray: false, + data: [], + }) + }) + + it('array data', () => { + const data = [1, 2, 3] + expect(getDataIsArray({ data } as any)).toEqual({ + isArray: true, + data, + }) + }) + + it('non-array data', () => { + const data = { a: 1, b: 2 } + expect(getDataIsArray({ data } as any)).toEqual({ + isArray: false, + data: [data], + }) + }) +}) diff --git a/src/utils/get-data-is-array/get-data-is-array.ts b/src/utils/get-data-is-array/get-data-is-array.ts new file mode 100644 index 00000000..fac2d82b --- /dev/null +++ b/src/utils/get-data-is-array/get-data-is-array.ts @@ -0,0 +1,19 @@ +import type { HookContext } from '@feathersjs/feathers' + +export function getDataIsArray( + context: H, +): { data: any[]; isArray: boolean } { + if (!context.data) { + return { + isArray: false, + data: [], + } + } + + const isArray = Array.isArray(context.data) + + return { + isArray, + data: isArray ? context.data : [context.data], + } +} diff --git a/src/utils/get-exposed-methods/get-exposed-methods.md b/src/utils/get-exposed-methods/get-exposed-methods.md new file mode 100644 index 00000000..7405a0ba --- /dev/null +++ b/src/utils/get-exposed-methods/get-exposed-methods.md @@ -0,0 +1,4 @@ +--- +title: getExposedMethods +category: utils +--- diff --git a/src/utils/get-exposed-methods/get-exposed-methods.test.ts b/src/utils/get-exposed-methods/get-exposed-methods.test.ts new file mode 100644 index 00000000..55224ad7 --- /dev/null +++ b/src/utils/get-exposed-methods/get-exposed-methods.test.ts @@ -0,0 +1,45 @@ +import { feathers } from '@feathersjs/feathers' +import { MemoryService } from '@feathersjs/memory' +import { getExposedMethods } from './get-exposed-methods.js' + +describe('getExposedMethods', () => { + it('returns an array of exposed methods', () => { + const app = feathers().use('/test', new MemoryService({})) + + expect(getExposedMethods(app.service('test'))).toEqual([ + 'find', + 'get', + 'create', + 'update', + 'patch', + 'remove', + ]) + }) + + it('returns an empty array if no methods are exposed', () => { + const app = feathers().use('/test', new MemoryService({}), { methods: [] }) + expect(getExposedMethods(app.service('test'))).toEqual([]) + }) + + it('returns default methods if no custom methods are provided', () => { + const app = feathers().use('/test', new MemoryService({}), { methods: ['find', 'get'] }) + expect(getExposedMethods(app.service('test'))).toEqual(['find', 'get']) + }) + + it('returns custom methods', () => { + const service = new MemoryService({}) + // @ts-expect-error to allow custom methods + service.customMethod1 = () => {} + // @ts-expect-error to allow custom methods + service.customMethod2 = () => {} + + const app = feathers().use('/test', service, { + methods: ['find', 'customMethod1', 'customMethod2'], + }) + expect(getExposedMethods(app.service('test'))).toEqual([ + 'find', + 'customMethod1', + 'customMethod2', + ]) + }) +}) diff --git a/src/utils/get-exposed-methods/get-exposed-methods.ts b/src/utils/get-exposed-methods/get-exposed-methods.ts new file mode 100644 index 00000000..2689c538 --- /dev/null +++ b/src/utils/get-exposed-methods/get-exposed-methods.ts @@ -0,0 +1,12 @@ +import type { Service } from '@feathersjs/feathers' +import { SERVICE } from '@feathersjs/feathers' + +export function getExposedMethods(service: Service) { + const result = (service as any)[SERVICE].methods + + if (!result || !Array.isArray(result)) { + throw new Error(`Service does not have exposed methods`) + } + + return result +} diff --git a/src/utils/get-items/get-items.test.ts b/src/utils/get-items/get-items.test.ts new file mode 100644 index 00000000..c86708d5 --- /dev/null +++ b/src/utils/get-items/get-items.test.ts @@ -0,0 +1,117 @@ +import { assert } from 'vitest' +import { getItems } from './get-items.js' + +describe('getItems', () => { + it('updates hook before::create item', () => { + assert.deepEqual( + getItems({ + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: { first: 'John', last: 'Doe' }, + } as any), + { first: 'John', last: 'Doe' }, + ) + }) + + it('updates hook before::create items', () => { + assert.deepEqual( + getItems({ + type: 'before', + method: 'create', + params: { provider: 'rest' }, + data: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } as any), + [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + ) + }) + + it('updates hook after::create item', () => { + assert.deepEqual( + getItems({ + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: { first: 'Jane2', last: 'Doe2' }, + } as any), + { first: 'Jane2', last: 'Doe2' }, + ) + }) + + it('updates hook after::create items', () => { + assert.deepEqual( + getItems({ + type: 'after', + method: 'create', + params: { provider: 'rest' }, + result: [ + { first: 'John2', last: 'Doe2' }, + { first: 'Jane', last: 'Doe' }, + ], + } as any), + [ + { first: 'John2', last: 'Doe2' }, + { first: 'Jane', last: 'Doe' }, + ], + ) + }) + + it('updates hook after::find item', () => { + assert.deepEqual( + getItems({ + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: { + total: 2, + data: [ + { first: 'John3', last: 'Doe3' }, + { first: 'Jane3', last: 'Doe3' }, + ], + }, + } as any), + [ + { first: 'John3', last: 'Doe3' }, + { first: 'Jane3', last: 'Doe3' }, + ], + ) + }) + + it('updates hook after::find item paginated', () => { + assert.deepEqual( + getItems({ + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + } as any), + [ + { first: 'John', last: 'Doe' }, + { first: 'Jane', last: 'Doe' }, + ], + ) + }) + + it('does not throw on before without data', () => { + assert.equal( + getItems({ type: 'before', method: 'create', params: { provider: 'rest' } } as any), + undefined, + ) + }) + + it('does not throw on after without data', () => { + assert.equal( + getItems({ type: 'after', method: 'find', params: { provider: 'rest' } } as any), + undefined, + ) + }) +}) diff --git a/src/utils/get-items.ts b/src/utils/get-items/get-items.ts similarity index 72% rename from src/utils/get-items.ts rename to src/utils/get-items/get-items.ts index de69848b..72796ffd 100755 --- a/src/utils/get-items.ts +++ b/src/utils/get-items/get-items.ts @@ -1,15 +1,15 @@ -import type { HookContext } from '@feathersjs/feathers'; +import type { HookContext } from '@feathersjs/feathers' /** * Get the records in context.data or context.result[.data]. (Utility function.) * * @see https://hooks-common.feathersjs.com/utilities.html#getitems + * + * @deprecated Use `getDataIsArray` or `getResultIsArray` instead. */ export function getItems(context: H): any { - // @ts-ignore - if (context.params && context.params._actOn === 'dispatch') return context.dispatch; + if (context.params && context.params._actOn === 'dispatch') return context.dispatch - const items = context.type === 'before' ? context.data : context.result; - // @ts-ignore - return items && context.method === 'find' ? items.data || items : items; + const items = context.type === 'before' ? context.data : context.result + return items && context.method === 'find' ? items.data || items : items } diff --git a/src/utils/get-paginate/get-paginate.md b/src/utils/get-paginate/get-paginate.md new file mode 100644 index 00000000..ca19afa4 --- /dev/null +++ b/src/utils/get-paginate/get-paginate.md @@ -0,0 +1,4 @@ +--- +title: getPaginate +category: utils +--- diff --git a/src/utils/get-paginate/get-paginate.test.ts b/src/utils/get-paginate/get-paginate.test.ts new file mode 100644 index 00000000..a23c2f90 --- /dev/null +++ b/src/utils/get-paginate/get-paginate.test.ts @@ -0,0 +1,73 @@ +import type { HookContext } from '@feathersjs/feathers' +import { getPaginate } from './get-paginate.js' + +describe('getPaginate', () => { + it('returns service.options.paginate', function () { + const serviceOptions = { + paginate: { + default: 10, + max: 50, + }, + } + + const paginate = getPaginate({ + params: {}, + service: { + options: serviceOptions, + }, + } as HookContext) + + assert.deepStrictEqual(paginate, { default: 10, max: 50 }) + }) + + it('returns undefined for params.paginate: false', function () { + const serviceOptions = { + paginate: { + default: 10, + max: 50, + }, + } + + const paginate = getPaginate({ + params: { paginate: false }, + service: { + options: serviceOptions, + }, + } as HookContext) + + assert.deepStrictEqual(paginate, undefined) + }) + + it('returns context.adapter.paginate over service.options.paginate', function () { + const serviceOptions = { + paginate: { + default: 10, + max: 50, + }, + } + + const paginate = getPaginate({ + params: { adapter: { paginate: { default: 20, max: 100 } } }, + service: { + options: serviceOptions, + }, + } as HookContext) + + assert.deepStrictEqual(paginate, { default: 20, max: 100 }) + }) + + it('returns undefined for no paginate', function () { + const serviceOptions = { + paginate: false, + } + + const paginate = getPaginate({ + params: {}, + service: { + options: serviceOptions, + }, + } as HookContext) + + assert.deepStrictEqual(paginate, undefined) + }) +}) diff --git a/src/utils/get-paginate/get-paginate.ts b/src/utils/get-paginate/get-paginate.ts new file mode 100644 index 00000000..f75e7fc0 --- /dev/null +++ b/src/utils/get-paginate/get-paginate.ts @@ -0,0 +1,29 @@ +import type { PaginationOptions } from '@feathersjs/adapter-commons' +import type { HookContext } from '@feathersjs/feathers' +import { hasOwnProperty } from '../../internal.utils.js' + +/** + * util to get paginate options from context + * 1. it uses `context.params.paginate` if it exists + * 2. it uses `service.options.paginate` if it exists + * 3. it uses `context.params.adapter` if it exists + */ +export const getPaginate = ( + context: H, +): PaginationOptions | undefined => { + if (hasOwnProperty(context.params, 'paginate')) { + return (context.params.paginate as PaginationOptions) || undefined + } + + if (context.params.paginate === false) { + return undefined + } + let options = context.service?.options || {} + + options = { + ...options, + ...context.params.adapter, + } + + return options.paginate || undefined +} diff --git a/src/utils/get-result-is-array/get-result-is-array.md b/src/utils/get-result-is-array/get-result-is-array.md new file mode 100644 index 00000000..0f9ed452 --- /dev/null +++ b/src/utils/get-result-is-array/get-result-is-array.md @@ -0,0 +1,4 @@ +--- +title: getResultIsArray +category: utils +--- diff --git a/src/utils/get-result-is-array/get-result-is-array.test.ts b/src/utils/get-result-is-array/get-result-is-array.test.ts new file mode 100644 index 00000000..8a729fb3 --- /dev/null +++ b/src/utils/get-result-is-array/get-result-is-array.test.ts @@ -0,0 +1,139 @@ +import { getResultIsArray } from './get-result-is-array.js' + +describe('getResultIsArray', () => { + it('falsy result', () => { + expect(getResultIsArray({ result: null } as any)).toEqual({ + isArray: false, + result: [], + key: 'result', + }) + + expect(getResultIsArray({} as any)).toEqual({ + isArray: false, + result: [], + key: 'result', + }) + }) + + it('array result', () => { + const result = [1, 2, 3] + expect(getResultIsArray({ result } as any)).toEqual({ + isArray: true, + result, + key: 'result', + }) + + expect(getResultIsArray({ method: 'find', result } as any)).toEqual({ + isArray: true, + result, + key: 'result', + }) + + expect(getResultIsArray({ method: 'find', result: { data: result } } as any)).toEqual({ + isArray: true, + result, + key: 'result', + }) + }) + + it('non-array result', () => { + const result = { a: 1, b: 2 } + expect(getResultIsArray({ result } as any)).toEqual({ + isArray: false, + result: [result], + key: 'result', + }) + + expect(getResultIsArray({ method: 'find', result } as any)).toEqual({ + isArray: false, + result: [result], + key: 'result', + }) + + expect(getResultIsArray({ method: 'find', result: { data: result } } as any)).toEqual({ + isArray: false, + result: [result], + key: 'result', + }) + }) + + it('dispatch', () => { + const result = { a: 1, b: 2 } + const dispatch = { c: 3, d: 4 } + expect(getResultIsArray({ result, dispatch } as any, { dispatch: true })).toEqual({ + isArray: false, + result: [dispatch], + key: 'dispatch', + }) + + expect( + getResultIsArray({ method: 'find', result, dispatch } as any, { dispatch: true }), + ).toEqual({ + isArray: false, + result: [dispatch], + key: 'dispatch', + }) + + expect( + getResultIsArray({ method: 'find', result: { data: result }, dispatch } as any, { + dispatch: true, + }), + ).toEqual({ + isArray: false, + result: [dispatch], + key: 'dispatch', + }) + }) + + it('returns dispatch if is missing with single result', () => { + const result = { a: 1, b: 2 } + const context = { result } as any + expect(getResultIsArray(context, { dispatch: true })).toEqual({ + isArray: false, + result: [result], + key: 'result', + }) + expect(context.dispatch).toEqual(undefined) + }) + + it("doesn't set dispatch if is missing with array result", () => { + const result = [{ a: 1, b: 2 }] + const context = { method: 'create', result } as any + + expect(getResultIsArray(context, { dispatch: true })).toEqual({ + isArray: true, + result: result, + key: 'result', + }) + expect(context.dispatch).toEqual(undefined) + }) + + it("doesn't set dispatch if is missing with find array", () => { + const result = [{ a: 1, b: 2 }] + const dispatch = undefined + const context = { method: 'find', result, dispatch } as any + + expect(getResultIsArray(context, { dispatch: true })).toEqual({ + isArray: true, + result, + key: 'result', + }) + }) + + it('sets dispatch if is missing with paginated result', () => { + const result = [{ a: 1, b: 2 }] + const dispatch = undefined + const context = { method: 'find', result: { data: result, total: 3 }, dispatch } as any + + expect( + getResultIsArray(context, { + dispatch: true, + }), + ).toEqual({ + isArray: true, + result, + key: 'result', + }) + expect(context.dispatch).toEqual(undefined) + }) +}) diff --git a/src/utils/get-result-is-array/get-result-is-array.ts b/src/utils/get-result-is-array/get-result-is-array.ts new file mode 100644 index 00000000..bdb2ad49 --- /dev/null +++ b/src/utils/get-result-is-array/get-result-is-array.ts @@ -0,0 +1,35 @@ +import type { HookContext } from '@feathersjs/feathers' +import copy from 'fast-copy' + +type GetResultIsArrayOptions = { + dispatch?: boolean +} + +export function getResultIsArray( + context: H, + options?: GetResultIsArrayOptions, +): { isArray: boolean; result: any[]; key: 'dispatch' | 'result' } { + const { dispatch = false } = options || {} + + const isDispatch: boolean = dispatch && context.dispatch !== undefined + + const result = dispatch ? (isDispatch ? context.dispatch : copy(context.result)) : context.result + + if (!result) { + return { + isArray: false, + result: [], + key: isDispatch ? 'dispatch' : 'result', + } + } + + const items = context.method === 'find' ? result.data || result : result + + const isArray = Array.isArray(items) + + return { + isArray, + result: isArray ? items : items ? [items] : [], + key: isDispatch ? 'dispatch' : 'result', + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts new file mode 100644 index 00000000..4d806186 --- /dev/null +++ b/src/utils/index.ts @@ -0,0 +1,13 @@ +export * from './calling-params/calling-params.js' +export * from './check-context-if.js' +export * from './check-context/check-context.js' +export * from './get-data-is-array/get-data-is-array.js' +export * from './get-exposed-methods/get-exposed-methods.js' +export * from './get-items/get-items.js' +export * from './get-paginate/get-paginate.js' +export * from './get-result-is-array/get-result-is-array.js' +export * from './replace-data/replace-data.js' +export * from './replace-items/replace-items.js' +export * from './replace-result/replace-result.js' +export * from './skip-result/skip-result.js' +export * from './transform-params/transform-params.js' diff --git a/src/utils/is-not.ts b/src/utils/is-not.ts deleted file mode 100755 index fa6b359d..00000000 --- a/src/utils/is-not.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MethodNotAllowed } from '@feathersjs/errors'; -import type { HookContext } from '@feathersjs/feathers'; -import { isPromise } from '../common'; -import type { PredicateFn } from '../types'; - -/** - * Negate a sync or async predicate function. - * - * @see https://hooks-common.feathersjs.com/utilities.html#isnot - */ -export function isNot( - predicate: boolean | PredicateFn, -): PredicateFn { - if (typeof predicate !== 'function') { - throw new MethodNotAllowed('Expected function as param. (isNot)'); - } - - return (context: H) => { - const result = predicate(context); // Should we pass a clone? (safety vs performance) - - if (!isPromise(result)) { - return !result; - } - - return result.then(result1 => !result1); - }; -} diff --git a/src/utils/params-for-server.ts b/src/utils/params-for-server.ts deleted file mode 100755 index eeec4eb1..00000000 --- a/src/utils/params-for-server.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { Params } from '@feathersjs/feathers'; - -/** - * Pass an explicit context.params from client to server. Client-side. (Utility function.) - * - * @see https://hooks-common.feathersjs.com/utilities.html#paramsforserver - */ -export function paramsForServer(params?: Params, ...whitelist: string[]): Params { - const ifWhitelist = !!whitelist.length; - const _params: Record = Object.assign({}, params); - - _params.query = _params.query || {}; - _params.query.$client = _params.query.$client || {}; - - Object.keys(_params).forEach(key => { - if (key !== 'query') { - if (!ifWhitelist || whitelist.includes(key)) { - _params.query.$client[key] = _params[key]; - } - - delete _params[key]; - } - }); - - return _params; -} diff --git a/src/utils/replace-data/replace-data.md b/src/utils/replace-data/replace-data.md new file mode 100644 index 00000000..cd6a4d99 --- /dev/null +++ b/src/utils/replace-data/replace-data.md @@ -0,0 +1,4 @@ +--- +title: replaceData +category: utils +--- diff --git a/src/utils/replace-data/replace-data.ts b/src/utils/replace-data/replace-data.ts new file mode 100644 index 00000000..6a263230 --- /dev/null +++ b/src/utils/replace-data/replace-data.ts @@ -0,0 +1,43 @@ +import type { HookContext } from '@feathersjs/feathers' +import { getDataIsArray } from '../get-data-is-array/get-data-is-array.js' +import { isPromise } from '../../common/index.js' +import type { Promisable } from '../../internal.utils.js' + +export function replaceData( + context: H, + cb: (item: any) => any, +): Promisable { + if (!context.data) { + return context + } + + const { data, isArray } = getDataIsArray(context) + + if (!data.length) { + return context + } + + let hasPromises = false + + const results = data.map(item => { + const result = cb(item) + + if (!hasPromises && isPromise(result)) { + hasPromises = true + } + + return result + }) + + function replace(data: any) { + context.data = isArray ? data : data[0] + + return context + } + + if (hasPromises) { + return Promise.all(results).then(replace) + } else { + return replace(results) + } +} diff --git a/src/utils/replace-items/replace-items.test.ts b/src/utils/replace-items/replace-items.test.ts new file mode 100644 index 00000000..2cdb3a1c --- /dev/null +++ b/src/utils/replace-items/replace-items.test.ts @@ -0,0 +1,71 @@ +import { assert } from 'vitest' +import { replaceItems } from './replace-items.js' + +// Tests when context.params._actOn === 'dispatch' are in act-on.test.ts +describe('replaceItems', () => { + let hookBefore: any + let hookAfter: any + let hookFindPaginate: any + let hookFind: any + + beforeEach(() => { + hookBefore = { type: 'before', method: 'create', params: { provider: 'rest' } } + hookAfter = { type: 'after', method: 'create', params: { provider: 'rest' } } + hookFindPaginate = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + result: { + total: 200, + data: [], + }, + } + hookFind = { + type: 'after', + method: 'find', + params: { provider: 'rest' }, + } + }) + + it('updates hook before::create item', () => { + replaceItems(hookBefore, { a: 1 }) + assert.deepEqual(hookBefore.data, { a: 1 }) + }) + + it('updates hook before::create items', () => { + replaceItems(hookBefore, [{ a: 1 }, { b: 2 }]) + assert.deepEqual(hookBefore.data, [{ a: 1 }, { b: 2 }]) + }) + + it('updates hook after::create item', () => { + replaceItems(hookAfter, { a: 1 }) + assert.deepEqual(hookAfter.result, { a: 1 }) + }) + + it('updates hook after::create items', () => { + replaceItems(hookAfter, [{ a: 1 }, { b: 2 }]) + assert.deepEqual(hookAfter.result, [{ a: 1 }, { b: 2 }]) + }) + + it('updates hook after::find item', () => { + replaceItems(hookFind, { a: 1 }) + assert.deepEqual(hookFind.result, { a: 1 }) + }) + + it('updates hook after::find items', () => { + replaceItems(hookFind, [{ a: 1 }, { b: 2 }]) + assert.deepEqual(hookFind.result, [{ a: 1 }, { b: 2 }]) + }) + + it('updates hook after::find item paginated NOTE THIS TEST NOTE THIS TEST', () => { + replaceItems(hookFindPaginate, { a: 1 }) + assert.equal(hookFindPaginate.result.total, 200) + assert.deepEqual(hookFindPaginate.result.data, [{ a: 1 }]) + }) + + it('updates hook after::find items paginated', () => { + replaceItems(hookFindPaginate, [{ a: 1 }, { b: 2 }]) + assert.equal(hookFindPaginate.result.total, 200) + assert.deepEqual(hookFindPaginate.result.data, [{ a: 1 }, { b: 2 }]) + }) +}) diff --git a/src/utils/replace-items.ts b/src/utils/replace-items/replace-items.ts similarity index 75% rename from src/utils/replace-items.ts rename to src/utils/replace-items/replace-items.ts index de0e8e1e..b5a03113 100755 --- a/src/utils/replace-items.ts +++ b/src/utils/replace-items/replace-items.ts @@ -1,25 +1,26 @@ -import type { HookContext } from '@feathersjs/feathers'; +import type { HookContext } from '@feathersjs/feathers' /** * Replace the records in context.data or context.result[.data]. (Utility function.) * @see https://hooks-common.feathersjs.com/utilities.html#replaceitems + * + * @deprecated Use `replaceData` or `replaceResult` instead. */ export function replaceItems(context: H, items: any): void { - // @ts-ignore if (context.params && context.params._actOn === 'dispatch') { if (context.method === 'find' && context.dispatch?.data) { - context.dispatch.data = Array.isArray(items) ? items : [items]; + context.dispatch.data = Array.isArray(items) ? items : [items] } else { - context.dispatch = items; + context.dispatch = items } - return; + return } if (context.type === 'before') { - context.data = items; + context.data = items } else if (context.method === 'find' && context.result && context.result.data) { - context.result.data = Array.isArray(items) ? items : [items]; + context.result.data = Array.isArray(items) ? items : [items] } else { - context.result = items; + context.result = items } } diff --git a/src/utils/replace-result/replace-result.md b/src/utils/replace-result/replace-result.md new file mode 100644 index 00000000..18c317e3 --- /dev/null +++ b/src/utils/replace-result/replace-result.md @@ -0,0 +1,4 @@ +--- +title: replaceResult +category: utils +--- diff --git a/src/utils/replace-result/replace-result.test.ts b/src/utils/replace-result/replace-result.test.ts new file mode 100644 index 00000000..0b5c0b71 --- /dev/null +++ b/src/utils/replace-result/replace-result.test.ts @@ -0,0 +1,169 @@ +import { expect } from 'vitest' +import { replaceResult } from './replace-result.js' + +// Tests when context.params._actOn === 'dispatch' are in act-on.test.ts +describe('replaceResult', () => { + it("replaces context.result on paginated 'find'", async () => { + const context = { + method: 'find', + result: { total: 2, data: [{ id: 1 }, { id: 2 }] }, + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual({ total: 2, data: [{ id: 2 }, { id: 3 }] }) + }) + + it("replaces context.result on array 'find'", async () => { + const context = { + method: 'find', + result: [{ id: 1 }, { id: 2 }], + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual([{ id: 2 }, { id: 3 }]) + }) + + it("replaces context.result on 'get'", async () => { + const context = { + method: 'find', + id: 1, + result: { id: 1 }, + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual({ id: 2 }) + }) + + it("replaces context.result on 'create'", async () => { + const context = { + method: 'create', + result: { id: 1 }, + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual({ id: 2 }) + }) + + it("replaces context.result on multi:'create'", async () => { + const context = { + method: 'create', + result: [{ id: 1 }, { id: 2 }], + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual([{ id: 2 }, { id: 3 }]) + }) + + it('replaces context.result on update', async () => { + const context = { + method: 'update', + id: 1, + result: { id: 1 }, + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual({ id: 2 }) + }) + + it('replaces context.result on patch', async () => { + const context = { + method: 'patch', + id: 1, + result: { id: 1 }, + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual({ id: 2 }) + }) + + it('replaces context.result on multi patch', async () => { + const context = { + method: 'patch', + id: null, + result: [{ id: 1 }, { id: 2 }], + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual([{ id: 2 }, { id: 3 }]) + }) + + it('replaces context.result on remove', async () => { + const context = { + method: 'remove', + id: 1, + result: { id: 1 }, + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual({ id: 2 }) + }) + + it('replaces context.result on multi remove', async () => { + const context = { + method: 'remove', + id: null, + result: [{ id: 1 }, { id: 2 }], + } + + await replaceResult(context as any, item => ({ id: item.id + 1 })) + + expect(context.result).toStrictEqual([{ id: 2 }, { id: 3 }]) + }) + + it("replaces context.dispatch on 'get'", async () => { + const context = { + method: 'find', + id: 1, + result: { result: true }, + dispatch: { dispatch: true }, + } + + await replaceResult(context as any, item => ({ ...item, test: true }), { dispatch: true }) + + expect(context.result).toStrictEqual({ result: true }) + expect(context.dispatch).toStrictEqual({ dispatch: true, test: true }) + }) + + it("replaces both context.result & context.dispatch on 'get'", async () => { + const context = { + method: 'find', + id: 1, + result: { result: true }, + dispatch: { dispatch: true }, + } + + await replaceResult(context as any, item => ({ ...item, test: true }), { dispatch: 'both' }) + + expect(context.result).toStrictEqual({ result: true, test: true }) + expect(context.dispatch).toStrictEqual({ dispatch: true, test: true }) + }) + + it("replaces context.dispatch even though it was not there before on 'get'", async () => { + const context = { + method: 'find', + id: 1, + result: { result: true }, + } as any + + await replaceResult( + context as any, + item => { + item.test = true + return item + }, + { dispatch: true }, + ) + + expect(context.result).toStrictEqual({ result: true }) + expect(context.dispatch).toStrictEqual({ result: true, test: true }) + }) +}) diff --git a/src/utils/replace-result/replace-result.ts b/src/utils/replace-result/replace-result.ts new file mode 100644 index 00000000..4db5270d --- /dev/null +++ b/src/utils/replace-result/replace-result.ts @@ -0,0 +1,74 @@ +import type { HookContext, NextFunction } from '@feathersjs/feathers' +import { getResultIsArray } from '../get-result-is-array/get-result-is-array.js' +import { isPromise } from '../../common/index.js' +import copy from 'fast-copy' +import type { DispatchOption } from '../../types.js' + +export type ReplaceResultOptions = { + next?: NextFunction + transform?: (items: any[]) => any[] + dispatch?: DispatchOption +} + +export async function replaceResult( + context: H, + cb: (item: any) => any, + options?: ReplaceResultOptions, +): Promise { + if (options?.next) { + await options.next() + } + + if (!!options?.dispatch && !context.dispatch) { + context.dispatch = copy(context.result) + } + + async function forResult(dispatch: boolean) { + const { result, isArray, key } = getResultIsArray(context, { dispatch }) + + if (!result.length) { + return context + } + + let hasPromises = false + + const results = result.map(item => { + const result = cb(item) + + if (!hasPromises && isPromise(result)) { + hasPromises = true + } + + return result + }) + + function replace(r: any) { + if (options?.transform) { + r = options.transform(r) + } + + if (!isArray) { + context[key] = r[0] + } else if (isArray && !Array.isArray(context[key]) && context[key].data) { + context[key].data = r + } else { + context[key] = r + } + + return context + } + + if (hasPromises) { + return await Promise.all(results).then(replace) + } else { + return replace(results) + } + } + + if (options?.dispatch === 'both') { + await Promise.all([forResult(true), forResult(false)]) + return context + } + + return await forResult(options?.dispatch ?? false) +} diff --git a/src/utils/run-hook.ts b/src/utils/run-hook.ts deleted file mode 100755 index 706b08f4..00000000 --- a/src/utils/run-hook.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { HookContext, Paginated } from '@feathersjs/feathers'; - -/** - * Let's you call a hook right after the service call. (Utility function.) - * @see https://hooks-common.feathersjs.com/utilities.html#runhook - */ -export function runHook( - context?: H, -): (hook: any) => (data: any[] | Paginated) => Promise { - const extraContent = context; // cannot access extraContent1 below. why not? - - return hookFunc => result => { - const ctx = Object.assign({}, { type: 'after', params: {}, result }, extraContent); - - // @ts-ignore - if (typeof result === 'object' && result !== null && result.total && result.data) { - // @ts-expect-error method is readonly - ctx.method = 'find'; - } - - return ( - Promise.resolve() - // @ts-ignore - .then(() => hookFunc(ctx)) - .then(newContext => { - if (!newContext) { - return; - } - - const result = newContext.result; - - if (typeof result === 'object' && result !== null && result.total && result.data) { - // find - return newContext.result; - } - - return newContext.result.data || newContext.result; - }) - ); - }; -} diff --git a/src/utils/skip-result/skip-result.md b/src/utils/skip-result/skip-result.md new file mode 100644 index 00000000..9a4a704a --- /dev/null +++ b/src/utils/skip-result/skip-result.md @@ -0,0 +1,4 @@ +--- +title: skipResult +category: utils +--- diff --git a/src/utils/skip-result/skip-result.test.ts b/src/utils/skip-result/skip-result.test.ts new file mode 100644 index 00000000..61ca099d --- /dev/null +++ b/src/utils/skip-result/skip-result.test.ts @@ -0,0 +1,260 @@ +import type { HookContext } from '@feathersjs/feathers' +import { skipResult } from './skip-result.js' + +describe('skipResult', function () { + const paginatedService = { + options: { + paginate: { + default: 10, + max: 50, + }, + }, + } + + const nonPaginatedService = { + options: { + paginate: false, + }, + } + + const paramsEmpty = {} + const paramsPaginateFalse = { paginate: false } + const paramsPaginate = { paginate: { default: 10, max: 50 } } + const paramsAdapterPaginate = { + adapter: { paginate: { default: 10, max: 50 } }, + } + + it('does not overwrite result', function () { + ;['find', 'get', 'create', 'update', 'patch', 'remove'].forEach(method => { + ;['before', 'after'].forEach(type => { + ;[paginatedService, nonPaginatedService].forEach(service => { + ;[paramsPaginateFalse, paramsAdapterPaginate].forEach(params => { + const context = skipResult({ + method, + type, + service, + params, + result: 123, + } as any as HookContext) + + assert.deepStrictEqual( + context.result, + 123, + `result is not changed. '${type}:${method}': '${service}' - '${params}'`, + ) + }) + }) + }) + }) + }) + + describe('find', function () { + it('sets paginated result', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'find', + } as any as HookContext) + assert.deepStrictEqual( + result, + { total: 0, skip: 0, limit: 0, data: [] }, + `'${i}': result is paginated empty`, + ) + }) + }) + + it('sets empty array', function () { + const combos = [ + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsEmpty }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'find', + } as any as HookContext) + assert.deepStrictEqual(result, [], `'${i}': result is empty array`) + }) + }) + }) + + describe('get', function () { + it('sets result to null', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'get', + } as any as HookContext) + assert.deepStrictEqual(result, null, `'${i}': result is null`) + }) + }) + }) + + describe('create', function () { + it('sets result to null for single data', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'create', + data: { id: 1 }, + } as any as HookContext) + assert.deepStrictEqual(result, null, `'${i}': result is null`) + }) + }) + + it('sets result to empty array for array data', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'create', + data: [{ id: 1 }], + type: 'before', + } as any as HookContext) + assert.deepStrictEqual(result, [], `'${i}': result is empty array`) + }) + }) + }) + + describe('update', function () { + it('sets result to null', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'update', + id: 1, + } as any as HookContext) + assert.deepStrictEqual(result, null, `'${i}': result is null`) + }) + }) + }) + + describe('patch', function () { + it('sets result to null for id: 1', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'patch', + id: 1, + } as any as HookContext) + assert.deepStrictEqual(result, null, `'${i}': result is null`) + }) + }) + + it('sets result to empty array for id: null', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'patch', + id: null, + } as any as HookContext) + assert.deepStrictEqual(result, [], `'${i}': result is empty array`) + }) + }) + }) + + describe('remove', function () { + it('sets result to null for id: 1', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'remove', + id: 1, + } as any as HookContext) + assert.deepStrictEqual(result, null, `'${i}': result is null`) + }) + }) + + it('sets result to empty array for id: null', function () { + const combos = [ + { service: paginatedService, params: paramsEmpty }, + { service: paginatedService, params: paramsAdapterPaginate }, + { service: paginatedService, params: paramsPaginateFalse }, + { service: nonPaginatedService, params: paramsPaginate }, + { service: nonPaginatedService, params: paramsAdapterPaginate }, + ] + + combos.forEach(({ service, params }, i) => { + const { result } = skipResult({ + service, + params, + method: 'remove', + id: null, + } as any as HookContext) + assert.deepStrictEqual(result, [], `'${i}': result is empty array`) + }) + }) + }) +}) diff --git a/src/utils/skip-result/skip-result.ts b/src/utils/skip-result/skip-result.ts new file mode 100644 index 00000000..8caa299d --- /dev/null +++ b/src/utils/skip-result/skip-result.ts @@ -0,0 +1,30 @@ +import type { HookContext } from '@feathersjs/feathers' +import { isMulti, isPaginated } from '../../predicates/index.js' + +/** + * util to set `context.result` to an empty array or object, depending on the hook type + */ +export const skipResult = (context: H) => { + if (context.result) { + return context + } + + const multi = isMulti(context) + + if (multi) { + if (context.method === 'find' && isPaginated(context)) { + context.result = { + total: 0, + skip: 0, + limit: 0, + data: [], + } + } else { + context.result = [] + } + } else { + context.result = null + } + + return context +} diff --git a/src/utils/some.ts b/src/utils/some.ts deleted file mode 100755 index 7baf1506..00000000 --- a/src/utils/some.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import type { AsyncPredicateFn, PredicateFn } from '../types'; - -/** - * Return the or of a series of sync or async predicate functions. - * @see https://hooks-common.feathersjs.com/utilities.html#some - */ -export function some( - ...predicates: PredicateFn[] -): AsyncPredicateFn { - return async function (this: any, context: H) { - const promises = predicates.map(fn => fn.apply(this, [context])); - - const results = await Promise.all(promises); - return await Promise.resolve(results.some(result => !!result)); - }; -} diff --git a/src/utils/transform-params/transform-params.md b/src/utils/transform-params/transform-params.md new file mode 100644 index 00000000..bbcc0f6c --- /dev/null +++ b/src/utils/transform-params/transform-params.md @@ -0,0 +1,4 @@ +--- +title: transformParams +category: utils +--- diff --git a/src/utils/transform-params/transform-params.ts b/src/utils/transform-params/transform-params.ts new file mode 100644 index 00000000..30eb4a25 --- /dev/null +++ b/src/utils/transform-params/transform-params.ts @@ -0,0 +1,18 @@ +import type { Params } from '@feathersjs/feathers' +import type { TransformParamsFn } from '../../types.js' + +/** + * Safely use a transformParams function to modify params. + */ +export const transformParams =

( + params: P, + fn: TransformParamsFn

| undefined, +): P => { + if (!fn) { + return params + } + + const result = fn({ ...params }) + + return result ?? params +} diff --git a/test/common/traverse.test.ts b/test/common/traverse.test.ts deleted file mode 100755 index 3a498c2b..00000000 --- a/test/common/traverse.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { assert } from 'vitest'; -import { traverse } from '../../src'; - -describe('services traverse', () => { - let hookBefore: any; - let hookBeforeArray: any; - let trimmer: any; - let hookAfter: any; - let hookAfterArray: any; - - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - data: { a: ' a b ' }, - params: { query: { b: ' b b ' } }, - }; - - hookBeforeArray = { - type: 'before', - method: 'create', - data: [{ a: ' a b ' }, { c: ' c ' }], - params: { query: { b: ' b b ' }, something: { c: ' c', d: 'd ' } }, - }; - - hookAfter = { - type: 'after', - method: 'create', - data: { q: 1 }, - params: { query: { b: ' b b ' } }, - result: { a: ' a b ' }, - }; - - hookAfterArray = { - type: 'after', - method: 'create', - data: { q: 1 }, - params: { query: { b: ' b b ' } }, - result: [{ a: ' a b ' }, { c: ' c ' }], - }; - - trimmer = function (this: any, node: any) { - if (typeof node === 'string') { - this.update(node.trim()); - } - }; - }); - - it('transforms hook.data single item', () => { - const result = clone(hookBefore); - result.data = { a: 'a b' }; - - // @ts-ignore - traverse(trimmer)(hookBefore); - - assert.deepEqual(hookBefore, result); - }); - - it('transforms hook.data array of items', () => { - const result = clone(hookBeforeArray); - result.data = [{ a: 'a b' }, { c: 'c' }]; - - // @ts-ignore - traverse(trimmer)(hookBeforeArray); - - assert.deepEqual(hookBeforeArray, result); - }); - - it('transforms hook.result single item', () => { - const result = clone(hookAfter); - result.result = { a: 'a b' }; - - // @ts-ignore - traverse(trimmer)(hookAfter); - - assert.deepEqual(hookAfter, result); - }); - - it('transforms hook.result array of items', () => { - const result = clone(hookAfterArray); - result.result = [{ a: 'a b' }, { c: 'c' }]; - - // @ts-ignore - traverse(trimmer)(hookAfterArray); - - assert.deepEqual(hookAfterArray, result); - }); - - it('transforms hook.params.query', () => { - const result = clone(hookBefore); - result.params.query = { b: 'b b' }; - - // @ts-ignore - traverse(trimmer, (hook: any) => hook.params.query)(hookBefore); - - assert.deepEqual(hookBefore, result); - }); - - it('transforms multiple objects within a hook', () => { - const result = clone(hookBeforeArray); - result.params = { query: { b: 'b b' }, something: { c: 'c', d: 'd' } }; - - // @ts-ignore - traverse(trimmer, (hook: any) => [hook.params.query, hook.params.something])(hookBeforeArray); - - assert.deepEqual(hookBeforeArray, result); - }); - - it('transforms objects', () => { - const obj: any = { query: { b: 'b b' }, something: { c: 'c', d: 'd' } }; - const result = clone(obj); - - // @ts-ignore - traverse(trimmer, obj)(hookBeforeArray); - - assert.deepEqual(obj, result); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/helpers/config-app.ts b/test/helpers/config-app.ts deleted file mode 100755 index b820b03a..00000000 --- a/test/helpers/config-app.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import getInitDb from './get-init-db'; - -export default function (dbNames: any) { - dbNames = typeof dbNames === 'string' ? [dbNames] : dbNames; - const serviceConfigs: any = { - users, - comments, - posts, - recommendation, - }; - - return feathers().configure(services); - - function services(this: any) { - dbNames.forEach((name: any) => { - // console.log(`configure service ${name}`); - this.configure(serviceConfigs[name]); - }); - } - - function users(this: any) { - this.use('users', new MemoryService(getInitDb('users'))); - } - - function comments(this: any) { - this.use('comments', new MemoryService(getInitDb('comments'))); - } - - function posts(this: any) { - this.use('posts', new MemoryService(getInitDb('posts'))); - } - - function recommendation(this: any) { - this.use('recommendation', new MemoryService(getInitDb('recommendation'))); - } -} diff --git a/test/helpers/get-init-db.ts b/test/helpers/get-init-db.ts deleted file mode 100755 index d686dcf1..00000000 --- a/test/helpers/get-init-db.ts +++ /dev/null @@ -1,111 +0,0 @@ -export default function (name: any) { - const users: any = { - 0: { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - 1: { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - }; - - const comments: any = { - 1: { - id: 1, - postId: 1, - title: 'Comment 1', - content: 'Lorem ipsum dolor sit amet 1', - author: 'as61389dadhga62343hads6712', - createdAt: 1480793101559, - }, - 2: { - id: 2, - postId: 2, - title: 'Comment 2', - content: 'Lorem ipsum dolor sit amet 2', - author: 'as61389dadhga62343hads6712', - createdAt: 1480793101559, - }, - 3: { - id: 3, - postId: 1, - title: 'Comment 3', - content: 'Lorem ipsum dolor sit amet 3', - author: '167asdf3689348sdad7312131s', - createdAt: 1480793101559, - }, - }; - - const posts: any = { - 1: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - 2: { - id: 2, - title: 'Post 2', - content: 'Lorem ipsum dolor sit amet 5', - author: '167asdf3689348sdad7312131s', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - 3: { - id: 3, - title: 'Post 3', - content: 'Lorem ipsum dolor sit amet 5', - author: '167asdf3689348sdad7312131s', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - 4: { - id: 4, - title: 'Post 4', - content: 'Lorem ipsum dolor sit amet 5', - author: '167asdf3689348sdad7312131s', - readers: [], - createdAt: 1480793101559, - }, - }; - - const recommendation: any = { - 1: { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }, - 2: { - userId: 'as61389dadhga62343hads6712', - postId: 2, - updatedAt: 1480793101475, - }, - 3: { - userId: '167asdf3689348sdad7312131s', - postId: 1, - updatedAt: 1480793101475, - }, - }; - - const dbs: any = { - users, - comments, - posts, - recommendation, - }; - - // console.log(`returning db for ${name}`); - return { - store: dbs[name], - idField: '_id', - }; -} diff --git a/test/helpers/make-services.ts b/test/helpers/make-services.ts deleted file mode 100755 index 85d2e533..00000000 --- a/test/helpers/make-services.ts +++ /dev/null @@ -1,100 +0,0 @@ -const postsStore = [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - // The current populate hook cannot handle this structure. - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - }, - { id: 2, body: 'Marshall post', userId: 102, starIds: [101, 103, 104] }, - { id: 3, body: 'Barbara post', userId: 103 }, - { id: 4, body: 'Aubree post', userId: 104 }, -]; - -const commentsStore = [ - { id: 11, text: 'John post Marshall comment 11', postId: 1, userId: 102 }, - { id: 12, text: 'John post Marshall comment 12', postId: 1, userId: 102 }, - { id: 13, text: 'John post Marshall comment 13', postId: 1, userId: 102 }, - { id: 14, text: 'Marshall post John comment 14', postId: 2, userId: 101 }, - { id: 15, text: 'Marshall post John comment 15', postId: 2, userId: 101 }, - { id: 16, text: 'Barbara post John comment 16', postId: 3, userId: 101 }, - { id: 17, text: 'Aubree post Marshall comment 17', postId: 4, userId: 102 }, -]; - -const usersStore = [ - { id: 101, name: 'John' }, - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, -]; - -export const posts: any = makeService(postsStore, 'posts'); -export const comments: any = makeService(commentsStore, 'comments'); -export const users: any = makeService(usersStore, 'users'); - -function makeService(store1: any, _name: any) { - return { - get(id: any) { - // console.log(`... ${name} get ${id}`); - const store = clone(store1); - - for (let i = 0, leni = store.length; i < leni; i++) { - if (store[i].id === id) return asyncReturn(store[i]); - } - - throw Error(`post id ${id} not found`); - }, - - find(params: any) { - // console.log(`... ${name} find`, params ? params.query : ''); - const store = clone(store1); - - if (!params || !params.query) return asyncReturn(store); - - const field = Object.keys(params.query)[0]; - const value = params.query[field]; - const $select = params.query.$select; - - return asyncReturn( - store - .filter((post: any) => { - return typeof value !== 'object' - ? post[field] === value - : value.$in.indexOf(post[field]) !== -1; - }) - .map((post: any) => pluck(post, $select)), - ); - }, - }; -} - -function asyncReturn(value: any) { - return new Promise(resolve => { - setTimeout(() => { - resolve(value); - }, 10); - }); -} - -function pluck(obj: any, fields: any) { - if (!fields) return obj; - - const res: any = {}; - - fields.forEach((name: any) => { - if (name in obj) { - res[name] = obj[name]; - } - }); - - return res; -} - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/act-on-dispatch.test.ts b/test/hooks/act-on-dispatch.test.ts deleted file mode 100755 index 60373faa..00000000 --- a/test/hooks/act-on-dispatch.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { assert } from 'vitest'; -import { actOnDefault, actOnDispatch, combine, getItems, replaceItems } from '../../src'; - -let hookBefore: any; - -function testHook(what: any, code: any) { - return (context: HookContext) => { - if (context.params._actOn !== what) { - throw new Error(`Hook code ${code} expected ${what} found ${context.params._actOn}`); - } - - context.params._actOnCodes.push(code); - }; -} - -describe('services actOn', () => { - describe('Call hooks which do not call other hooks', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'get', - params: { _actOnCodes: [] }, - }; - }); - - it('actOnDefault', async () => { - const result: any = await actOnDefault( - testHook(undefined, 1), - testHook(undefined, 2), - testHook(undefined, 3), - )(hookBefore); - - assert.deepEqual(result.params._actOnCodes, [1, 2, 3]); - }); - - it('actOnDispatch', async () => { - const result: any = await actOnDispatch( - testHook('dispatch', 10), - testHook('dispatch', 20), - testHook('dispatch', 30), - )(hookBefore); - - assert.deepEqual(result.params._actOnCodes, [10, 20, 30]); - }); - }); - - describe('Call hooks calling others same actOn', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'get', - params: { _actOnCodes: [] }, - }; - }); - - it('actOnDefault calling actOnDefault', async () => { - const result: any = await actOnDefault( - combine(testHook(undefined, 11), testHook(undefined, 12)), - combine(testHook(undefined, 21), testHook(undefined, 22)), - )(hookBefore); - - assert.deepEqual(result.params._actOnCodes, [11, 12, 21, 22]); - }); - - it('actOnDefault calling actOnDispatch', async () => { - const result: any = await actOnDefault( - actOnDispatch(combine(testHook('dispatch', 11), testHook('dispatch', 12))), - combine(testHook(undefined, 21), testHook(undefined, 22)), - )(hookBefore); - - assert.deepEqual(result.params._actOnCodes, [11, 12, 21, 22]); - }); - - it('actOnDispatch calling actOnDefault', async () => { - const result: any = await actOnDispatch( - actOnDefault(combine(testHook(undefined, 11), testHook(undefined, 12))), - combine(testHook('dispatch', 21), testHook('dispatch', 22)), - )(hookBefore); - - assert.deepEqual(result.params._actOnCodes, [11, 12, 21, 22]); - }); - }); - - describe('getItems & replaceItems', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'get', - data: { a: 1 }, - result: { b: 2 }, - dispatch: { c: 3 }, - params: { _actOn: 'dispatch' }, - }; - }); - - it('Gets dispatch data', () => { - assert.deepEqual(getItems(hookBefore), hookBefore.dispatch); - }); - - it('Returns dispatch data', () => { - replaceItems(hookBefore, { foo: 'bar' }); - - assert.deepEqual(hookBefore.dispatch, { foo: 'bar' }); - }); - }); -}); diff --git a/test/hooks/alter-items.test.ts b/test/hooks/alter-items.test.ts deleted file mode 100755 index 95f9d30c..00000000 --- a/test/hooks/alter-items.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { assert } from 'vitest'; -import { alterItems } from '../../src'; - -let hookBefore: any; -let hookAfter: any; -let hookFindPaginate: any; -let hookCreateMulti: any; -let hookFind: any; - -describe('services alterItems', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { first: 'Jane', last: 'Doe' }, - }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - hookCreateMulti = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - }); - - it('default func is a no-op', () => { - // @ts-ignore - alterItems()(hookBefore); - assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe' }); - }); - - it('context is 2nd param', () => { - let contextParam; - alterItems((_rec: any, context: any) => { - contextParam = context; - })(hookBefore); - assert.deepEqual(contextParam, hookBefore); - }); - - it('throws if 1st param is not a func', () => { - try { - // @ts-ignore - alterItems('no-func'); - } catch (error) { - // @ts-ignore - assert.equal(error.message, 'Function required. (alter)'); - return; - } - throw new Error('alterItems does not throw an error if 1st param is not a function'); - }); - - it('updates hook before::create', () => { - alterItems((rec: any) => { - rec.state = 'UT'; - })(hookBefore); - assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }); - }); - - it('updates hook before::create::multi', () => { - alterItems((rec: any) => { - rec.state = 'UT'; - })(hookCreateMulti); - assert.deepEqual(hookCreateMulti.data, [ - { first: 'John', last: 'Doe', state: 'UT' }, - { first: 'Jane', last: 'Doe', state: 'UT' }, - ]); - }); - - it('updates hook after::find with pagination', () => { - alterItems((rec: any) => { - delete rec.last; - })(hookFindPaginate); - assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]); - }); - - it('updates hook after::find with no pagination', () => { - alterItems((rec: any) => { - rec.new = rec.first; - })(hookFind); - assert.deepEqual(hookFind.result, [ - { first: 'John', last: 'Doe', new: 'John' }, - { first: 'Jane', last: 'Doe', new: 'Jane' }, - ]); - }); - - it('updates hook after', () => { - alterItems((rec: any) => { - rec.new = rec.first; - })(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }); - }); - - it('updates hook before::create with new item returned', () => { - alterItems((rec: any) => Object.assign({}, rec, { state: 'UT' }))(hookBefore); - assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }); - }); - - it('updates hook after::find with pagination with new item returned', () => { - alterItems((rec: any) => Object.assign({}, { first: rec.first }))(hookFindPaginate); - assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]); - }); - - it('updates hook after::find with pagination with new item returned', () => { - alterItems((rec: any) => Object.assign({}, rec, { new: rec.first }))(hookFind); - assert.deepEqual(hookFind.result, [ - { first: 'John', last: 'Doe', new: 'John' }, - { first: 'Jane', last: 'Doe', new: 'Jane' }, - ]); - }); - - it('updates hook after with new item returned', () => { - alterItems((rec: any) => Object.assign({}, rec, { new: rec.first }))(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }); - }); - - it('returns a promise that contains context', async () => { - const promise = alterItems((rec: any) => { - rec.state = 'UT'; - return Promise.resolve(); - })(hookBefore); - - assert.ok(promise instanceof Promise); - - const result = await promise; - - assert.deepEqual(result, hookBefore); - }); - - it('updates hook before::create with new item returned', () => { - // @ts-ignore - return alterItems((rec: any) => Promise.resolve(Object.assign({}, rec, { state: 'UT' })))( - hookBefore, - ).then(() => { - assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }); - }); - }); - - it('updates hook before::create async', () => { - const alterFunc = (rec: any) => { - rec.state = 'UT'; - return Promise.resolve(); - }; - // @ts-ignore - return alterItems(alterFunc)(hookBefore).then(() => { - assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }); - }); - }); - - it('updates hook before::create async with new item returned', () => { - const alterFunc = (rec: any) => Promise.resolve(Object.assign({}, rec, { state: 'UT' })); - // @ts-ignore - return alterItems(alterFunc)(hookBefore).then(() => { - assert.deepEqual(hookBefore.data, { first: 'John', last: 'Doe', state: 'UT' }); - }); - }); - - it('updates hook after::create', () => { - return alterItems((rec: any) => { - rec.new = rec.first; - return Promise.resolve(); - // @ts-ignore - })(hookAfter).then(() => { - assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }); - }); - }); - - it('updates hook after::create with new item returned', () => { - // @ts-ignore - return alterItems((rec: any) => Promise.resolve(Object.assign({}, rec, { new: rec.first })))( - hookAfter, - ).then(() => { - assert.deepEqual(hookAfter.result, { first: 'Jane', last: 'Doe', new: 'Jane' }); - }); - }); - - it('updates hook after::find with pagination', () => { - return alterItems((rec: any) => { - delete rec.last; - return Promise.resolve(); - // @ts-ignore - })(hookFindPaginate).then(() => { - assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]); - }); - }); - - it('updates hook after::find with no pagination', () => { - return alterItems((rec: any) => { - rec.new = rec.first; - return Promise.resolve(); - // @ts-ignore - })(hookFind).then(() => { - assert.deepEqual(hookFind.result, [ - { first: 'John', last: 'Doe', new: 'John' }, - { first: 'Jane', last: 'Doe', new: 'Jane' }, - ]); - }); - }); - - it('updates hook after::find with pagination with new item returned', () => { - // @ts-ignore - return alterItems((rec: any) => Promise.resolve(Object.assign({}, { first: rec.first })))( - hookFindPaginate, - ).then(() => { - assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]); - }); - }); - - it('updates hook after::find with no pagination with new item returned', () => { - // @ts-ignore - return alterItems((rec: any) => Promise.resolve(Object.assign({}, rec, { new: rec.first })))( - hookFind, - ).then(() => { - assert.deepEqual(hookFind.result, [ - { first: 'John', last: 'Doe', new: 'John' }, - { first: 'Jane', last: 'Doe', new: 'Jane' }, - ]); - }); - }); -}); diff --git a/test/hooks/cache.test.ts b/test/hooks/cache.test.ts deleted file mode 100755 index 141cc5a4..00000000 --- a/test/hooks/cache.test.ts +++ /dev/null @@ -1,376 +0,0 @@ -import { assert } from 'vitest'; -import { cache } from '../../src'; - -// @ts-ignore -import CacheMap from '@feathers-plus/cache'; - -let cacheMap: any; -let hookBeforeSingle: any; -let hookBeforeMulti: any; -let hookAfterSingle: any; -let hookAfterSingleNormalize: any; -let hookAfterMulti: any; -let hookAfterPaginated: any; -let hookBeforeUuid: any; -let hookAfterUuid: any; -let hookBeforeMultiMixed: any; -let hookAfterMultiMixed: any; -let map: any; -let cloneCount: any; - -const makeCacheKey = (key: any) => -key; - -describe('service cache', () => { - beforeEach(() => { - cacheMap = CacheMap({ max: 3 }); - map = new Map(); - cloneCount = 0; - - hookBeforeSingle = { - type: 'before', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - data: { id: 1, first: 'John', last: 'Doe' }, - }; - hookBeforeMulti = { - type: 'before', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - data: [ - { id: 1, first: 'John', last: 'Doe' }, - { id: 2, first: 'Jane', last: 'Doe' }, - ], - }; - hookAfterSingle = { - type: 'after', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - result: { id: 1, first: 'Jane', last: 'Doe' }, - }; - hookAfterSingleNormalize = { - type: 'after', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - result: { id: -1, first: 'Jane', last: 'Doe' }, - }; - hookAfterMulti = { - type: 'after', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - result: [ - { id: 1, first: 'John', last: 'Doe' }, - { id: 2, first: 'Jane', last: 'Doe' }, - ], - }; - hookAfterPaginated = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { id: 1, first: 'John', last: 'Doe' }, - { id: 2, first: 'Jane', last: 'Doe' }, - ], - }, - }; - hookBeforeUuid = { - type: 'before', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - data: { uuid: 1, first: 'John', last: 'Doe' }, - service: { id: 'uuid' }, - }; - hookAfterUuid = { - type: 'after', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - result: { uuid: 1, first: 'Jane', last: 'Doe' }, - service: { id: 'uuid' }, - }; - hookBeforeMultiMixed = { - type: 'before', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - data: [ - { _id: 1, first: 'John', last: 'Doe' }, - { id: 2, first: 'Jane', last: 'Doe' }, - ], - }; - hookAfterMultiMixed = { - type: 'after', - id: undefined, - method: undefined, - params: { provider: 'rest' }, - result: [ - { id: 1, first: 'John', last: 'Doe' }, - { _id: 2, first: 'Jane', last: 'Doe' }, - ], - }; - }); - - describe('Can build a cache', () => { - it('Can build a cache', () => { - cacheMap.set('a', 'aa'); - assert.equal(cacheMap.get('a'), 'aa', 'bad get after set'); - - cacheMap.delete('a'); - assert.equal(cacheMap.get('a'), undefined, 'bad get after delete'); - - cacheMap.set('a', 'aa'); - cacheMap.clear(); - assert.equal(cacheMap.get('a'), undefined, 'bad get after clear'); - }); - }); - - describe('Clears cache', () => { - it('Before one-record update', () => { - hookBeforeSingle.method = 'update'; - - cacheMap.set(1, 123); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeSingle); - assert.deepEqual(cacheMap.get(1), undefined); - }); - - it('Before multi-record update', () => { - hookBeforeMulti.method = 'update'; - - cacheMap.set(1, 123); - cacheMap.set(2, 124); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeMulti); - - assert.deepEqual(cacheMap.get(1), undefined); - assert.deepEqual(cacheMap.get(2), undefined); - }); - - it('Before one-record patch', () => { - hookBeforeSingle.method = 'patch'; - - cacheMap.set(1, 123); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeSingle); - - assert.deepEqual(cacheMap.get(1), undefined); - }); - - it('Before multi-record patch', () => { - hookBeforeMulti.method = 'patch'; - - cacheMap.set(1, 123); - cacheMap.set(2, 789); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeMulti); - assert.deepEqual(cacheMap.get(1), undefined, 'id 1'); - assert.deepEqual(cacheMap.get(2), undefined, 'id 2'); - }); - - it('NOT before one-record create', () => { - hookBeforeSingle.method = 'create'; - - cacheMap.set(1, 123); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeSingle); - assert.deepEqual(cacheMap.get(1), 123); - }); - - it('NOT before multi-record remove', () => { - hookBeforeMulti.method = 'remove'; - - cacheMap.set(1, 123); - cacheMap.set(2, 321); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeMulti); - assert.deepEqual(cacheMap.get(1), 123); - assert.deepEqual(cacheMap.get(2), 321); - }); - - it('After multi-record remove', () => { - hookAfterMulti.method = 'remove'; - - cacheMap.set(1, 123); - cacheMap.set(2, 321); - - // @ts-ignore - cache(cacheMap, 'id')(hookAfterMulti); - - assert.deepEqual(cacheMap.get(1), undefined, 'id 1'); - assert.deepEqual(cacheMap.get(2), undefined, 'id 2'); - }); - }); - - describe('Loads cache', () => { - it('After one-record create', () => { - hookAfterSingle.method = 'create'; - - // @ts-ignore - cache(cacheMap, 'id')(hookAfterSingle); - assert.deepEqual(cacheMap.get(1), { id: 1, first: 'Jane', last: 'Doe' }); - }); - - it('After multi-record patch', () => { - hookAfterMulti.method = 'patch'; - - // @ts-ignore - cache(cacheMap, 'id')(hookAfterMulti); - - assert.deepEqual(cacheMap.get(1), { id: 1, first: 'John', last: 'Doe' }, 'id 1'); - assert.deepEqual(cacheMap.get(2), { id: 2, first: 'Jane', last: 'Doe' }, 'id 2'); - }); - - it('After paginated find', () => { - // @ts-ignore - cache(cacheMap, 'id')(hookAfterPaginated); - - assert.deepEqual(cacheMap.get(1), { id: 1, first: 'John', last: 'Doe' }, 'id 1'); - assert.deepEqual(cacheMap.get(2), { id: 2, first: 'Jane', last: 'Doe' }, 'id 2'); - }); - - it('NOT after remove', () => { - hookAfterMulti.method = 'remove'; - - // @ts-ignore - cache(cacheMap, 'id')(hookAfterMulti); - - assert.deepEqual(cacheMap.get(1), undefined, 'id 1'); - assert.deepEqual(cacheMap.get(2), undefined, 'id 2'); - }); - - it('Normalizes record', () => { - hookAfterSingleNormalize.method = 'create'; - - // @ts-ignore - cache(cacheMap, 'id', { makeCacheKey })(hookAfterSingleNormalize); - assert.deepEqual(cacheMap.get(1), { id: -1, first: 'Jane', last: 'Doe' }); - }); - }); - - describe('Gets from cache', () => { - it('Before one-record get', () => { - hookBeforeSingle.method = 'get'; - hookBeforeSingle.id = 1; - - cacheMap.set(1, { foo: 'bar' }); - - // @ts-ignore - cache(cacheMap, 'id')(hookBeforeSingle); - - assert.deepEqual(cacheMap.get(1), { foo: 'bar' }, 'cache'); - assert.deepEqual(hookBeforeSingle.result, { foo: 'bar' }); - }); - - it('Normalizes record', () => { - hookBeforeSingle.method = 'get'; - hookBeforeSingle.id = -1; - - cacheMap.set(1, { id: -1, foo: 'bar' }); - - // @ts-ignore - cache(cacheMap, 'id', { makeCacheKey })(hookBeforeSingle); - - assert.deepEqual(cacheMap.get(1), { id: -1, foo: 'bar' }, 'cache'); - assert.deepEqual(hookBeforeSingle.result, { id: -1, foo: 'bar' }); - }); - }); - - describe('Uses context.service.id', () => { - it('Clears cache before one-record update', () => { - hookBeforeUuid.method = 'update'; - - cacheMap.set(1, 123); - - cache(cacheMap)(hookBeforeUuid); - assert.deepEqual(cacheMap.get(1), undefined); - }); - - it('Loads cache after one-record create', () => { - hookAfterUuid.method = 'create'; - - cache(cacheMap)(hookAfterUuid); - assert.deepEqual(cacheMap.get(1), { uuid: 1, first: 'Jane', last: 'Doe' }); - }); - - it('Before one-record get', () => { - hookBeforeUuid.method = 'get'; - hookBeforeUuid.id = 1; - - cacheMap.set(1, { foo: 'bar' }); - - cache(cacheMap)(hookBeforeUuid); - - assert.deepEqual(cacheMap.get(1), { foo: 'bar' }, 'cache'); - assert.deepEqual(hookBeforeUuid.result, { foo: 'bar' }); - }); - }); - - describe('Uses item._id || item.id', () => { - it('Clears cache before multi-record patch', () => { - hookBeforeMultiMixed.method = 'patch'; - - cacheMap.set(1, 123); - cacheMap.set(2, 789); - - cache(cacheMap)(hookBeforeMultiMixed); - assert.deepEqual(cacheMap.get(1), undefined, 'id 1'); - assert.deepEqual(cacheMap.get(2), undefined, 'id 2'); - }); - - it('Loads cache after multi-record patch', () => { - hookAfterMultiMixed.method = 'patch'; - - cache(cacheMap)(hookAfterMultiMixed); - - assert.deepEqual(cacheMap.get(1), { id: 1, first: 'John', last: 'Doe' }, 'id 1'); - assert.deepEqual(cacheMap.get(2), { _id: 2, first: 'Jane', last: 'Doe' }, 'id 2'); - }); - }); - - describe('Works with an ES6 Map', () => { - it('Clears cache before one-record update', () => { - hookBeforeUuid.method = 'update'; - - map.set(1, 123); - - cache(map)(hookBeforeUuid); - assert.deepEqual(map.get(1), undefined); - }); - - it('Loads cache after one-record create', () => { - hookAfterUuid.method = 'create'; - - cache(map)(hookAfterUuid); - assert.deepEqual(map.get(1), { uuid: 1, first: 'Jane', last: 'Doe' }); - }); - }); - - describe('Misc', () => { - it('Uses option.clone', () => { - hookAfterUuid.method = 'create'; - - // @ts-ignore - cache(cacheMap, null, { clone })(hookAfterUuid); - assert.deepEqual(cacheMap.get(1), { uuid: 1, first: 'Jane', last: 'Doe' }, 'get'); - assert.equal(cloneCount, 1, 'count'); - }); - }); -}); - -function clone(obj: any) { - cloneCount += 1; - return Object.assign({}, obj); -} diff --git a/test/hooks/de-populate.test.ts b/test/hooks/de-populate.test.ts deleted file mode 100755 index 8f7ffde0..00000000 --- a/test/hooks/de-populate.test.ts +++ /dev/null @@ -1,288 +0,0 @@ -import { assert } from 'vitest'; -import { dePopulate } from '../../src'; - -describe('services dePopulate - not dot notation', () => { - let hookAfter: any; - let hookBeforeArray: any; - let hookBefore: any; - - beforeEach(() => { - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post', 'x'], - _elapsed: { post: 16051500, total: 20707798, x: 1 }, - _computed: ['a1', 'a1'], - a1: 1, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - }; - hookBefore = { - type: 'before', - method: 'update', - params: { provider: 'rest' }, - data: { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }, - }; - hookBeforeArray = { - type: 'before', - method: 'patch', - params: { provider: 'rest' }, - data: [ - { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 3456238, total: 3642135 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - { - userId: 'as61389dadhga62343hads6712', - postId: 2, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 3457496, total: 3878535 }, - post: { - id: 2, - title: 'Post 2', - content: 'Lorem ipsum dolor sit amet 5', - author: '167asdf3689348sdad7312131s', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - { - userId: '167asdf3689348sdad7312131s', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 3446912, total: 3857237 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - ], - }; - }); - - it('one item, after hook, missing props', () => { - const hook = clone(hookAfter); - const deHook: any = dePopulate()(hook); - assert.deepEqual(deHook.result, { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }); - }); - - it('one item, before hook, not populated', () => { - const hook = clone(hookBefore); - const deHook: any = dePopulate()(hook); - assert.deepEqual(deHook.data, { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }); - }); - - it('item array, before hook', () => { - const hook = clone(hookBeforeArray); - const deHook: any = dePopulate()(hook); - assert.deepEqual(deHook.data, [ - { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }, - { - userId: 'as61389dadhga62343hads6712', - postId: 2, - updatedAt: 1480793101475, - }, - { - userId: '167asdf3689348sdad7312131s', - postId: 1, - updatedAt: 1480793101475, - }, - ]); - }); -}); - -describe('services dePopulate - dot notation', () => { - let hookAfter: any; - let hookBeforeArray: any; - let hookBefore: any; - - beforeEach(() => { - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post.a.b', 'x'], - _elapsed: { post: 16051500, total: 20707798, x: 1 }, - _computed: ['a1', 'a1'], - a1: 1, - post: { - a: { - b: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - }, - }, - }; - hookBefore = { - type: 'before', - method: 'update', - params: { provider: 'rest' }, - data: { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }, - }; - hookBeforeArray = { - type: 'before', - method: 'patch', - params: { provider: 'rest' }, - data: [ - { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post.a'], - _elapsed: { post: 3456238, total: 3642135 }, - post: { - a: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - }, - { - userId: 'as61389dadhga62343hads6712', - postId: 2, - updatedAt: 1480793101475, - _include: ['post.a', 'x', 'post.b.c', 'comments'], - _elapsed: { post: 3457496, total: 3878535 }, - comments: {}, - post: { - a: { - id: 2, - title: 'Post 2', - content: 'Lorem ipsum dolor sit amet 5', - author: '167asdf3689348sdad7312131s', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - }, - { - userId: '167asdf3689348sdad7312131s', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 3446912, total: 3857237 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - }, - }, - ], - }; - }); - - it('one item, after hook, missing props', () => { - const hook = clone(hookAfter); - const deHook: any = dePopulate()(hook); - assert.deepEqual(deHook.result, { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - post: { a: {} }, - }); - }); - - it('one item, before hook, not populated', () => { - const hook = clone(hookBefore); - const deHook: any = dePopulate()(hook); - assert.deepEqual(deHook.data, { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - }); - }); - - it('item array, before hook', () => { - const hook = clone(hookBeforeArray); - const deHook: any = dePopulate()(hook); - assert.deepEqual(deHook.data, [ - { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - post: {}, - }, - { - userId: 'as61389dadhga62343hads6712', - postId: 2, - updatedAt: 1480793101475, - post: {}, - }, - { - userId: '167asdf3689348sdad7312131s', - postId: 1, - updatedAt: 1480793101475, - }, - ]); - }); -}); - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/disallow.test.ts b/test/hooks/disallow.test.ts deleted file mode 100755 index 861221c6..00000000 --- a/test/hooks/disallow.test.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { assert } from 'vitest'; - -import { disallow } from '../../src'; - -describe('services disallow', () => { - describe('disallow is compatible with .disable (without predicate)', () => { - let hookRest: any; - let hookSocketio: any; - let hookServer: any; - - beforeEach(() => { - hookRest = { method: 'create', params: { provider: 'rest' } }; - hookSocketio = { method: 'create', params: { provider: 'socketio' } }; - hookServer = { method: 'create', params: { provider: '' } }; - }); - - it('disables all providers with no param', () => { - assert.throws(() => { - disallow()(hookSocketio); - }); - assert.throws(() => { - disallow()(hookServer); - }); - }); - - it('disables a provider', () => { - assert.throws(() => { - disallow('socketio')(hookSocketio); - }); - }); - - it('does not disable the server', () => { - disallow('socketio')(hookServer); - assert.throws(() => { - disallow('socketio')(hookSocketio); - }); - }); - - it('does not disable another provider', () => { - disallow('socketio')(hookRest); - assert.throws(() => { - disallow('socketio')(hookSocketio); - }); - }); - - it('disables multiple providers', () => { - disallow('socketio', 'rest')(hookServer); - assert.throws(() => { - disallow('socketio', 'rest')(hookSocketio); - }); - assert.throws(() => { - disallow('socketio', 'rest')(hookRest); - }); - }); - - it('"external" disables all external providers', () => { - disallow('socketio', 'rest')(hookServer); - assert.throws(() => { - disallow('socketio', 'rest')(hookSocketio); - }); - assert.throws(() => { - disallow('socketio', 'rest')(hookRest); - }); - }); - }); - - describe('disallow functionality is like isProvider', () => { - let hookServer: any; - let hookSocketio: any; - let hook: any; - - beforeEach(() => { - hookServer = { type: 'before', method: 'create', params: { provider: '' } }; - hookSocketio = { type: 'before', method: 'create', params: { provider: 'socketio' } }; - }); - - it('returns a function', () => { - const fcn = disallow('server'); - - assert.isFunction(fcn); - }); - - it('throws on no args', () => { - assert.throws(() => disallow()(hook)); - }); - - it('finds provider with 1 arg', () => { - const hook = clone(hookSocketio); - - const result = disallow('rest')(hook); - assert.equal(result, undefined); - - assert.throws(() => { - disallow('socketio')(hook); - }); - }); - - it('finds provider with 2 args', () => { - const hook = clone(hookSocketio); - - const result = disallow('rest', 'server')(hook); - assert.equal(result, undefined); - - assert.throws(() => { - disallow('rest', 'socketio')(hook); - }); - }); - - it('finds server', () => { - const hook = clone(hookServer); - - const result = disallow('rest', 'socketio', 'external')(hook); - assert.equal(result, undefined); - - assert.throws(() => { - disallow('rest', 'socketio', 'server')(hook); - }); - }); - - it('finds external', () => { - const hook = clone(hookSocketio); - - const result = disallow('rest', 'server')(hook); - assert.equal(result, undefined); - - assert.throws(() => { - disallow('rest', 'server', 'external')(hook); - }); - }); - - it('succeeds if not provider', () => { - const hook = clone(hookServer); - - const result = disallow('socketio')(hook); - assert.equal(result, undefined); - }); - - it('succeeds if not external', () => { - const hook = clone(hookServer); - - const result = disallow('external')(hook); - assert.equal(result, undefined); - }); - - it('succeeds if not server', () => { - const hook = clone(hookSocketio); - - const result = disallow('server')(hook); - assert.equal(result, undefined); - }); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/discard-2.test.ts b/test/hooks/discard-2.test.ts deleted file mode 100755 index 45eb0480..00000000 --- a/test/hooks/discard-2.test.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { assert } from 'vitest'; -import { discard } from '../../src'; - -describe('common hook discard', () => { - describe('removes fields', () => { - const beforeJohn = (): any => ({ type: 'before', data: { first: 'John', last: 'Doe' } }); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - // const beforeUndef = (): any => ({ type: 'before', data: { first: undefined, last: 'Doe' } }); - const beforeNull = (): any => ({ type: 'before', data: { first: null, last: 'Doe' } }); - const afterJane = (): any => ({ type: 'after', result: { first: 'Jane', last: 'Doe' } }); - const afterBoth = (): any => ({ - type: 'after', - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }); - const afterPage = (): any => ({ - type: 'after', - result: { - total: 2, - skip: 0, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }); - - const decisionTable = [ - // desc, context, method, provider, args, result - ['before::create', beforeJohn(), 'create', undefined, ['first'], { last: 'Doe' }], - ['before::create', beforeJohn(), 'create', 'rest', ['first'], { last: 'Doe' }], - ['before::create', beforeJohn(), 'create', 'socketio', ['first'], { last: 'Doe' }], - [ - 'after::find with paginate', - afterPage(), - 'find', - undefined, - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - [ - 'after::find with paginate', - afterPage(), - 'find', - 'rest', - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - [ - 'after::find with paginate', - afterPage(), - 'find', - 'socketio', - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - [ - 'after::find no paginate', - afterBoth(), - 'find', - undefined, - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - [ - 'after::find no paginate', - afterBoth(), - 'find', - 'rest', - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - [ - 'after::find no paginate', - afterBoth(), - 'find', - 'socketio', - ['last'], - [{ first: 'John' }, { first: 'Jane' }], - ], - ['after', afterJane(), 'create', undefined, ['last'], { first: 'Jane' }], - ['after', afterJane(), 'create', 'rest', ['last'], { first: 'Jane' }], - ['after', afterJane(), 'create', 'socketio', ['last'], { first: 'Jane' }], - ['call internally on server', afterJane(), 'create', undefined, ['last'], { first: 'Jane' }], - [ - 'not throw field missing', - beforeJohn(), - 'create', - undefined, - ['first', 'xx'], - { last: 'Doe' }, - ], - ['not throw field missing', beforeJohn(), 'create', 'rest', ['first', 'xx'], { last: 'Doe' }], - [ - 'not throw field missing', - beforeJohn(), - 'create', - 'socketio', - ['first', 'xx'], - { last: 'Doe' }, - ], - ['not throw field null', beforeNull(), 'create', undefined, ['first'], { last: 'Doe' }], - ['not throw field null', beforeNull(), 'create', 'rest', ['first'], { last: 'Doe' }], - ['not throw field null', beforeNull(), 'create', 'socketio', ['first'], { last: 'Doe' }], - ]; - - decisionTable.forEach(([desc, context, method, provider, args, result]) => { - it(desc, () => { - context.method = method; - if (provider !== null) { - context.params = context.params || {}; - context.params.provider = provider; - } - - discard(...args)(context); - assert.deepEqual( - context.data ? context.data : context.result.data || context.result, - result, - ); - }); - }); - }); - - describe('handles dot notation', () => { - const ctx = (): any => ({ - type: 'before', - method: 'create', - data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }); - const ctx2 = (): any => ({ - type: 'after', - method: 'get', - result: { property: null, foo: 'bar' }, - }); - - const decisionTable = [ - // desc, context, args, result - [ - 'handles dots', - ctx(), - ['dept'], - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }, - ], - [ - 'handle 1 dot', - ctx(), - ['empl.status'], - { empl: { name: { first: 'John', last: 'Doe' } }, dept: 'Acct' }, - ], - [ - 'handle 2 dot', - ctx(), - ['empl.name.first'], - { empl: { name: { last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - ], - [ - 'missing path', - ctx(), - ['empl.xx.first'], - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - ], - [ - 'missing no dot', - ctx(), - ['xx'], - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - ], - [ - '2 fields', - ctx(), - ['empl.status', 'dept'], - { empl: { name: { first: 'John', last: 'Doe' } } }, - ], - ['path not obj', ctx2(), ['property.secret'], { property: null, foo: 'bar' }], - ]; - - decisionTable.forEach(([desc, context, args, result]) => { - it(desc, () => { - discard(...args)(context); - assert.deepEqual( - context.data ? context.data : context.result.data || context.result, - result, - ); - }); - }); - }); -}); diff --git a/test/hooks/discard.test.ts b/test/hooks/discard.test.ts deleted file mode 100755 index 668572e0..00000000 --- a/test/hooks/discard.test.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { assert } from 'vitest'; -import * as hooks from '../../src'; - -let hookBefore: any; -let hookAfter: any; -let hookFindPaginate: any; -let hookFind: any; - -describe('services discard', () => { - describe('removes fields', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { first: 'Jane', last: 'Doe' }, - }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - }); - - it('updates hook before::create', () => { - hooks.discard('first')(hookBefore); - assert.deepEqual(hookBefore.data, { last: 'Doe' }); - }); - - it('updates hook after::find with pagination', () => { - hooks.discard('last')(hookFindPaginate); - assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]); - }); - - it('updates hook after::find with no pagination', () => { - hooks.discard('last')(hookFind); - assert.deepEqual(hookFind.result, [{ first: 'John' }, { first: 'Jane' }]); - }); - - it('updates hook after', () => { - hooks.discard('last')(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'Jane' }); - }); - - it('updates when called internally on server', () => { - hookAfter.params.provider = ''; - hooks.discard('last')(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'Jane' }); - }); - - it('does not throw if field is missing', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - hooks.discard('first', 'xx')(hook); - assert.deepEqual(hook.data, { last: 'Doe' }); - }); - - it('does not throw if field is null', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: null, last: 'Doe' }, - }; - hooks.discard('first')(hook); - assert.deepEqual(hook.data, { last: 'Doe' }); - }); - }); - - describe('handles dot notation', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }; - }); - - it('prop with no dots', () => { - hooks.discard('dept')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - }); - }); - - it('prop with 1 dot', () => { - hooks.discard('empl.status')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' } }, - dept: 'Acct', - }); - }); - - it('prop with 2 dots', () => { - hooks.discard('empl.name.first')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('ignores bad or missing paths', () => { - hooks.discard('empl.xx.first')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('ignores bad or missing no dot path', () => { - hooks.discard('xx')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('discards multiple fields', () => { - const hook: any = { - type: 'after', - method: 'get', - result: { - roles: ['super'], - _id: 'a', - email: 'foo', - password: 'bar', - name: 'Rafael', - id: 'b', - }, - query: {}, - }; - - hooks.discard('email', 'password')(hook); - - assert.deepEqual(hook.result, { - roles: ['super'], - _id: 'a', - // email: 'foo', - // password: 'bar', - name: 'Rafael', - id: 'b', - } as any); - }); - - it('null prop', () => { - const hook: any = { - type: 'after', - method: 'get', - result: { - property: null, - other: 'bar', - }, - query: {}, - }; - - hooks.discard('property.secret')(hook); - - assert.deepEqual(hook.result, { - property: null, - other: 'bar', - }); - }); - }); -}); diff --git a/test/hooks/fast-join-cache.test.ts b/test/hooks/fast-join-cache.test.ts deleted file mode 100755 index 242ed7e6..00000000 --- a/test/hooks/fast-join-cache.test.ts +++ /dev/null @@ -1,378 +0,0 @@ -import { assert } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import BatchLoader from '@feathers-plus/batch-loader'; -// @ts-ignore -import CacheMap from '@feathers-plus/cache'; -import { MemoryService } from '@feathersjs/memory'; -import { cache, fastJoin, iff, makeCallingParams } from '../../src'; - -const { getResultsByKey, getUniqueKeys } = BatchLoader; - -const postsStoreStartId = 5; -const postsStoreInit = [ - { id: 1, body: 'John post', userId: 101, starIds: [102, 103, 104] }, - { id: 2, body: 'Marshall post', userId: 102, starIds: [101, 103, 104] }, - { id: 3, body: 'Barbara post', userId: 103 }, - { id: 4, body: 'Aubree post', userId: 104 }, -]; - -const usersStoreStartId = 105; -const usersStoreInit = [ - { id: 101, name: 'John' }, - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, -]; - -let app: any; -let users: any; -let posts: any; -let enableCache: any; -let joinAuthorCount: any; -let joinStarersCount: any; -let userBatchLoaderCount: any; - -const cacheMapUsers = CacheMap({ max: 100 }); -const userBatchLoader = new BatchLoader( - async (keys: any, context: any) => { - userBatchLoaderCount += 1; - const result: any = await users.find( - makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }), - ); - return getResultsByKey(keys, result, (user: any) => user.id, '!'); - }, - { context: {}, cacheMap: cacheMapUsers }, -); - -function services(this: any) { - const app = this; - app.configure(usersService); - app.configure(postsService); -} - -function postsService(this: any) { - const app = this; - const store = clone(postsStoreInit); - - class PostsService extends MemoryService { - foo: boolean; - - constructor(...args: any[]) { - super(...args); - this.foo = true; - } - - get(...args: any[]) { - // @ts-ignore - return super.get(...args); - } - } - - app.use('/posts', new PostsService({ store, postsStoreStartId })); - - app.service('posts').hooks({ - before: { - all: [], - }, - }); -} - -function usersService(this: any) { - const app = this; - const store = clone(usersStoreInit); - - class UsersService extends MemoryService { - junk: boolean; - constructor(...args: any[]) { - super(...args); - this.junk = true; - } - - get(...args: any[]) { - // @ts-ignore - return super.get(...args); - } - } - - app.use('/users', new UsersService({ store, usersStoreStartId })); - - app.service('users').hooks({ - before: { - all: iff(enableCache, cache(cacheMapUsers)), - }, - after: { - all: iff(enableCache, cache(cacheMapUsers)), - }, - }); -} - -describe('services fastJoin & cache', () => { - beforeEach(() => { - app = feathers().configure(services); - - posts = app.service('posts'); - users = app.service('users'); - - enableCache = false; - joinAuthorCount = 0; - joinStarersCount = 0; - userBatchLoaderCount = 0; - }); - - describe('check services work', () => { - it('find posts', async () => { - const data = await posts.find(); - assert.deepEqual(data, postsStoreInit); - }); - - it('find users', async () => { - const data = await users.find(); - assert.deepEqual(data, usersStoreInit); - }); - }); - - describe('test fastJoin', () => { - it('no cacheMap, no cache hook', async () => { - const context = await ex8(); - - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('with cacheMap, no cache hook', async () => { - const context = await ex8a(); - - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - }); - - describe('test fastJoin with cacheMap & cache', () => { - beforeEach(() => { - enableCache = true; - cacheMapUsers.reset(); - }); - - it('works for 1 call', async () => { - const context = await ex8b(); - - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - assert.equal(joinAuthorCount, 1, 'joinAuthorCount'); - assert.equal(joinStarersCount, 1, 'joinStarersCount'); - }); - - it('uses persistent cache for 2 calls', async () => { - assert.equal(cacheMapUsers.itemCount, 0, '0 cache'); - - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - // First call - let context = await ex8b(); - - assert.deepEqual(context, result); - assert.equal(cacheMapUsers.itemCount, 4, '1 cache'); - assert.equal(joinAuthorCount, 1, '1 joinAuthorCount'); - assert.equal(joinStarersCount, 1, '1 joinStarersCount'); - assert.equal(userBatchLoaderCount, 1, '1 userBatchLoaderCount'); - - // Second call - joinAuthorCount = 0; - joinStarersCount = 0; - userBatchLoaderCount = 0; - - context = await ex8b(); - - assert.deepEqual(context, result); - assert.equal(cacheMapUsers.itemCount, 4, '2 cache'); - assert.equal(joinAuthorCount, 1, '2 joinAuthorCount'); - assert.equal(joinStarersCount, 1, '2 joinStarersCount'); - assert.equal(userBatchLoaderCount, 0, '2 userBatchLoaderCount'); // key check - }); - }); -}); - -async function ex8() { - const postResolvers = { - before: (context: any) => { - context._loaders = { user: {} }; - - context._loaders.user.id = new BatchLoader( - async (keys: any, context: any) => { - const result = await users.find( - makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }), - ); - return getResultsByKey(keys, result, (user: any) => user.id, '!'); - }, - { context }, - ); - }, - - joins: { - author: () => async (post: any, context: any) => { - post.author = await context._loaders.user.id.load(post.userId); - }, - - starers: () => async (post: any, context: any) => { - if (!post.starIds) return; - post.starers = await context._loaders.user.id.loadMany(post.starIds); - }, - }, - }; - - const context: any = { - method: 'find', - result: clone(await posts.find({ query: { id: 1 } })), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex8a() { - const cacheMap = CacheMap({ max: 100 }); - - const postResolvers = { - before: (context: any) => { - context._loaders = { user: {} }; - - context._loaders.user.id = new BatchLoader( - async (keys: any, context: any) => { - const result = await users.find( - makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }), - ); - return getResultsByKey(keys, result, (user: any) => user.id, '!'); - }, - { context, cacheMap }, - ); - }, - - joins: { - author: () => async (post: any, context: any) => { - post.author = await context._loaders.user.id.load(post.userId); - }, - - starers: () => async (post: any, context: any) => { - if (!post.starIds) return; - post.starers = await context._loaders.user.id.loadMany(post.starIds); - }, - }, - }; - - const context: any = { - method: 'find', - result: clone(await posts.find({ query: { id: 1 } })), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex8b() { - const postResolvers = { - before: (context: any) => { - context._loaders = { user: {} }; - - context._loaders.user.id = userBatchLoader; - }, - - joins: { - author: () => async (post: any, context: any) => { - joinAuthorCount += 1; - post.author = await context._loaders.user.id.load(post.userId); - }, - - starers: () => async (post: any, context: any) => { - joinStarersCount += 1; - if (!post.starIds) return; - post.starers = await context._loaders.user.id.loadMany(post.starIds); - }, - }, - }; - - const context: any = { - method: 'find', - result: clone(await posts.find({ query: { id: 1 } })), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/fast-join.test.ts b/test/hooks/fast-join.test.ts deleted file mode 100755 index 85c50a2d..00000000 --- a/test/hooks/fast-join.test.ts +++ /dev/null @@ -1,753 +0,0 @@ -import { assert } from 'vitest'; -import BatchLoader from '@feathers-plus/batch-loader'; -import { fastJoin, makeCallingParams } from '../../src'; - -import { posts, users, comments } from '../helpers/make-services'; - -const { getResultsByKey, getUniqueKeys, loaderFactory } = BatchLoader; - -describe('service fast-join', () => { - it('Guide - resolvers', async () => { - const context = await ex1(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - author: { id: 101, name: 'John' }, - starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - shaping the result', async () => { - const context = await ex2(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - author: { id: 101, name: 'John' }, - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Customize Resolver Operation', async () => { - const context = await ex3(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Calculated Fields', async () => { - const context = await ex4(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - starerCount: 3, - author: { id: 101, name: 'John' }, - starers: [{ name: 'Marshall' }, { name: 'Barbara' }, { name: 'Aubree' }], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Recursive Operations', async () => { - const context = await ex5(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - comments: [ - { - id: 11, - text: 'John post Marshall comment 11', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - { - id: 12, - text: 'John post Marshall comment 12', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - { - id: 13, - text: 'John post Marshall comment 13', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Keeping Resolvers DRY', async () => { - const context = await ex6(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - comments: [ - { - id: 11, - text: 'John post Marshall comment 11', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - { - id: 12, - text: 'John post Marshall comment 12', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - { - id: 13, - text: 'John post Marshall comment 13', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Using a Simple Batch-Loader', async () => { - const context = await ex7(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Using Batch-Loaders', async () => { - const context = await ex8(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1 }, - { userId: 103, points: 1 }, - { userId: 104, points: 1 }, - ], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); - - it('Guide - Putting It All Together', async () => { - const context = await ex9(); - const result: any = { - method: 'find', - result: [ - { - id: 1, - body: 'John post', - userId: 101, - starIds: [102, 103, 104], - reputation: [ - { userId: 102, points: 1, author: 'Marshall' }, - { userId: 103, points: 1, author: 'Barbara' }, - { userId: 104, points: 1, author: 'Aubree' }, - ], - author: { id: 101, name: 'John' }, - starers: [ - { id: 102, name: 'Marshall' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - comments: [ - { - id: 11, - text: 'John post Marshall comment 11', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - { - id: 12, - text: 'John post Marshall comment 12', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - { - id: 13, - text: 'John post Marshall comment 13', - postId: 1, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - ], - }, - { - id: 2, - body: 'Marshall post', - userId: 102, - starIds: [101, 103, 104], - author: { id: 102, name: 'Marshall' }, - starers: [ - { id: 101, name: 'John' }, - { id: 103, name: 'Barbara' }, - { id: 104, name: 'Aubree' }, - ], - comments: [ - { - id: 14, - text: 'Marshall post John comment 14', - postId: 2, - userId: 101, - author: { id: 101, name: 'John' }, - }, - { - id: 15, - text: 'Marshall post John comment 15', - postId: 2, - userId: 101, - author: { id: 101, name: 'John' }, - }, - ], - }, - { - id: 3, - body: 'Barbara post', - userId: 103, - author: { id: 103, name: 'Barbara' }, - comments: [ - { - id: 16, - text: 'Barbara post John comment 16', - postId: 3, - userId: 101, - author: { id: 101, name: 'John' }, - }, - ], - }, - { - id: 4, - body: 'Aubree post', - userId: 104, - author: { id: 104, name: 'Aubree' }, - comments: [ - { - id: 17, - text: 'Aubree post Marshall comment 17', - postId: 4, - userId: 102, - author: { id: 102, name: 'Marshall' }, - }, - ], - }, - ], - params: {}, - _loaders: undefined, - }; - - assert.deepEqual(context, result); - }); -}); - -async function ex1() { - const postResolvers = { - joins: { - author: () => async (post: any) => { - post.author = ( - await users.find({ - query: { - id: post.userId, - }, - }) - )[0]; - }, - starers: ($select: any) => async (post: any) => { - post.starers = await users.find({ - query: { - id: { $in: post.starIds }, - $select: $select || ['name'], - }, - }); - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex2() { - const postResolvers = { - joins: { - author: () => async (post: any) => { - post.author = ( - await users.find({ - query: { - id: post.userId, - }, - }) - )[0]; - }, - starers: ($select: any) => async (post: any) => { - post.starers = await users.find({ - query: { - id: { $in: post.starIds }, - $select: $select || ['name'], - }, - }); - }, - }, - }; - - const query = { - author: true, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers, (_context: any) => query)(context); -} - -async function ex3() { - const postResolvers = { - joins: { - author: () => async (post: any) => { - post.author = ( - await users.find({ - query: { - id: post.userId, - }, - }) - )[0]; - }, - starers: ($select: any) => async (post: any) => { - post.starers = await users.find({ - query: { - id: { $in: post.starIds }, - $select: $select || ['name'], - }, - }); - }, - }, - }; - - const query = { - author: true, - starers: [['id', 'name']], - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin( - (_context: any) => postResolvers, - (_context: any) => query, - )(context); -} - -async function ex4() { - const postResolvers: any = { - joins: { - author: () => async (post: any) => { - post.author = ( - await users.find({ - query: { - id: post.userId, - }, - }) - )[0]; - }, - starers: ($select: any) => async (post: any) => { - post.starers = await users.find({ - query: { - id: { $in: post.starIds }, - $select: $select || ['name'], - }, - }); - }, - starerCount: () => (post: any) => { - post.starerCount = post.starIds.length; - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex5() { - const postResolvers: any = { - joins: { - comments: { - resolver: ($select: any, $limit: any, $sort: any) => async (post: any) => { - post.comments = await comments.find({ - query: { - postId: post.id, - $select, - $limit: $limit || 5, - [$sort]: { createdAt: -1 }, - }, - }); - return post.comments; - }, - joins: { - author: ($select: any) => async (comment: any) => { - comment.author = ( - await users.find({ - query: { - id: comment.userId, - $select, - }, - }) - )[0]; - }, - }, - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex6() { - const commentResolvers = { - joins: { - author: (_$select: any) => async (comment: any) => { - comment.author = ( - await users.find({ - query: { - id: comment.userId, - }, - }) - )[0]; - }, - }, - }; - - const postResolvers = { - joins: { - comments: { - resolver: ($select: any, $limit: any, $sort: any) => async (post: any) => { - post.comments = await comments.find({ - query: { - postId: post.id, - $select, - $limit: $limit || 5, - [$sort]: { createdAt: -1 }, - }, - }); - return post.comments; - }, - joins: commentResolvers, - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex7() { - const postResolvers = { - before: (context: any) => { - context._loaders = { user: {} }; - - context._loaders.user.id = loaderFactory(users, 'id', false)(context); - }, - - joins: { - author: () => async (post: any, context: any) => { - post.author = await context._loaders.user.id.load(post.userId); - }, - - starers: () => async (post: any, context: any) => { - if (!post.starIds) return; - post.starers = await context._loaders.user.id.loadMany(post.starIds); - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex8() { - const postResolvers = { - before: (context: any) => { - context._loaders = { user: {} }; - - context._loaders.user.id = new BatchLoader( - async (keys: any, context: any) => { - const result = await users.find( - makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }), - ); - return getResultsByKey(keys, result, (user: any) => user.id, '!'); - }, - { context }, - ); - }, - - joins: { - author: () => async (post: any, context: any) => { - post.author = await context._loaders.user.id.load(post.userId); - }, - - starers: () => async (post: any, context: any) => { - if (!post.starIds) return; - post.starers = await context._loaders.user.id.loadMany(post.starIds); - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: 1 } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} - -async function ex9() { - const commentResolvers = { - joins: { - author: () => async (comment: any, context: any) => { - if (!comment.userId) return; - comment.author = await context._loaders.user.id.load(comment.userId); - }, - }, - }; - - const postResolvers = { - before: (context: any) => { - context._loaders = { user: {}, comments: {} }; - - context._loaders.user.id = new BatchLoader( - async (keys: any, context: any) => { - const result = await users.find( - makeCallingParams(context, { id: { $in: getUniqueKeys(keys) } }), - ); - return getResultsByKey(keys, result, (user: any) => user.id, '!'); - }, - { context }, - ); - - context._loaders.comments.postId = new BatchLoader( - async (keys: any, context: any) => { - const result = await comments.find( - makeCallingParams(context, { postId: { $in: getUniqueKeys(keys) } }), - ); - // @ts-ignore - return getResultsByKey(keys, result, (comment: any) => comment.postId, '[!]'); - }, - { context }, - ); - }, - - joins: { - author: () => async (post: any, context: any) => { - post.author = await context._loaders.user.id.load(post.userId); - }, - - starers: () => async (post: any, context: any) => { - if (!post.starIds) return; - post.starers = await context._loaders.user.id.loadMany(post.starIds); - }, - - reputation_author: - (..._args: any[]): any => - async (post: any, context: any): Promise => { - if (!post.reputation) return null; - const authors = await context._loaders.user.id.loadMany( - post.reputation.map((rep: any) => rep.userId), - ); - post.reputation.forEach((rep: any, i: any) => { - rep.author = authors[i].name; - }); - }, - - comments: { - resolver: - (..._args: any[]) => - async (post: any, context: any) => { - post.comments = await context._loaders.comments.postId.load(post.id); - return post.comments; - }, - joins: commentResolvers, - }, - }, - }; - - const context: any = { - method: 'find', - result: await posts.find({ query: { id: { $in: [1, 2, 3, 4] } } }), - params: {}, - }; - - return fastJoin(postResolvers)(context); -} diff --git a/test/hooks/fgraphql.test.ts b/test/hooks/fgraphql.test.ts deleted file mode 100755 index 27817ebe..00000000 --- a/test/hooks/fgraphql.test.ts +++ /dev/null @@ -1,777 +0,0 @@ -// @ts-ignore -import runTime from '@feathers-plus/graphql/lib/run-time'; -import BatchLoader from '@feathers-plus/batch-loader'; -import { assert } from 'vitest'; -import { parse } from 'graphql'; -import { fgraphql } from '../../src'; - -const { getResultsByKey } = BatchLoader; - -describe('services fgraphql', () => { - describe('using service resolver', () => { - /* eslint-disable */ - const beforeJane = () => ({ type: 'before', data: { first: 'Jane', last: 'Doe' } }); - const afterJane = () => ({ type: 'after', result: { first: 'Jane', last: 'Doe' } }); - - const decisionTable: any[] = [ - // Test options - // desc, schema, resolvers, recordType, query, options, context, client, result - ['schema str', s('str'), r('full'), 'User', q('obj'), o('both'), afterJane(), false, a('janeFull') ], - ['schema fcn', s('fcn'), r('full'), 'User', q('obj'), o('both'), afterJane(), false, a('janeFull') ], - ['schema obj', s('obj'), r('full'), 'User', q('obj'), o('both'), afterJane(), false, a('janeFull') ], - ['query str', s('str'), r('full'), 'User', q('obj'), o('both'), afterJane(), false, a('janeFull') ], - ['query fcn', s('str'), r('full'), 'User', q('fcn'), o('both'), afterJane(), false, a('janeFull') ], - ['opt server-', s('str'), r('full'), 'User', q('obj'), o('server-'), afterJane(), false, a('janeFull-') ], - ['opt client-', s('str'), r('full'), 'User', q('obj'), o('client-'), afterJane(), true, a('janeFull-') ], - ['before hook', s('str'), r('full'), 'User', q('obj'), o('both'), beforeJane(), false, a('janeFull') ], - ['func params', s('param'),r('params'), 'User', q('params'),o('both'), afterJane(), false, a('janeParams')], - ['join names', s('str'), r('full'), 'User', q('obj'), o('join-'), afterJane(), false, a('janeJoin') ], - // Test conversion of resolver results - // desc, schema, resolvers, recordType, query, options, context, client, result - ['undef->null', s('cnv0'), r('undefin'),'User', q('obj'), o('both'), beforeJane(), false, a('janeNull') ], - ['undef->array',s('cnv1'), r('undefin'),'User', q('obj'), o('both'), beforeJane(), false, a('janeArray0')], - ['obj->array', s('cnv1'), r('full'), 'User', q('obj'), o('both'), beforeJane(), false, a('janeArray') ], - ['array->obj', s('str'), r('array1'), 'User', q('obj'), o('both'), beforeJane(), false, a('janeFull') ], - // Test error checking - // desc, schema, resolvers, recordType, query, options, context, client, result - ['x schema', s('err1'), r('full'), 'User', 1, o('both'), afterJane(), false, 101 ], - ['x query', s('str'), r('full'), 'User', q('err1'), o('both'), afterJane(), false, 102 ], - ['x hook type', s('str'), r('full'), 'Userxxx', q('obj'), o('both'), afterJane(), false, 104 ], - ['x context', s('str'), r('full'), 'User', q('obj'), o('prop-'), afterJane(), false, 105 ], - ['x reso func', s('str'), r('err1'), 'User', q('obj'), o('both'), afterJane(), false, 203 ], - ['x array len2',s('str'), r('array2'), 'User', q('obj'), o('both'), afterJane(), false, 204 ], - // Test features not available in GraphQL - // desc, schema, resolvers, recordType, query, options, context, client, result - ['normal', s('str'), r('full'), 'User', q('obj'), o('both'), afterJane(), false, a('janeFull') ], - ['chge parent', s('str'), r('parent'), 'User', q('obj'), o('both'), afterJane(), false, a('janeMess') ], - ['value 1', s('str'), r('full'), 'User', q('value1'),o('both'), afterJane(), false, a('janeFull') ], - ['value 0', s('str'), r('full'), 'User', q('value0'),o('both'), afterJane(), false, a('jane0') ], - ['value falsey',s('str'), r('full'), 'User', q('falsey'),o('both'), afterJane(), false, a('janeFalsey')], - ['incl flds 1', s('str'), r('full'), 'User', q('obj'), o('both'), afterJane(), false, a('janeFull') ], - ['incl flds s', s('str'), r('full'), 'User', q('obj'), o('server-'), afterJane(), false, a('janeFull-') ], - ['incl flds c', s('str'), r('full'), 'User', q('obj'), o('client-'), afterJane(), true, a('janeFull-') ], - ['_none', s('str'), r('full'), 'User', q('none'), o('both'), afterJane(), false, a('janeFull-') ], - // Test join type at top level #2 - // desc, schema, resolvers, recordType, query, options, context, client, result - ['1 post', s('S2'), r('S2'), 'User', q('S2post'),o('both'), afterJane(), false, a('S2post') ], - ['1 comment', s('S2'), r('S2'), 'User', q('S2comm'),o('both'), afterJane(), false, a('S2comm') ], - ['l both', s('S2'), r('S2'), 'User', q('S2both'),o('both'), afterJane(), false, a('S2both') ], - ['1 post args', s('S2'), r('S2'), 'User', q('S2parm'),o('both'), afterJane(), false, a('S2parm') ], - ['1 post cont', s('S2'), r('S2'), 'User', q('S2parm'),o('prop+'), afterJane(), false, a('S2cont') ], - // Test join type at level #3 - // desc, schema, resolvers, recordType, query, options, ontext, client, result - ['2 all', s('S3'), r('S3'), 'User', q('S3all'), o('both'), afterJane(), false, a('S3all') ], - ]; - /* eslint-enable */ - - decisionTable.forEach( - ([desc, schema, resolvers, recordType, query, options, context, client, result]) => { - it(desc, async () => { - context.params = context.params || {}; - if (client) { - context.params.provider = 'socketio'; - } - - try { - const newContext: any = await fgraphql({ - parse, - runTime, - schema, - resolvers, - recordType, - query, - options, - })(context); - - if (!isObject(result)) { - assert.fail(`Unexpected success. Expected ${result}.`); - } else { - // inspector('result=', result); - // inspector('actual=', newContext.data || newContext.result); - assert.deepEqual(newContext.data || newContext.result, result, 'unexpected result'); - } - } catch (err: any) { - if (err.message.substr(0, 19) === 'Unexpected success.') { - throw err; - } - - if (isObject(result)) { - assert.fail(`unexpected fail: ${err.message}`); - return; - } - - assert.strictEqual(err.code, result, `unexpected error: ${err.message}`); - } - }); - }, - ); - }); - - describe('using batchloader', () => { - let recordType: any; - let schema: any; - let context: any; - let query: any; - let options: any; - let usersBatchLoader: any; - let usersBatchLoaderCalls: any; - let resolvers: any; - let result: any; - - const usersDb: any = { - 31: { _id: '31', name: 'user 31' }, - 32: { _id: '32', name: 'user 32' }, - 35: { _id: '35', name: 'user 35' }, - 36: { _id: '36', name: 'user 36' }, - 37: { _id: '37', name: 'user 37' }, - }; - - const postsDb: any = { - 11: { _id: '11', body: 'body 11', userId: '31' }, - 12: { _id: '12', body: 'body 12', userId: '31' }, - 13: { _id: '13', body: 'body 13', userId: '32' }, - }; - - const commentsDb: any = { - 21: { _id: '21', comment: 'comment 21', postId: '11', userId: '35' }, - 22: { _id: '22', comment: 'comment 22', postId: '12', userId: '35' }, - 23: { _id: '23', comment: 'comment 23', postId: '13', userId: '35' }, - 24: { _id: '24', comment: 'comment 24', postId: '11', userId: '36' }, - 25: { _id: '25', comment: 'comment 25', postId: '12', userId: '36' }, - 26: { _id: '26', comment: 'comment 26', postId: '13', userId: '36' }, - 27: { _id: '27', comment: 'comment 24', postId: '11', userId: '37' }, - 28: { _id: '28', comment: 'comment 25', postId: '12', userId: '37' }, - 29: { _id: '29', comment: 'comment 26', postId: '13', userId: '37' }, - }; - - beforeEach(() => { - usersBatchLoaderCalls = []; - recordType = 'Post'; - - schema = ` - type User { - _id: ID - name: String - } - type Post { - _id: ID - body: String - userId: ID, - author: User - comments: [Comment] - } - type Comment { - _id: ID - comment: String - postId: ID, - userId: ID, - post: Post - author: User - }`; - - context = { - type: 'after', - params: {}, - result: Object.keys(postsDb).map(key => postsDb[key]), - }; - - query = { - body: 1, - userId: 1, - author: { - name: 1, - }, - comments: { - userId: 1, - author: { - name: 1, - }, - }, - }; - - options = { - inclJoinedNames: false, - }; - - usersBatchLoader = new BatchLoader(async (keys: any) => { - usersBatchLoaderCalls.push(keys); - const result = keys.map((key: any) => usersDb[key]); - return getResultsByKey(keys, result, (rec: any) => rec._id, '!'); - }); - - resolvers = () => ({ - Post: { - // tests returning a Promise - author: (parent: any, _args: any, _content: any, _ast: any) => - usersBatchLoader.load(parent.userId), - // tests returning a value - comments: (parent: any, _args: any, _content: any, _ast: any) => { - const x: any = []; - Object.keys(commentsDb).forEach(key => { - if (commentsDb[key].postId === parent._id) { - x.push(commentsDb[key]); - } - }); - return x; - }, - }, - Comment: { - author: (parent: any, _args: any, _content: any, _ast: any) => - usersBatchLoader.load(parent.userId), - }, - }); - - result = [ - { - body: 'body 11', - userId: '31', - comments: [ - { userId: '35', author: { _id: '35', name: 'user 35' } }, - { userId: '36', author: { _id: '36', name: 'user 36' } }, - { userId: '37', author: { _id: '37', name: 'user 37' } }, - ], - author: { _id: '31', name: 'user 31' }, - }, - { - body: 'body 12', - userId: '31', - comments: [ - { userId: '35', author: { _id: '35', name: 'user 35' } }, - { userId: '36', author: { _id: '36', name: 'user 36' } }, - { userId: '37', author: { _id: '37', name: 'user 37' } }, - ], - author: { _id: '31', name: 'user 31' }, - }, - { - body: 'body 13', - userId: '32', - comments: [ - { userId: '35', author: { _id: '35', name: 'user 35' } }, - { userId: '36', author: { _id: '36', name: 'user 36' } }, - { userId: '37', author: { _id: '37', name: 'user 37' } }, - ], - author: { _id: '32', name: 'user 32' }, - }, - ]; - }); - - it('batches calls', async () => { - try { - const newContext: any = await fgraphql({ - parse, - runTime, - schema, - resolvers, - recordType, - query, - options, - })(context); - - // inspector('batchloader calls', usersBatchLoaderCalls); - // inspector('actual=', newContext.data || newContext.result); - - assert.deepEqual(newContext.data || newContext.result, result, 'unexpected result'); - assert.deepEqual( - usersBatchLoaderCalls, - [['31', '32', '35', '36', '37']], - 'unexpected calls', - ); - } catch (err) { - console.log(err); - throw err; - } - }); - }); -}); - -function isObject(obj: any) { - return typeof obj === 'object' && obj !== null; -} - -// schemas -function s(typ: any) { - const SDL1 = ` -type User { - _id: ID - firstName: String - lastName: String - fullName: String! -}`; - - const S2 = ` -type User { - _id: ID - firstName: String - lastName: String - posts: [Post] - comments: [Comment] -} -type Post { - _id: ID - body: String -} -type Comment { - _id: ID - comment: String -}`; - - const S3 = ` -type User { - _id: ID - firstName: String - lastName: String - posts: [Post] - comments: [Comment] -} -type Post { - _id: ID - body: String - author: User -} -type Comment { - _id: ID - comment: String - author: User -}`; - - const C0 = ` -type User { - _id: ID - firstName: String - lastName: String - fullName: String -}`; - - const C1 = ` -type User { - _id: ID - firstName: String - lastName: String - fullName: [String] -}`; - - switch (typ) { - case 'str': - return SDL1; - case 'cnv0': - return C0; - case 'cnv1': - return C1; - case 'fcn': - return () => SDL1; - case 'obj': - return { - User: { - firstName: { typeof: 'String' }, - lastName: { typeof: 'String' }, - fullName: { nonNullTypeField: true, typeof: 'String' }, - }, - }; - case 'param': - return { - User: { - firstName: { typeof: 'String' }, - lastName: { typeof: 'String' }, - fullName: { nonNullTypeField: true, typeof: 'String' }, - params: { typeof: 'JSON' }, - }, - }; - case 'err1': - return (): any => null; - - case 'S2': - return S2; - case 'S3': - return S3; - default: - throw new Error(`Invalid typ ${typ} for "s" function.`); - } -} - -// resolvers -function r(typ: any) { - return function resolvers(_app: any, _options: any) { - // eslint-disable-line no-unused-vars - // const { convertArgsToFeathers, extractAllItems, extractFirstItem } = options; // eslint-disable-line no-unused-vars - // const convertArgs = convertArgsToFeathers([]); // eslint-disable-line no-unused-vars - // let comments = app.service('/comments'); - - switch (typ) { - case 'full': - return { - User: { - // fullName: String! - fullName: (parent: any, _args: any, _content: any, _ast: any) => - `${parent.first} ${parent.last}`, // eslint-disable-line no-unused-vars - }, - }; - case 'parent': - return { - User: { - // fullName: String! - fullName: (parent: any, _args: any, _content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - const returns = `${parent.first} ${parent.last}`; - parent.first = 'foo'; - return returns; - }, - }, - }; - case 'params': - return { - User: { - // fullName: String! - fullName: (parent: any, _args: any, _content: any, _ast: any) => - `${parent.first} ${parent.last}`, // eslint-disable-line no-unused-vars - params: (_parent: any, args: any, _content: any, ast: any) => ({ - args, - ast, - }), - }, - }; - case 'err1': - return { User: { fullName: 'foo' } }; - - case 'array2': - return { - User: { - fullName: () => [{ fullName: 'foo' }, { fullName: 'foo' }], - }, - }; - case 'undefin': - return { - User: { - fullName: (): any => undefined, - }, - }; - case 'array1': - return { - User: { - fullName: (parent: any) => [`${parent.first} ${parent.last}`], - }, - }; - - case 'S2': - return { - User: { - // posts: [Post] - posts: (_parent: any, args: any, content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - return [ - { _id: '1001', body: 'foo body' }, - { _id: (args.params || content.foo || {})._id || '1002', body: 'bar body' }, - ]; - }, - // comments: [Comment] - comments: (_parent: any, _args: any, _content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - return [ - { _id: '2001', comment: 'foo comment' }, - { _id: '2002', comment: 'bar comment' }, - ]; - }, - }, - Post: {}, - }; - - case 'S3': - return { - User: { - // posts: [Post] - posts: (_parent: any, args: any, _content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - return [ - { _id: '1001', body: 'foo body' }, - { _id: (args.params || {})._id || '1002', body: 'bar body' }, - ]; - }, - // comments: [Comment] - comments: (_parent: any, _args: any, _content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - return [ - { _id: '2001', comment: 'foo comment' }, - { _id: '2002', comment: 'bar comment' }, - ]; - }, - }, - Post: { - // author: User - author: (_parent: any, _args: any, _content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - return { _id: '3001', first: 'Jane', last: 'Doe' }; - }, - }, - Comment: { - // author: User - author: (_parent: any, _args: any, _content: any, _ast: any) => { - // eslint-disable-line no-unused-vars - return { _id: '4001', first: 'Jane', last: 'Doe' }; - }, - }, - }; - default: - throw new Error(`Invalid typ ${typ} for "r" function.`); - } - }; -} - -// query -function q(typ: any): any { - switch (typ) { - /* eslint-disable */ - case 'obj': - return { fullName: {} } ; - case 'none': - return { fullName: {}, _none: {} } ; - case 'value1': - return { fullName: 1, first: 1, last: 1 } ; - case 'value0': - return { fullName: 0, first: 1, last: 0 } ; - case 'falsey': - return { fullName: '', first: null, last: 1 } ; - case 'fcn': - return () => ({ fullName: {} } ); - case 'params': - return { fullName: {}, params: { - _args: { key: 1, query: { foo: 2 }, params: { bar: 3 }, baz: 4 } - } } ; - case 'err1': - return undefined; - - case 'S2post': - return { posts: {} } ; - case 'S2comm': - return { comments: {} } ; - case 'S2both': - return { posts: {}, comments: {} } ; - case 'S2parm': - return { - posts: { - _args: { params: { _id: '9999' } } - } - }; - case 'S2cont': - return { - posts: {} - }; - - case 'S3all': - return { - posts: { - author: {} - }, - comments: { - author: {} - } - }; - - case 'big1': - return { - fullName: {}, - posts: { - _args: { query: { } }, // { key: any, query: { ... }, params: { ... } - author: { - firstName: '', - fullName: '', // {} or '' doesn't matter as no props inside would-have-been {} - posts: { - draft: '', - }, - }, - }, - comments: {}, - followed_by: { - foo: '', // non-resolver name looks like field name. forces drop of real fields - follower: { - foo: '', - fullName: {}, - } - }, - following: { - foo: '', - followee: { - foo: '', - fullName: {}, - }, - }, - likes: { - author: { - firstName: '', - lastName: '', - }, - comment: { - body: '' - }, - }, - }; - default: - throw new Error(`Invalid typ ${typ} for "q" function.`); - /* eslint-enable */ - } -} - -// options -function o(typ: any) { - switch (typ) { - case 'both': - return { - inclAllFieldsServer: true, - inclAllFieldsClient: true, - }; - case 'server-': - return { inclAllFieldsServer: false }; - case 'client-': - return { inclAllFieldsClient: false }; - case 'loop': - return { skipHookWhen: () => false }; - case 'prop-': - return { - inclAllFieldsServer: true, - inclAllFieldsClient: true, - extraAuthProps: 1, - }; - case 'prop+': - return { - inclAllFieldsServer: true, - inclAllFieldsClient: true, - extraAuthProps: ['foo'], - }; - case 'join-': - return { - inclAllFieldsServer: true, - inclAllFieldsClient: true, - inclJoinedNames: false, - }; - default: - throw new Error(`Invalid typ ${typ} for "o" function.`); - } -} - -// results -function a(typ: any) { - switch (typ) { - /* eslint-disable */ - case 'janeNull' : - return { first: 'Jane', last: 'Doe', fullName: null, _include: ['fullName'] }; - case 'janeFull' : - return { first: 'Jane', last: 'Doe', fullName: 'Jane Doe', _include: ['fullName'] }; - case 'janeArray' : - return { first: 'Jane', last: 'Doe', fullName: ['Jane Doe'], _include: ['fullName'] }; - case 'janeArray0' : - return { first: 'Jane', last: 'Doe', fullName: [], _include: ['fullName'] }; - case 'janeFull-' : - return { fullName: 'Jane Doe', _include: ['fullName'] }; - case 'janeMess' : - return { first: 'foo', last: 'Doe', fullName: 'Jane Doe', _include: ['fullName'] }; - case 'jane0' : - return { first: 'Jane' }; - case 'janeFalsey' : - return { last: 'Doe' }; - case 'janeJoin' : - return { first: 'Jane', last: 'Doe', fullName: 'Jane Doe' }; - case 'janeParams' : - return { first: 'Jane', last: 'Doe', fullName: 'Jane Doe', _include: ['fullName', 'params'], - params: { - args: { key: 1, query: { foo: 2 }, params: { bar: 3 }, baz: 4 }, ast: undefined - } as any }; - - case 'S2post' : - return { - first: 'Jane', - last: 'Doe', - posts: [ - { _id: '1001', body: 'foo body' }, - { _id: '1002', body: 'bar body' }, - ], - _include: ['posts'] - }; - case 'S2parm' : - return { - first: 'Jane', - last: 'Doe', - posts: [ - { _id: '1001', body: 'foo body' }, - { _id: '9999', body: 'bar body' }, - ], - _include: ['posts'] - }; - case 'S2comm' : - return { - first: 'Jane', - last: 'Doe', - comments: [ - { _id: '2001', comment: 'foo comment' }, - { _id: '2002', comment: 'bar comment' }, - ], - _include: ['comments'] - }; - case 'S2cont' : - return { - first: 'Jane', - last: 'Doe', - posts: [ - { _id: '1001', body: 'foo body' }, - { _id: '9999', body: 'bar body' }, - ], - _include: ['posts'] - }; - case 'S2both' : - return { - first: 'Jane', - last: 'Doe', - posts: [ - { _id: '1001', body: 'foo body' }, - { _id: '1002', body: 'bar body' }, - ], - comments: [ - { _id: '2001', comment: 'foo comment' }, - { _id: '2002', comment: 'bar comment' }, - ], - _include: ['posts', 'comments'] - }; - - case 'S3all' : - return { - first: 'Jane', - last: 'Doe', - posts: [ - { _id: '1001', - body: 'foo body', - author: { _id: '3001', first: 'Jane', last: 'Doe' }, - _include: ['author'] - }, - { - _id: '1002', - body: 'bar body', - author: { _id: '3001', first: 'Jane', last: 'Doe' }, - _include: ['author'] - } - ], - comments: [ - { _id: '2001', - comment: 'foo comment', - author: { _id: '4001', first: 'Jane', last: 'Doe' }, - _include: ['author'] - }, - { - _id: '2002', - comment: 'bar comment', - author: { _id: '4001', first: 'Jane', last: 'Doe' }, - _include: ['author'] - } - ], - _include: ['posts', 'comments'] - } - - default: - throw new Error(`Invalid typ ${typ} for "a" function.`); - } - /* eslint-enable */ -} - -/* -const { inspect } = require('util'); -function inspector(desc, obj) { - console.log(desc); - console.log(inspect(obj, { colors: true, depth: 5 })); -} -*/ diff --git a/test/hooks/get-replace-items.test.ts b/test/hooks/get-replace-items.test.ts deleted file mode 100755 index e1105962..00000000 --- a/test/hooks/get-replace-items.test.ts +++ /dev/null @@ -1,241 +0,0 @@ -import { assert } from 'vitest'; -import { actOnDispatch, getItems, replaceItems } from '../../src'; - -// Tests when context.params._actOn === 'dispatch' are in act-on.test.ts - -describe('services getItems & replaceItems', () => { - let hookBefore: any; - let hookAfter: any; - let hookBeforeArray: any; - let hookAfterArray: any; - let hookFindPaginate: any; - let hookFind: any; - - describe('getItems', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - hookBeforeArray = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { first: 'Jane2', last: 'Doe2' }, - }; - hookAfterArray = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: [ - { first: 'John2', last: 'Doe2' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { first: 'John3', last: 'Doe3' }, - { first: 'Jane3', last: 'Doe3' }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - }); - - it('updates hook before::create item', () => { - const stuff = getItems(hookBefore); - assert.deepEqual(stuff, { first: 'John', last: 'Doe' }); - }); - - it('updates hook before::create items', () => { - const stuff = getItems(hookBeforeArray); - assert.deepEqual(stuff, [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ]); - }); - - it('updates hook after::create item', () => { - const stuff = getItems(hookAfter); - assert.deepEqual(stuff, { first: 'Jane2', last: 'Doe2' }); - }); - - it('updates hook after::create items', () => { - const stuff = getItems(hookAfterArray); - assert.deepEqual(stuff, [ - { first: 'John2', last: 'Doe2' }, - { first: 'Jane', last: 'Doe' }, - ]); - }); - - it('updates hook after::find item', () => { - const stuff = getItems(hookFindPaginate); - assert.deepEqual(stuff, [ - { first: 'John3', last: 'Doe3' }, - { first: 'Jane3', last: 'Doe3' }, - ]); - }); - - it('updates hook after::find item paginated', () => { - const stuff = getItems(hookFind); - assert.deepEqual(stuff, [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ]); - }); - - it('does not throw on before without data', () => { - const hookBad: any = { type: 'before', method: 'create', params: { provider: 'rest' } }; - const stuff = getItems(hookBad); - assert.equal(stuff, undefined); - }); - - it('does not throw on after without data', () => { - const hookBad: any = { type: 'after', method: 'find', params: { provider: 'rest' } }; - const stuff = getItems(hookBad); - assert.equal(stuff, undefined); - }); - }); - - describe('replaceItems', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', params: { provider: 'rest' } }; - hookAfter = { type: 'after', method: 'create', params: { provider: 'rest' } }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 200, - data: [], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - }; - }); - - it('updates hook before::create item', () => { - replaceItems(hookBefore, { a: 1 }); - assert.deepEqual(hookBefore.data, { a: 1 }); - }); - - it('updates hook before::create items', () => { - replaceItems(hookBefore, [{ a: 1 }, { b: 2 }]); - assert.deepEqual(hookBefore.data, [{ a: 1 }, { b: 2 }]); - }); - - it('updates hook after::create item', () => { - replaceItems(hookAfter, { a: 1 }); - assert.deepEqual(hookAfter.result, { a: 1 }); - }); - - it('updates hook after::create items', () => { - replaceItems(hookAfter, [{ a: 1 }, { b: 2 }]); - assert.deepEqual(hookAfter.result, [{ a: 1 }, { b: 2 }]); - }); - - it('updates hook after::find item', () => { - replaceItems(hookFind, { a: 1 }); - assert.deepEqual(hookFind.result, { a: 1 }); - }); - - it('updates hook after::find items', () => { - replaceItems(hookFind, [{ a: 1 }, { b: 2 }]); - assert.deepEqual(hookFind.result, [{ a: 1 }, { b: 2 }]); - }); - - it('updates hook after::find item paginated NOTE THIS TEST NOTE THIS TEST', () => { - replaceItems(hookFindPaginate, { a: 1 }); - assert.equal(hookFindPaginate.result.total, 200); - assert.deepEqual(hookFindPaginate.result.data, [{ a: 1 }]); - }); - - it('updates hook after::find items paginated', () => { - replaceItems(hookFindPaginate, [{ a: 1 }, { b: 2 }]); - assert.equal(hookFindPaginate.result.total, 200); - assert.deepEqual(hookFindPaginate.result.data, [{ a: 1 }, { b: 2 }]); - }); - }); - - describe('replaceItems actOnDispatch', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', params: { provider: 'rest' } }; - hookAfter = { type: 'after', method: 'create', params: { provider: 'rest' } }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - dispatch: { - total: 200, - data: [], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - }; - }); - - it('updates hook after::create item', async () => { - await actOnDispatch(() => replaceItems(hookAfter, { a: 1 }))(hookAfter); - assert.deepEqual(hookAfter.dispatch, { a: 1 }); - }); - - it('updates hook after::create items', async () => { - await actOnDispatch(() => replaceItems(hookAfter, [{ a: 1 }, { b: 2 }]))(hookAfter); - assert.deepEqual(hookAfter.dispatch, [{ a: 1 }, { b: 2 }]); - }); - - it('updates hook after::find item', async () => { - await actOnDispatch(() => replaceItems(hookFind, { a: 1 }))(hookFind); - assert.deepEqual(hookFind.dispatch, { a: 1 }); - }); - - it('updates hook after::find items', async () => { - await actOnDispatch(() => replaceItems(hookFind, [{ a: 1 }, { b: 2 }]))(hookFind); - assert.deepEqual(hookFind.dispatch, [{ a: 1 }, { b: 2 }]); - }); - - it('updates hook after::find item paginated NOTE THIS TEST NOTE THIS TEST', async () => { - await actOnDispatch(() => replaceItems(hookFindPaginate, { a: 1 }))(hookFindPaginate); - assert.equal(hookFindPaginate.dispatch.total, 200); - assert.deepEqual(hookFindPaginate.dispatch.data, [{ a: 1 }]); - }); - - it('updates hook after::find items paginated', async () => { - await actOnDispatch(() => replaceItems(hookFindPaginate, [{ a: 1 }, { b: 2 }]))( - hookFindPaginate, - ); - assert.equal(hookFindPaginate.dispatch.total, 200); - assert.deepEqual(hookFindPaginate.dispatch.data, [{ a: 1 }, { b: 2 }]); - }); - }); -}); diff --git a/test/hooks/iff-else.test.ts b/test/hooks/iff-else.test.ts deleted file mode 100755 index b36757e4..00000000 --- a/test/hooks/iff-else.test.ts +++ /dev/null @@ -1,681 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { assert } from 'vitest'; -import { iff } from '../../src'; -import { isPromise } from '../../src/common'; - -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; -let hookFcnAsyncCalls: any; -let hookFcnCalls: any; -let predicateHook: any; -let predicateOptions: any; -let predicateValue: any; - -const predicateSync = (hook: any) => { - predicateHook = clone(hook); - return true; -}; - -const predicateSync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return true; -}; - -const predicateAsync = (hook: any) => { - predicateHook = clone(hook); - return new Promise(resolve => resolve(true)); -}; - -const predicateAsync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return new Promise(resolve => resolve(true)); -}; - -const predicateAsyncFunny = (hook: any) => { - predicateHook = clone(hook); - return new Promise(resolve => { - predicateValue = 'abc'; - return resolve(predicateValue); - }); -}; - -const hookFcnSync = (hook: HookContext): HookContext => { - hookFcnSyncCalls += 1; - - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -const hookFcnAsync = (hook: HookContext) => - new Promise(resolve => { - hookFcnAsyncCalls += 1; - - hook.data.first = hook.data.first.toLowerCase(); - - resolve(hook); - }); - -const hookCb = (hook: any) => { - hookFcnCalls += 1; - - return hook; -}; - -describe('services iff - sync predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if truthy non-function', () => { - return ( - iff( - // @ts-ignore - 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('does not call sync hook function if falsey non-function', () => { - // @ts-ignore - const result: any = iff('', hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); - - it('calls sync hook function if sync predicate truthy', () => { - return ( - iff( - // @ts-ignore - () => 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('does not call sync hook function if sync predicate falsey', () => { - // @ts-ignore - const result = iff(() => '', hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); -}); - -describe('services iff - sync predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if sync predicate truthy', () => { - return ( - iff( - true, - hookFcnAsync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('does not call async hook function if sync predicate falsey', () => { - const result = iff(false, hookFcnAsync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); - - it('calls async hook function if sync predicate returns truthy', () => { - return ( - iff( - () => true, - hookFcnAsync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -describe('services iff - async predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if aync predicate truthy', () => { - return ( - iff( - () => new Promise(resolve => resolve(true)), - hookFcnSync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }) - ); - }); - - it('does not call sync hook function if async predicate falsey', () => { - return ( - iff( - () => new Promise(resolve => resolve(false)), - hookFcnSync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }) - ); - }); -}); - -describe('services iff - async predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if aync predicate truthy', () => { - return ( - iff( - () => new Promise(resolve => resolve(true)), - hookFcnAsync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }) - ); - }); - - it('does not call async hook function if async predicate falsey', () => { - return ( - iff( - () => new Promise(resolve => resolve(false)), - hookFcnAsync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }) - ); - }); -}); - -describe('services iff - sync predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - }); - - it('does not need to access hook', () => { - return ( - iff( - // @ts-ignore - () => 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('is passed hook as param', () => { - return ( - iff( - predicateSync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('a higher order predicate can pass more options', () => { - return ( - iff( - predicateSync2({ z: 'z' }), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateOptions, { z: 'z' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -describe('services iff - async predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - predicateValue = null; - }); - - it('is passed hook as param', () => { - return ( - iff( - predicateAsync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }) - ); - }); - - it('is resolved', () => { - return ( - iff( - // @ts-ignore - predicateAsyncFunny, - hookFcnSync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - - assert.equal(predicateValue, 'abc'); - }) - ); - }); - - it('a higher order predicate can pass more options', () => { - return ( - iff( - predicateAsync2({ y: 'y' }), - hookFcnSync, - )(hook) - // @ts-ignore - .then((result1: any) => { - assert.deepEqual(predicateOptions, { y: 'y' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }) - ); - }); -}); - -describe('services iff - runs .else()', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - hookFcnCalls = 0; - }); - - it('using iff(true, ...)', () => { - return ( - iff( - true, - hookFcnSync, - hookFcnSync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 3); - assert.equal(hookFcnAsyncCalls, 0); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('using iff(true, ...).else(...)', () => { - return ( - iff(true, hookFcnSync, hookFcnSync, hookFcnSync) - .else(hookFcnSync)(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 3); - assert.equal(hookFcnAsyncCalls, 0); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('using if(false).else(...)', () => { - return ( - iff(false, hookFcnSync) - .else( - hookFcnSync, - hookFcnSync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 3); - assert.equal(hookFcnAsyncCalls, 0); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -describe('services iff - runs iff(true, iff(true, ...)', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - hookFcnCalls = 0; - }); - - it('using iff(true, iff(true, hookFcnSync))', () => { - return ( - iff( - true, - hookFcnAsync, - iff(true, hookFcnSync), - hookCb, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('using iff(true, iff(true, hookFcnAsync))', () => { - return ( - iff( - true, - hookFcnSync, - iff(true, hookFcnAsync), - hookCb, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('runs iff(true, iff(true, hookFcnCb))', () => { - return ( - iff( - true, - hookFcnSync, - iff(true, hookCb), - hookFcnAsync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -describe('services iff - runs iff(true, iff(false).else(...)', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - hookFcnCalls = 0; - }); - - it('using iff(true, iff(false).else(hookFcnSync))', () => { - return ( - iff( - true, - hookFcnAsync, - iff(false, hookCb).else(hookFcnSync), - hookFcnAsync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 2); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('using iff(true, iff(false).else(hookFcnAsync))', () => { - return ( - iff( - true, - hookFcnSync, - iff(false, hookFcnSync).else(hookFcnAsync), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 2); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -describe('services iff - runs iff(false).else(iff(...).else(...))', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - hookFcnCalls = 0; - }); - - it('using iff(false).else(iff(true, ...))', () => { - return ( - iff(false, hookCb) - .else( - hookFcnSync, - iff(true, hookFcnAsync), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 2); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('runs iff(false).else(iff(false).else(...))', () => { - return ( - iff(false, hookCb) - .else( - hookFcnSync, - iff(false, hookFcnSync).else(hookFcnAsync), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 2); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 0); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -describe('services iff - multiple iff() sequentially', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - hookFcnCalls = 0; - }); - - it('runs in iff(true, ...)', () => { - return ( - iff( - true, - hookCb, - iff(true, hookFcnSync, hookFcnSync, hookFcnSync), - hookCb, - iff(true, hookFcnAsync, hookFcnAsync, hookFcnAsync, hookFcnAsync), - hookCb, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 3); - assert.equal(hookFcnAsyncCalls, 4); - assert.equal(hookFcnCalls, 3); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('runs in iff(false).else(...)', () => { - return ( - iff(false, hookCb) - .else( - hookFcnSync, - iff(true, hookFcnAsync), - iff(false, hookFcnSync).else(hookCb), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.equal(hookFcnSyncCalls, 2); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - - assert.deepEqual(hook, hookAfter); - }) - ); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/iff.test.ts b/test/hooks/iff.test.ts deleted file mode 100755 index 3cd132ca..00000000 --- a/test/hooks/iff.test.ts +++ /dev/null @@ -1,407 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { assert } from 'vitest'; -import { iff } from '../../src'; -import { isPromise } from '../../src/common'; - -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; -let hookFcnAsyncCalls: any; -let hookFcnCbCalls: any; -let predicateHook: any; -let predicateOptions: any; -let predicateValue: any; - -const predicateSync = (hook: any) => { - predicateHook = clone(hook); - return true; -}; - -const predicateSync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return true; -}; - -const predicateAsync = (hook: any) => { - predicateHook = clone(hook); - return new Promise(resolve => resolve(true)); -}; - -const predicateAsync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return new Promise(resolve => resolve(true)); -}; - -const predicateAsyncFunny = (hook: any) => { - predicateHook = clone(hook); - return new Promise(resolve => { - predicateValue = 'abc'; - return resolve(predicateValue); - }); -}; - -const hookFcnSync = (hook: HookContext): HookContext => { - hookFcnSyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -const hookFcnAsync = (hook: HookContext) => - new Promise(resolve => { - hookFcnAsyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - resolve(hook); - }); - -const hookFcn = (hook: HookContext): HookContext => { - hookFcnCbCalls = +1; - - return hook; -}; - -describe('services iff - sync predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if truthy non-function', () => { - iff( - // @ts-ignore - 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if falsey non-function', () => { - // @ts-ignore - const result = iff('', hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); - - it('calls sync hook function if sync predicate truthy', () => { - iff( - // @ts-ignore - () => 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if sync predicate falsey', () => { - // @ts-ignore - const result = iff(() => '', hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); -}); - -describe('services iff - sync predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if sync predicate truthy', async () => { - const result = iff(true, hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call async hook function if sync predicate falsey', () => { - const result = iff(false, hookFcnAsync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } - - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - - it('calls async hook function if sync predicate returns truthy', async () => { - const result = iff(() => true, hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -describe('services iff - async predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if aync predicate truthy', async () => { - const result = iff(() => new Promise(resolve => resolve(true)), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('does not call sync hook function if async predicate falsey', async () => { - const result = iff(() => new Promise(resolve => resolve(false)), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - }); -}); - -describe('services iff - async predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if aync predicate truthy', async () => { - const result = iff(() => new Promise(resolve => resolve(true)), hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('does not call async hook function if async predicate falsey', async () => { - const result = iff(() => new Promise(resolve => resolve(false)), hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - }); -}); - -describe('services iff - sync predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - }); - - it('does not need to access hook', () => { - iff( - // @ts-ignore - () => 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('is passed hook as param', () => { - iff( - predicateSync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('a higher order predicate can pass more options', () => { - iff( - predicateSync2({ z: 'z' }), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateOptions, { z: 'z' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -describe('services iff - async predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - predicateValue = null; - }); - - it('is passed hook as param', async () => { - // @ts-ignore - const result = iff(predicateAsync, hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('is resolved', async () => { - // @ts-ignore - const result = iff(predicateAsyncFunny, hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - - assert.equal(predicateValue, 'abc'); - }); - }); - - it('a higher order predicate can pass more options', async () => { - // @ts-ignore - const result = iff(predicateAsync2({ y: 'y' }), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateOptions, { y: 'y' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); -}); - -describe('services iff - runs multiple hooks', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('runs successfully', async () => { - await iff( - true, - hookFcnSync, - hookFcnAsync, - hookFcn, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCbCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/iffelse.test.ts b/test/hooks/iffelse.test.ts deleted file mode 100755 index 2a46dabb..00000000 --- a/test/hooks/iffelse.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { assert } from 'vitest'; -import { iffElse, some, every } from '../../src'; - -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; -let hookFcnAsyncCalls: any; -let hookFcnCalls: any; -let predicateParam1: any; -let predicateParam2: any; -let predicateParam3: any; -let predicateParam4: any; -let context: any; -let predicateTrueContext: any; -let hookFcnSyncContext: any; -let hookFcnAsyncContext: any; -let hookFcnContext: any; - -const hookFcnSync = function (this: any, hook: any) { - hookFcnSyncContext = this; - - hookFcnSyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -const hookFcnAsync = function (this: any, hook: any) { - hookFcnAsyncContext = this; - - return new Promise(resolve => { - hookFcnAsyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - resolve(hook); - }); -}; - -const hookFcn = function (this: any, hook: any, _cb: any) { - hookFcnContext = this; - - hookFcnCalls = +1; - - return hook; -}; - -const predicateTrue = function (this: any, hook: any, more2: any, more3: any, more4: any): true { - predicateTrueContext = this; - - predicateParam1 = hook; - predicateParam2 = more2; - predicateParam3 = more3; - predicateParam4 = more4; - - return true; -}; - -describe('services iffElse', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - describe('runs single hook', () => { - it('when true', () => { - return ( - iffElse( - true, - hookFcnSync, - hookFcnAsync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('when false', () => { - return ( - iffElse( - false, - hookFcnSync, - hookFcnAsync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 0); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - }); - - describe('runs multiple hooks', () => { - it('when true', () => { - return ( - iffElse( - true, - // @ts-ignore - [hookFcnSync, hookFcnAsync, hookFcn], - null, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('when false', () => { - return ( - // @ts-ignore - iffElse(false, null, [hookFcnSync, hookFcnAsync, hookFcn])(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - assert.deepEqual(hook, hookAfter); - }) - ); - }); - }); - - describe('predicate gets right params', () => { - it('when true', () => { - return ( - iffElse( - // @ts-ignore - predicateTrue, - [hookFcnSync, hookFcnAsync, hookFcn], - null, - )(hook) - // @ts-ignore - .then(() => { - assert.deepEqual(predicateParam1, hook, 'param1'); - assert.strictEqual(predicateParam2, undefined, 'param2'); - assert.strictEqual(predicateParam3, undefined, 'param3'); - assert.strictEqual(predicateParam4, undefined, 'param4'); - }) - ); - }); - - it('every passes on correct params', () => { - return ( - iffElse( - // @ts-ignore - every(predicateTrue), - // @ts-ignore - [hookFcnSync, hookFcnAsync, hookFcn], - null, - )(hook) - // @ts-ignore - .then(() => { - assert.deepEqual(predicateParam1, hook, 'param1'); - assert.strictEqual(predicateParam2, undefined, 'param2'); - assert.strictEqual(predicateParam3, undefined, 'param3'); - assert.strictEqual(predicateParam4, undefined, 'param4'); - }) - ); - }); - - it('some passes on correct params', () => { - return ( - iffElse( - // @ts-ignore - some(predicateTrue), - // @ts-ignore - [hookFcnSync, hookFcnAsync, hookFcn], - null, - )(hook) - // @ts-ignore - .then(() => { - assert.deepEqual(predicateParam1, hook, 'param1'); - assert.strictEqual(predicateParam2, undefined, 'param2'); - assert.strictEqual(predicateParam3, undefined, 'param3'); - assert.strictEqual(predicateParam4, undefined, 'param4'); - }) - ); - }); - }); - - describe('predicate and hooks get right context', () => { - beforeEach(() => { - context = { service: 'abc' }; - predicateTrueContext = undefined; - hookFcnSyncContext = undefined; - hookFcnAsyncContext = undefined; - hookFcnContext = undefined; - }); - - it('services', () => { - return ( - // @ts-ignore - iffElse(predicateTrue, [hookFcnSync, hookFcnAsync, hookFcn], null) - .call(context, hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - assert.deepEqual(hook, hookAfter); - - assert.deepEqual(predicateTrueContext, { service: 'abc' }); - assert.deepEqual(hookFcnSyncContext, { service: 'abc' }); - assert.deepEqual(hookFcnAsyncContext, { service: 'abc' }); - assert.deepEqual(hookFcnContext, { service: 'abc' }); - }) - ); - }); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/is-provider.test.ts b/test/hooks/is-provider.test.ts deleted file mode 100755 index 0e7106b4..00000000 --- a/test/hooks/is-provider.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { assert } from 'vitest'; -import { iff, isProvider } from '../../src'; -import { isPromise } from '../../src/common'; - -let hookServer: any; -let hookSocketio: any; - -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; - -const hookFcnSync = (hook: any) => { - hookFcnSyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -describe('services isProvider - predicate', () => { - beforeEach(() => { - hookServer = { type: 'before', method: 'create', params: { provider: '' } }; - hookSocketio = { type: 'before', method: 'create', params: { provider: 'socketio' } }; - }); - - it('returns a function', () => { - const fcn = isProvider('server'); - - assert.isFunction(fcn); - }); - - it('gets passed the hook', () => { - const hook = clone(hookServer); - const result = isProvider('server')(hook); - - assert.equal(result, true); - }); - - it('throws on no args', () => { - assert.throws(() => isProvider()); - }); - - it('finds provider with 1 arg', () => { - const hook = clone(hookSocketio); - const result = isProvider('socketio')(hook); - - assert.equal(result, true); - }); - - it('finds provider with 2 args', () => { - const hook = clone(hookSocketio); - const result = isProvider('rest', 'socketio')(hook); - - assert.equal(result, true); - }); - - it('finds server', () => { - const hook = clone(hookServer); - const result = isProvider('rest', 'socketio', 'server')(hook); - - assert.equal(result, true); - }); - - it('finds external', () => { - const hook = clone(hookSocketio); - const result = isProvider('rest', 'server', 'external')(hook); - - assert.equal(result, true); - }); - - it('fails properly if not provider', () => { - const hook = clone(hookServer); - const result = isProvider('socketio')(hook); - - assert.equal(result, false); - }); - - it('fails properly if not external', () => { - const hook = clone(hookServer); - const result = isProvider('external')(hook); - - assert.equal(result, false); - }); - - it('fails properly if not server', () => { - const hook = clone(hookSocketio); - const result = isProvider('server')(hook); - - assert.equal(result, false); - }); -}); - -describe('services isProvider - works with iff', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - data: { first: 'John' }, - params: { provider: 'rest' }, - }; - hookAfter = { - type: 'before', - method: 'create', - data: { first: 'john' }, - params: { provider: 'rest' }, - }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - }); - - it('calls sync hook function if truthy', () => { - iff( - isProvider('rest'), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if falsey', () => { - const result = iff(isProvider('server'), hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/keep-in-array.test.ts b/test/hooks/keep-in-array.test.ts deleted file mode 100755 index 32aba0a0..00000000 --- a/test/hooks/keep-in-array.test.ts +++ /dev/null @@ -1,274 +0,0 @@ -import { assert } from 'vitest'; - -import { keepInArray } from '../../src'; - -let hookBefore: any; -let hookAfter: any; -let hookFindPaginate: any; -let hookFind: any; -let hookFindNested: any; - -describe('services keepInArray', () => { - describe('removes fields', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: 'John', last: 'Doe' }] }, - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { users: [{ first: 'Jane', last: 'Doe' }] }, - }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { users: [{ first: 'John', last: 'Doe' }] }, - { users: [{ first: 'Jane', last: 'Doe' }] }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: [ - { users: [{ first: 'John', last: 'Doe' }] }, - { users: [{ first: 'Jane', last: 'Doe' }] }, - ], - }; - }); - - it('updates hook before::create', () => { - keepInArray('users', ['last'])(hookBefore); - assert.deepEqual(hookBefore.data, { users: [{ last: 'Doe' }] }); - }); - - it('ignores bad or missing field', () => { - keepInArray('xx', ['last'])(hookBefore); - assert.deepEqual(hookBefore.data, { users: [{ first: 'John', last: 'Doe' }] }); - }); - - it('updates hook after::find with pagination', () => { - keepInArray('users', ['first'])(hookFindPaginate); - assert.deepEqual(hookFindPaginate.result.data, [ - { users: [{ first: 'John' }] }, - { users: [{ first: 'Jane' }] }, - ]); - }); - - it('updates hook after::find with no pagination', () => { - keepInArray('users', ['first'])(hookFind); - assert.deepEqual(hookFind.result, [ - { users: [{ first: 'John' }] }, - { users: [{ first: 'Jane' }] }, - ]); - }); - - it('updates hook after', () => { - keepInArray('users', ['first'])(hookAfter); - assert.deepEqual(hookAfter.result, { users: [{ first: 'Jane' }] }); - }); - - it('updates when called internally on server', () => { - hookAfter.params.provider = ''; - keepInArray('users', ['first'])(hookAfter); - assert.deepEqual(hookAfter.result, { users: [{ first: 'Jane' }] }); - }); - - it('does not throw if field is missing', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: 'John', last: 'Doe' }] }, - }; - keepInArray('users', ['last', 'xx'])(hook); - assert.deepEqual(hook.data, { users: [{ last: 'Doe' }] }); - }); - - it('keeps undefined values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: undefined, last: 'Doe' }] }, - }; - keepInArray('users', ['first'])(hook); - assert.deepEqual(hook.data, { users: [{ first: undefined }] }); - }); - - it('keeps null values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: null, last: 'Doe' }] }, - }; - keepInArray('users', ['first'])(hook); - assert.deepEqual(hook.data, { users: [{ first: null }] }); - }); - - it('keeps false values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: false, last: 'Doe' }] }, - }; - keepInArray('users', ['first'])(hook); - assert.deepEqual(hook.data, { users: [{ first: false }] }); - }); - - it('keeps 0 values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: 0, last: 'Doe' }] }, - }; - keepInArray('users', ['first'])(hook); - assert.deepEqual(hook.data, { users: [{ first: 0 }] }); - }); - - it('keeps empty string values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { users: [{ first: '', last: 'Doe' }] }, - }; - keepInArray('users', ['first'])(hook); - assert.deepEqual(hook.data, { users: [{ first: '' }] }); - }); - }); - - describe('handles dot notation', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { - users: [{ empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }], - }, - }; - hookFindNested = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: [ - { account: { users: [{ first: 'John', last: 'Doe' }] } }, - { account: { users: [{ first: 'Jane', last: 'Doe' }] } }, - ], - }; - }); - - it('updates hook after::find with dot notation field ', () => { - keepInArray('account.users', ['first'])(hookFindNested); - assert.deepEqual(hookFindNested.result, [ - { account: { users: [{ first: 'John' }] } }, - { account: { users: [{ first: 'Jane' }] } }, - ]); - }); - - it('prop with no dots', () => { - keepInArray('users', ['empl'])(hookBefore); - assert.deepEqual(hookBefore.data, { - users: [{ empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }], - }); - }); - - it('prop with 1 dot', () => { - keepInArray('users', ['empl.name', 'dept'])(hookBefore); - assert.deepEqual(hookBefore.data, { - users: [{ empl: { name: { first: 'John', last: 'Doe' } }, dept: 'Acct' }], - }); - }); - - it('prop with 2 dots', () => { - keepInArray('users', ['empl.name.last', 'empl.status', 'dept'])(hookBefore); - assert.deepEqual(hookBefore.data, { - users: [{ empl: { name: { last: 'Doe' }, status: 'AA' }, dept: 'Acct' }], - }); - }); - - it('ignores bad or missing paths', () => { - keepInArray('users', ['empl.name.first', 'empl.name.surname'])(hookBefore); - assert.deepEqual(hookBefore.data, { users: [{ empl: { name: { first: 'John' } } }] }); - }); - - it('ignores bad or missing no dot path', () => { - keepInArray('users', ['xx'])(hookBefore); - assert.deepEqual(hookBefore.data, { users: [{}] }); - }); - }); - - describe('ignore non-object records', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: [ - { - users: [ - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - null, - undefined, - Infinity, - ], - }, - null, - undefined, - Infinity, - ], - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: [ - { users: [{ first: 'Jane', last: 'Doe' }, null, undefined, Infinity] }, - null, - undefined, - Infinity, - ], - }; - }); - - it('before', () => { - keepInArray('users', ['empl'])(hookBefore); - assert.deepEqual(hookBefore.data, [ - { - users: [ - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }, - null, - undefined, - Infinity, - ], - }, - null, - undefined, - Infinity, - ]); - }); - - it('after', () => { - keepInArray('users', ['first'])(hookAfter); - assert.deepEqual(hookAfter.result, [ - { users: [{ first: 'Jane' }, null, undefined, Infinity] }, - null, - undefined, - Infinity, - ]); - }); - }); -}); diff --git a/test/hooks/keep-query-in-array.test.ts b/test/hooks/keep-query-in-array.test.ts deleted file mode 100755 index 58c12bf5..00000000 --- a/test/hooks/keep-query-in-array.test.ts +++ /dev/null @@ -1,179 +0,0 @@ -import { assert } from 'vitest'; -import { keepQueryInArray } from '../../src'; - -let hookBefore: any; -let hookFindNested: any; - -describe('services keepQueryInArray', () => { - describe('removes fields', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: 'John', last: 'Doe' }] }, - }; - }); - - it('updates hook before::find', () => { - keepQueryInArray('users', ['last'])(hookBefore); - assert.deepEqual(hookBefore.query, { users: [{ last: 'Doe' }] }); - }); - - it('ignores bad or missing field', () => { - keepQueryInArray('xx', ['last'])(hookBefore); - assert.deepEqual(hookBefore.query, { users: [{ first: 'John', last: 'Doe' }] }); - }); - - it('does not throw if field is missing', () => { - const hook: any = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: 'John', last: 'Doe' }] }, - }; - keepQueryInArray('users', ['last', 'xx'])(hook); - assert.deepEqual(hook.query, { users: [{ last: 'Doe' }] }); - }); - - it('keeps undefined values', () => { - const hook: any = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: undefined, last: 'Doe' }] }, - }; - keepQueryInArray('users', ['first'])(hook); - assert.deepEqual(hook.query, { users: [{ first: undefined }] }); - }); - - it('keeps null values', () => { - const hook: any = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: null, last: 'Doe' }] }, - }; - keepQueryInArray('users', ['first'])(hook); - assert.deepEqual(hook.query, { users: [{ first: null }] }); - }); - - it('keeps false values', () => { - const hook: any = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: false, last: 'Doe' }] }, - }; - keepQueryInArray('users', ['first'])(hook); - assert.deepEqual(hook.query, { users: [{ first: false }] }); - }); - - it('keeps 0 values', () => { - const hook: any = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: 0, last: 'Doe' }] }, - }; - keepQueryInArray('users', ['first'])(hook); - assert.deepEqual(hook.query, { users: [{ first: 0 }] }); - }); - - it('keeps empty string values', () => { - const hook: any = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { users: [{ first: '', last: 'Doe' }] }, - }; - keepQueryInArray('users', ['first'])(hook); - assert.deepEqual(hook.query, { users: [{ first: '' }] }); - }); - }); - - describe('handles dot notation', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { - users: [{ empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }], - }, - }; - hookFindNested = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { account: { users: [{ first: 'John', last: 'Doe' }] } }, - }; - }); - - it('updates hook find with dot notation field ', () => { - keepQueryInArray('account.users', ['first'])(hookFindNested); - assert.deepEqual(hookFindNested.query, { account: { users: [{ first: 'John' }] } }); - }); - - it('prop with no dots', () => { - keepQueryInArray('users', ['empl'])(hookBefore); - assert.deepEqual(hookBefore.query, { - users: [{ empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }], - }); - }); - - it('prop with 1 dot', () => { - keepQueryInArray('users', ['empl.name', 'dept'])(hookBefore); - assert.deepEqual(hookBefore.query, { - users: [{ empl: { name: { first: 'John', last: 'Doe' } }, dept: 'Acct' }], - }); - }); - - it('prop with 2 dots', () => { - keepQueryInArray('users', ['empl.name.last', 'empl.status', 'dept'])(hookBefore); - assert.deepEqual(hookBefore.query, { - users: [{ empl: { name: { last: 'Doe' }, status: 'AA' }, dept: 'Acct' }], - }); - }); - - it('ignores bad or missing paths', () => { - keepQueryInArray('users', ['empl.name.first', 'empl.name.surname'])(hookBefore); - assert.deepEqual(hookBefore.query, { users: [{ empl: { name: { first: 'John' } } }] }); - }); - - it('ignores bad or missing no dot path', () => { - keepQueryInArray('users', ['xx'])(hookBefore); - assert.deepEqual(hookBefore.query, { users: [{}] }); - }); - }); - - describe('removes non-object records', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'find', - params: { provider: 'rest' }, - query: { - users: [ - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - null, - undefined, - Infinity, - ], - }, - }; - }); - - it('before', () => { - keepQueryInArray('users', ['empl'])(hookBefore); - assert.deepEqual(hookBefore.query, { - users: [ - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }, - null, - undefined, - Infinity, - ], - }); - }); - }); -}); diff --git a/test/hooks/keep.test.ts b/test/hooks/keep.test.ts deleted file mode 100755 index e132873d..00000000 --- a/test/hooks/keep.test.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { assert } from 'vitest'; -import { keep } from '../../src'; - -let hookBefore: any; -let hookAfter: any; -let hookFindPaginate: any; -let hookFind: any; - -describe('services keep', () => { - describe('removes fields', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { first: 'Jane', last: 'Doe' }, - }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - }); - - it('updates hook before::create', () => { - keep('last')(hookBefore); - assert.deepEqual(hookBefore.data, { last: 'Doe' }); - }); - - it('updates hook after::find with pagination', () => { - keep('first')(hookFindPaginate); - assert.deepEqual(hookFindPaginate.result.data, [{ first: 'John' }, { first: 'Jane' }]); - }); - - it('updates hook after::find with no pagination', () => { - keep('first')(hookFind); - assert.deepEqual(hookFind.result, [{ first: 'John' }, { first: 'Jane' }]); - }); - - it('updates hook after', () => { - keep('first')(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'Jane' }); - }); - - it('updates when called internally on server', () => { - hookAfter.params.provider = ''; - keep('first')(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'Jane' }); - }); - - it('does not throw if field is missing', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - keep('last', 'xx')(hook); - assert.deepEqual(hook.data, { last: 'Doe' }); - }); - - it('keeps undefined values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: undefined, last: 'Doe' }, - }; - keep('first')(hook); - assert.deepEqual(hook.data, { first: undefined }); - }); - - it('keeps null values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: null, last: 'Doe' }, - }; - keep('first')(hook); - assert.deepEqual(hook.data, { first: null }); - }); - - it('keeps false values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: false, last: 'Doe' }, - }; - keep('first')(hook); - assert.deepEqual(hook.data, { first: false }); - }); - - it('keeps 0 values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 0, last: 'Doe' }, - }; - keep('first')(hook); - assert.deepEqual(hook.data, { first: 0 }); - }); - - it('keeps empty string values', () => { - const hook: any = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: '', last: 'Doe' }, - }; - keep('first')(hook); - assert.deepEqual(hook.data, { first: '' }); - }); - }); - - describe('handles dot notation', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }; - }); - - it('prop with no dots', () => { - keep('empl')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - }); - }); - - it('prop with 1 dot', () => { - keep('empl.name', 'dept')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' } }, - dept: 'Acct', - }); - }); - - it('prop with 2 dots', () => { - keep('empl.name.last', 'empl.status', 'dept')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('ignores bad or missing paths', () => { - keep('empl.name.first', 'empl.name.surname')(hookBefore); - assert.deepEqual(hookBefore.data, { empl: { name: { first: 'John' } } }); - }); - - it('ignores bad or missing no dot path', () => { - keep('xx')(hookBefore); - assert.deepEqual(hookBefore.data, {}); - }); - }); - - describe('ignore non-object records', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: [ - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - null, - undefined, - Infinity, - ], - }; - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: [{ first: 'Jane', last: 'Doe' }, null, undefined, Infinity], - }; - }); - - it('before', () => { - keep('empl')(hookBefore); - assert.deepEqual(hookBefore.data, [ - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' } }, - null, - undefined, - Infinity, - ]); - }); - - it('after', () => { - keep('first')(hookAfter); - assert.deepEqual(hookAfter.result, [{ first: 'Jane' }, null, undefined, Infinity]); - }); - }); -}); diff --git a/test/hooks/lowercase.test.ts b/test/hooks/lowercase.test.ts deleted file mode 100755 index c2f72bdc..00000000 --- a/test/hooks/lowercase.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { assert } from 'vitest'; -import { lowerCase } from '../../src'; - -let hookBefore: any; -let hookAfter: any; -let hookFindPaginate: any; -let hookFind: any; - -describe('services lowercase', () => { - describe('updates data', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } }; - hookFindPaginate = { - type: 'after', - method: 'find', - result: { - total: 2, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - }); - - it('updates hook before::create', () => { - lowerCase('first', 'last')(hookBefore); - assert.deepEqual(hookBefore.data, { first: 'john', last: 'doe' }); - }); - - it('updates hook after::find with pagination', () => { - lowerCase('first', 'last')(hookFindPaginate); - assert.deepEqual(hookFindPaginate.result.data, [ - { first: 'john', last: 'doe' }, - { first: 'jane', last: 'doe' }, - ]); - }); - - it('updates hook after::find with no pagination', () => { - lowerCase('first', 'last')(hookFind); - assert.deepEqual(hookFind.result, [ - { first: 'john', last: 'doe' }, - { first: 'jane', last: 'doe' }, - ]); - }); - - it('updates hook after', () => { - lowerCase('first', 'last')(hookAfter); - assert.deepEqual(hookAfter.result, { first: 'jane', last: 'doe' }); - }); - - it('does not throw if field is missing', () => { - const hook: any = { type: 'before', method: 'create', data: { last: 'Doe' } }; - lowerCase('first', 'last')(hook); - assert.deepEqual(hook.data, { last: 'doe' }); - }); - - it('does not throw if field is undefined', () => { - const hook: any = { - type: 'before', - method: 'create', - data: { first: undefined, last: 'Doe' }, - }; - lowerCase('first', 'last')(hook); - assert.deepEqual(hook.data, { first: undefined, last: 'doe' }); - }); - - it('does not throw if field is null', () => { - const hook: any = { type: 'before', method: 'create', data: { first: null, last: 'Doe' } }; - lowerCase('first', 'last')(hook); - assert.deepEqual(hook.data, { first: null, last: 'doe' }); - }); - - it('throws if field is not a string', () => { - const hook: any = { type: 'before', method: 'create', data: { first: 1, last: 'Doe' } }; - assert.throws(() => { - lowerCase('first', 'last')(hook); - }); - }); - }); - - describe('handles dot notation', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }; - }); - - it('prop with no dots', () => { - lowerCase('dept')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'acct', - }); - }); - - it('prop with 1 dot', () => { - lowerCase('empl.status')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'aa' }, - dept: 'Acct', - }); - }); - - it('prop with 2 dots', () => { - lowerCase('empl.name.first')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'john', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('ignores bad or missing paths', () => { - lowerCase('empl.xx.first')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('ignores bad or missing no dot path', () => { - lowerCase('xx')(hookBefore); - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - }); -}); diff --git a/test/hooks/mongo-keys.test.ts b/test/hooks/mongo-keys.test.ts deleted file mode 100755 index a60f8525..00000000 --- a/test/hooks/mongo-keys.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { assert } from 'vitest'; -import { ObjectId } from 'mongodb'; -import { mongoKeys } from '../../src'; - -const s0 = '000000000000'; -const s1 = '111111111111'; -const s2 = '222222222222'; -const s5 = '555555555555'; -const s8 = '888888888888'; - -describe('services mongoKeys', () => { - it('{ a: s1, c: s0 }', () => { - const newQuery = wrapper(['a'], { a: s1, c: s0 }); - - assert.instanceOf(newQuery.a, ObjectId, '"a" not ObjectID'); - assert.isString(newQuery.c, '"c" not a string'); - }); - - it('{ a: { b: s0 }, c: s0 }', () => { - const newQuery = wrapper(['a'], { a: { b: s0 }, c: s0 }); - - assert.isString(newQuery.a.b, '"a.b" not a string'); - assert.isString(newQuery.c, '"c" not a string'); - }); - - it('{ a: { $in: [s1, s2] }, c: s0 }', () => { - const newQuery = wrapper(['a'], { a: { $in: [s1, s2] }, c: s0 }); - - assert.instanceOf(newQuery.a.$in[0], ObjectId, '"a.$in[0]" not ObjectID'); - assert.instanceOf(newQuery.a.$in[1], ObjectId, '"a.$in[1]" not ObjectID'); - assert.isString(newQuery.c, '"c" not a string'); - }); - - it("{ a: s1, b: '111111111111', c: s0 }", () => { - const newQuery = wrapper(['a', 'b'], { a: s1, b: s2, c: s0 }); - - assert.instanceOf(newQuery.a, ObjectId, '"a" not ObjectID'); - assert.instanceOf(newQuery.b, ObjectId, '"b" not ObjectID'); - assert.isString(newQuery.c, '"c" not a string'); - }); - - it('{ a: { x: s8 } }', () => { - const newQuery = wrapper(['a.x'], { a: { x: s8 } }); - - assert.instanceOf(newQuery.a.x, ObjectId, '"a.x" not ObjectID'); - }); - - it('{ $or: [{ a: { x: s8 } }, { b: s5 }, { c: s0 }], d: s0 }', () => { - const newQuery = wrapper(['a.x', 'b'], { - $or: [{ a: { x: s8 } }, { b: s5 }, { c: s0 }], - d: s0, - }); - - assert.instanceOf(newQuery.$or[0].a.x, ObjectId, '"$or[0].a.x" not ObjectID'); - assert.instanceOf(newQuery.$or[1].b, ObjectId, '"$or[1].b" not ObjectID'); - assert.isString(newQuery.$or[2].c, '"$or[2].c" not a string'); - assert.isString(newQuery.d, '"d" not a string'); - }); - - it('{ $or: [{ a: { x: s8 } }, { a: s5 }] } - questionable', () => { - const newQuery = wrapper(['a', 'a.x'], { $or: [{ a: { x: s8 } }, { a: s5 }] }); - - assert.instanceOf(newQuery.$or[0].a.x, ObjectId, '"$or[0].a.x" not ObjectID'); - assert.instanceOf(newQuery.$or[1].a, ObjectId, '"$or[1].a" not ObjectID'); - }); -}); - -function wrapper(keys: any, query: any) { - const newContext: any = mongoKeys( - ObjectId, - keys, - )({ params: { query }, type: 'before', method: 'find' } as any); - return newContext.params.query; -} diff --git a/test/hooks/params-from-client.test.ts b/test/hooks/params-from-client.test.ts deleted file mode 100755 index 40be1c3a..00000000 --- a/test/hooks/params-from-client.test.ts +++ /dev/null @@ -1,187 +0,0 @@ -import { assert } from 'vitest'; -import { paramsFromClient } from '../../src'; - -describe('services params-from-client', () => { - describe('basics', () => { - it('works no params', () => { - const hook: any = {}; - const hook1 = paramsFromClient('populate', 'serialize')(hook); - - assert.deepEqual(hook1, {} as any); - }); - - it('works no query', () => { - const hook: any = { params: {} }; - const hook1 = paramsFromClient('populate', 'serialize')(hook); - - assert.deepEqual(hook1, { params: {} } as any); - }); - - it('works no $client', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - }, - }, - }; - const hook1 = paramsFromClient('populate', 'serialize')(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - }, - }, - } as any); - }); - - it('leaves hook unchanged if $client not an object', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - $client: 'z', - }, - }, - }; - - const hook1 = paramsFromClient('populate', 'serialize')(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - $client: 'z', - }, - }, - } as any); - }); - }); - - describe('copies client params', () => { - it('works no whitelisted params', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - $client: { populate: 'aa', serialize: 'bb' }, - }, - }, - }; - - const hook1 = paramsFromClient()(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - }, - }, - } as any); - }); - - it('copies whitelisted params', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - $client: { populate: 'aa', serialize: 'bb' }, - }, - }, - }; - - const hook1 = paramsFromClient('populate', 'serialize')(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - }, - populate: 'aa', - serialize: 'bb', - }, - } as any); - }); - - it('copies whitelisted params even if some missing', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - $client: { populate: 'aa', serialize: 'bb' }, - }, - }, - }; - - const hook1 = paramsFromClient('a', 'populate', 'b', 'serialize', 'q', 'r')(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - }, - populate: 'aa', - serialize: 'bb', - }, - } as any); - }); - - it('copies only whitelisted params', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - $client: { populate: 'aa', serialize: 'bb' }, - }, - }, - }; - - const hook1 = paramsFromClient('populate')(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - }, - populate: 'aa', - }, - } as any); - }); - - it('copies only whitelisted params even if none', () => { - const hook: any = { - params: { - query: { - div: 'a', - dept: 'b', - $client: { populate: 'aa', serialize: 'bb' }, - }, - }, - }; - - const hook1 = paramsFromClient('q', 'q')(hook); - - assert.deepEqual(hook1, { - params: { - query: { - div: 'a', - dept: 'b', - }, - }, - } as any); - }); - }); -}); diff --git a/test/hooks/populate-1deep-1child.test.ts b/test/hooks/populate-1deep-1child.test.ts deleted file mode 100755 index 7436bc2a..00000000 --- a/test/hooks/populate-1deep-1child.test.ts +++ /dev/null @@ -1,668 +0,0 @@ -import { assert } from 'vitest'; -import _set from 'lodash/set.js'; - -import configApp from '../helpers/config-app'; -import getInitDb from '../helpers/get-init-db'; -import { populate } from '../../src'; - -let provider: any; - -['array', 'obj'].forEach(type => { - describe(`services populate - include 1:1 - ${type}`, () => { - let hookAfter: any; - let hookAfterArray: any; - - let app: any; - let recommendation; - - beforeEach(() => { - app = configApp(['posts', 'recommendation']); - recommendation = clone(getInitDb('recommendation').store); - - app.service('posts').hooks({ - before: { - all: [ - (hook: any) => { - provider = hook.params.provider; - }, - ], - }, - }); - - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - path: 'recommendations', - result: recommendation['1'], - }; - hookAfterArray = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - path: 'recommendations', - result: [recommendation['1'], recommendation['2'], recommendation['3']], - }; - }); - - describe('root is one item', () => { - it('saves in nameAs without dot notation', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', // we have no test for dot notation 'cause no such data - childField: 'id', - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('post'); - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('saves in nameAs using dot notation', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post.items', - parentField: 'postId', // we have no test for dot notation 'cause no such data - childField: 'id', - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('post.items'); - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('saves in service as default', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('ignores undefined parentField', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - delete hook.result.postId; - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - - delete expected.postId; - delete expected.posts; - expected._include = []; - - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('uses asArray', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - asArray: true, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts', true); - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('Stores null when no joined records and !asArray', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - hook.result.postId = '999'; - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - - expected.postId = '999'; - expected.posts = null; - - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('Stores [] when no joined records and asArray', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - hook.result.postId = '999'; - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - asArray: true, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - - expected.postId = '999'; - expected.posts = []; - - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('query overridden by childField', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - query: { id: 'aaaaaa' }, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('Provider in joins defaults to method call', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - query: { id: 'aaaaaa' }, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - assert.equal(provider, 'rest'); // Feathers default if not from WebSocket - }) - ); - }); - - it('Provider in joins can be overridden', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - query: { id: 'aaaaaa' }, - provider: undefined, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - assert.equal(provider, undefined); - }) - ); - }); - - it('Provider can be passed down from top level', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - provider: 'global', - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - query: { id: 'aaaaaa' }, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - assert.equal(provider, 'global'); - }) - ); - }); - - it('Global provider can be overwritten at schema level', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - provider: 'global', - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - query: { id: 'aaaaaa' }, - provider: 'socketio', - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - assert.equal(provider, 'socketio'); - }) - ); - }); - - it('Falsy providers override default provider', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - hook.params.provider = 'rest'; // Set up default provider - - const schema: any = { - provider: undefined, - include: makeInclude(type, { - service: 'posts', - parentField: 'postId', - childField: 'id', - query: { id: 'aaaaaa' }, - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - assert.equal(provider, undefined); - }) - ); - }); - - it('childField overridden by select', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - parentField: 'updatedAt', - childField: 'id', - select: (_hook: any, parent: any) => ({ - id: parent.postId, - }), - }), - }; - - return ( - populate({ schema })(hook) - // @ts-ignore - .then((hook1: any) => { - const expected = recommendationPosts('posts'); - assert.deepEqual(hook1.result, expected); - }) - ); - }); - - it('checks permissions', () => { - const spy: any = []; - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const checkPermissions = (_hook: any, service: any, permissions: any, depth: any) => { - spy.push({ service, permissions, depth }); - return true; - }; - - const schema = { - permissions: 'for root', - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - permissions: 'for posts', - }), - }; - - // @ts-ignore - return ( - populate({ schema, checkPermissions })(hook) - // @ts-ignore - .then((hook1: any) => { - let expected = recommendationPosts('post'); - assert.deepEqual(hook1.result, expected); - - expected = [ - { service: 'recommendations', permissions: 'for root', depth: 0 }, - { service: 'posts', permissions: 'for posts', depth: 1 }, - ]; - assert.deepEqual(spy, expected); - }) - ); - }); - - it('throws on invalid permissions', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const checkPermissions = (_hook: any, _service: any, _permissions: any, depth: any) => { - return depth === 0; - }; - - const schema = { - permissions: 'for root', - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - permissions: 'for posts', - }), - }; - - // @ts-ignore - return ( - populate({ schema, checkPermissions })(hook) - // @ts-ignore - .then(() => { - throw new Error('was not supposed to succeed'); - }) - .catch((err: any) => { - assert.notEqual(err, undefined); - }) - ); - }); - - it('stores elapsed time', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - }), - }; - - return ( - populate({ schema, profile: true })(hook) - // @ts-ignore - .then((hook1: any) => { - const elapsed = hook1.result._elapsed; - assert.deepEqual(Object.keys(elapsed), ['post', 'total']); - assert.isAbove(elapsed.total, 999); - assert.isAtLeast(elapsed.total, elapsed.post); - }) - ); - }); - - it('allow non related field joins if query', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - query: { id: hookAfter.result.postId }, - }), - }; - - return ( - populate({ schema, profile: true })(hook) - // @ts-ignore - .then((hook1: any) => { - const elapsed = hook1.result._elapsed; - assert.deepEqual(Object.keys(elapsed), ['post', 'total']); - assert.isAbove(elapsed.total, 999); - assert.isAtLeast(elapsed.total, elapsed.post); - }) - ); - }); - - it('allow non related field joins if select', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - select: (_hook: any, parentItem: any) => ({ - id: parentItem.postId, - }), - }), - }; - - return ( - populate({ schema, profile: true })(hook) - // @ts-ignore - .then((hook1: any) => { - const elapsed = hook1.result._elapsed; - assert.deepEqual(Object.keys(elapsed), ['post', 'total']); - assert.isAbove(elapsed.total, 999); - assert.isAtLeast(elapsed.total, elapsed.post); - }) - ); - }); - - it('throws if no parentField option in related field join', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - childField: 'id', - }), - }; - - return ( - populate({ schema, profile: true })(hook) - // @ts-ignore - .then(() => { - assert.fail('unexpectedly succeeeded'); - }) - .catch((err: any) => { - assert.isObject(err, 'no error object'); - }) - ); - }); - - it('throws if no parentField defined in related field join', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - delete hook.result.postId; - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - }), - }; - - return ( - populate({ schema, profile: true })(hook) - // @ts-ignore - .then(() => { - assert.fail('unexpectedly succeeded'); - }) - .catch((err: any) => { - assert.isObject(err, 'no error object'); - }) - ); - }); - }); - - describe('root is item array', () => { - it('populates each item', () => { - const hook = clone(hookAfterArray); - hook.app = app; // app is a func and wouldn't be cloned - - const schema = { - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - }), - }; - - return ( - populate({ schema, profile: true })(hook) - // @ts-ignore - .then((hook1: any) => { - assert.equal(hook1.result.length, 3); - }) - ); - }); - }); - - describe('populate does not change original schema object', () => { - it('check include field', () => { - const hook = clone(hookAfterArray); - hook.app = app; - - const includeOptions = () => ({ - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - }); - - const include = makeInclude(type, includeOptions()); - const expected = makeInclude(type, includeOptions()); - - return ( - populate({ schema: { include }, profile: true })(hook) - // @ts-ignore - .then((hook1: any) => { - assert.deepEqual(include, expected); - }) - ); - }); - }); - }); -}); - -// Helpers - -function makeInclude(type: any, obj: any) { - return type === 'obj' ? obj : [obj]; -} - -function recommendationPosts(nameAs: any, asArray?: any, recommendation?: any, posts?: any) { - recommendation = recommendation || clone(getInitDb('recommendation').store['1']); - posts = posts || clone(getInitDb('posts').store['1']); - - const expected = clone(recommendation); - expected._include = [nameAs]; - - // expected[nameAs] = asArray ? [clone(posts)] : clone(posts); - _set(expected, nameAs, asArray ? [clone(posts)] : clone(posts)); - - return expected; -} - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/populate-basics.test.ts b/test/hooks/populate-basics.test.ts deleted file mode 100755 index 2245402a..00000000 --- a/test/hooks/populate-basics.test.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { assert } from 'vitest'; -import { populate } from '../../src'; - -describe('services populate - finds items in hook', () => { - let hookAfter: any; - let hookAfterArray: any; - let hookFindPaginate: any; - - beforeEach(() => { - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { first: 'Jane2', last: 'Doe2' }, - }; - hookAfterArray = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: [ - { first: 'John2', last: 'Doe2' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - hookFindPaginate = { - type: 'after', - method: 'find', - params: { provider: 'rest' }, - result: { - total: 2, - data: [ - { first: 'John3', last: 'Doe3' }, - { first: 'Jane3', last: 'Doe3' }, - ], - }, - }; - }); - - it('one item', () => { - const hook = clone(hookAfter); - return ( - populate({ schema: {} })(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - }) - ); - }); - - it('item array', () => { - const hook = clone(hookAfterArray); - return ( - populate({ schema: {} })(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfterArray); - }) - ); - }); - - it('find paginated', () => { - const hook = clone(hookFindPaginate); - return ( - populate({ schema: {} })(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookFindPaginate); - }) - ); - }); -}); - -describe('services populate - throws on bad params', () => { - // run to increase code climate score - let hookAfter: any; - - beforeEach(() => { - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - result: { first: 'Jane2', last: 'Doe2' }, - }; - }); - - it('schema', () => { - assert.throws(() => { - // @ts-ignore - populate({}); - }); - assert.throws(() => { - // @ts-ignore - populate({ schema: 1 }); - }); - }); - - it('permissions not func', () => { - const hook = clone(hookAfter); - // @ts-ignore - return ( - // @ts-ignore - populate({ schema: {}, checkPermissions: 1 })(hook) - // @ts-ignore - .then(() => { - throw new Error('was not supposed to succeed'); - }) - .catch((err: any) => { - assert.notEqual(err, undefined); - }) - ); - }); - - it('throws on invalid permissions', () => { - const hook = clone(hookAfter); - // @ts-ignore - return ( - populate({ schema: {}, checkPermissions: () => false })(hook) - // @ts-ignore - .then(() => { - throw new Error('was not supposed to succeed'); - }) - .catch((err: any) => { - assert.notEqual(err, undefined); - }) - ); - }); -}); - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/populate-misc.test.ts b/test/hooks/populate-misc.test.ts deleted file mode 100755 index de6bbf42..00000000 --- a/test/hooks/populate-misc.test.ts +++ /dev/null @@ -1,301 +0,0 @@ -import { assert } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { iff, populate } from '../../src'; - -const userId = 6; -const userInit = { - 0: { name: 'Jane Doe', key: 'a', id: 0 }, - 1: { name: 'Jack Doe', key: 'a', id: 1 }, - 2: { name: 'Jack Doe', key: 'a', id: 2, deleted: true }, - 3: { name: 'Rick Doe', key: 'b', id: 3 }, - 4: { name: 'Dick Doe', key: 'b', id: 4 }, - 5: { name: 'Dick Doe', key: 'b', id: 5, deleted: true }, -}; -const teamId = 2; -const teamInit = { - 0: { team: 'Does', memberIds: [0, 1, 2], id: 0 }, - 1: { team: 'Dragons', memberIds: [3, 4, 5], id: 1 }, -}; - -const schemaDefault = { - include: [ - { - service: 'users', - nameAs: 'members', - parentField: 'memberIds', - childField: 'id', - }, - ], -}; - -const resultDefault = [ - { - team: 'Does', - memberIds: [0, 1, 2], - id: 0, - _include: ['members'], - members: [ - { name: 'Jane Doe', key: 'a', id: 0 }, - { name: 'Jack Doe', key: 'a', id: 1 }, - { name: 'Jack Doe', key: 'a', id: 2, deleted: true }, - ], - }, -]; - -const schemaDefaultTeams = { - service: 'teams', - include: [ - { - service: 'users', - nameAs: 'members', - parentField: 'memberIds', - childField: 'id', - }, - ], -}; - -const schemaDefaultXteams = { - service: 'xteams', - include: [ - { - service: 'users', - nameAs: 'members', - parentField: 'memberIds', - childField: 'id', - }, - ], -}; - -const schemaFalse = { - include: [ - { - service: 'users', - nameAs: 'members', - parentField: 'memberIds', - childField: 'id', - paginate: false, - }, - ], -}; - -const schemaTrue = { - include: [ - { - service: 'users', - nameAs: 'members', - parentField: 'memberIds', - childField: 'id', - paginate: true, - }, - ], -}; - -const resultTrue = [ - { - team: 'Does', - memberIds: [0, 1, 2], - id: 0, - _include: ['members'], - members: [ - { name: 'Jane Doe', key: 'a', id: 0 }, - { name: 'Jack Doe', key: 'a', id: 1 }, - ], - }, -]; - -const schema1 = { - include: [ - { - service: 'users', - nameAs: 'members', - parentField: 'memberIds', - childField: 'id', - paginate: 1, - }, - ], -}; - -const result1 = [ - { - team: 'Does', - memberIds: [0, 1, 2], - id: 0, - _include: ['members'], - members: { name: 'Jane Doe', key: 'a', id: 0 }, - }, -]; - -let whichSchema: any; -let userHookFlag1: any; -let teamHookFlag1: any; -let fcnOptions: any; - -function schemaFcn(_hook: any, options: any) { - fcnOptions = options; - return schemaDefault; -} - -function services(this: any) { - const app = this; - app.configure(user); - app.configure(team); -} - -function user(this: any) { - const app = this; - - app.use( - '/users', - new MemoryService({ - store: clone(userInit), - startId: userId, - paginate: { - default: 2, - max: 2, - }, - }), - ); - - app.service('users').hooks({ - before: { - all: [ - (hook: any) => { - userHookFlag1 = hook.params.userHookFlag1; - }, - ], - }, - }); -} - -function team(this: any) { - const app = this; - - app.use( - '/teams', - new MemoryService({ - store: clone(teamInit), - startId: teamId, - }), - ); - - app.service('teams').hooks({ - after: { - all: [ - (hook: any) => { - teamHookFlag1 = hook.params.teamHookFlag1; - }, - iff(() => whichSchema === 'schemaDefault', populate({ schema: schemaDefault })), - iff(() => whichSchema === 'schemaFalse', populate({ schema: schemaFalse })), - iff(() => whichSchema === 'schemaTrue', populate({ schema: schemaTrue })), - iff(() => whichSchema === 'schema1', populate({ schema: schema1 })), - iff(() => whichSchema === 'schemaDefaultTeams', populate({ schema: schemaDefaultTeams })), - iff(() => whichSchema === 'schemaDefaultXteams', populate({ schema: schemaDefaultXteams })), - iff(() => whichSchema === 'schemaDefaultFcn', populate({ schema: schemaFcn })), - ], - }, - }); -} - -describe('services populate - hook.params passed to includes', () => { - let app; - let teams: any; - - beforeEach(() => { - app = feathers().configure(services); - teams = app.service('teams'); - userHookFlag1 = null; - }); - - it('hook.params passed to includes', () => { - whichSchema = 'schemaDefault'; - return teams.find({ query: { id: 0 }, userHookFlag1: 'userHookFlag1' }).then((result: any) => { - assert.equal(userHookFlag1, 'userHookFlag1'); - assert.deepEqual(result, resultDefault); - }); - }); - - it('ignores pagination by default', () => { - whichSchema = 'schemaDefault'; - return teams.find({ query: { id: 0 } }).then((result: any) => { - assert.deepEqual(result, resultDefault); - }); - }); - - it('ignores pagination when paginate:false', () => { - whichSchema = 'schemaFalse'; - return teams.find({ query: { id: 0 } }).then((result: any) => { - assert.deepEqual(result, resultDefault); - }); - }); - - it('uses configuration when paginate:true', () => { - whichSchema = 'schemaTrue'; - return teams.find({ query: { id: 0 } }).then((result: any) => { - assert.deepEqual(result, resultTrue); - }); - }); - - it('can specify number of results to return', () => { - whichSchema = 'schema1'; - return teams.find({ query: { id: 0 } }).then((result: any) => { - assert.deepEqual(result, result1); - }); - }); - - it('passes on correct base service', () => { - whichSchema = 'schemaDefaultTeams'; - return teams.find({ query: { id: 0 } }).then((result: any) => { - assert.deepEqual(result, resultDefault); - }); - }); - - it('throws on incorrect base service', () => { - whichSchema = 'schemaDefaultXteams'; - return teams - .find({ query: { id: 0 } }) - .then(() => { - assert.fail('unexpected succeeded'); - }) - .catch((err: any) => { - assert.equal(err.className, 'bad-request'); - }); - }); -}); - -describe('services populate - schema may be a function', () => { - let app; - let teams: any; - - beforeEach(() => { - app = feathers().configure(services); - teams = app.service('teams'); - userHookFlag1 = null; - fcnOptions = null; - }); - - it('calls the function', () => { - whichSchema = 'schemaDefaultFcn'; - return teams.find({ query: { id: 0 }, userHookFlag1: 'userHookFlag1' }).then((result: any) => { - assert.equal(userHookFlag1, 'userHookFlag1'); - assert.deepEqual(result, resultDefault); - }); - }); - - it('function gets hook and options', () => { - whichSchema = 'schemaDefaultFcn'; - return teams - .find({ query: { id: 0 }, userHookFlag1: 'userHookFlag1', teamHookFlag1: 'teamHookFlag1' }) - .then((result: any) => { - assert.equal(teamHookFlag1, 'teamHookFlag1'); - assert.strictEqual(fcnOptions.schema, schemaFcn); - - assert.equal(userHookFlag1, 'userHookFlag1'); - assert.deepEqual(result, resultDefault); - }); - }); -}); - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/populate-relations.test.ts b/test/hooks/populate-relations.test.ts deleted file mode 100755 index a90e9a6e..00000000 --- a/test/hooks/populate-relations.test.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { assert } from 'vitest'; -import configApp from '../helpers/config-app'; -import getInitDb from '../helpers/get-init-db'; -import { populate } from '../../src'; - -['array', 'obj'].forEach(type => { - describe(`services populate - 1:1 & 1:m & m:1 - ${type}`, () => { - let hookAfter: any; - let hookAfterArray: any; - let schema: any; - - let app: any; - let recommendation; - - beforeEach(() => { - app = configApp(['recommendation', 'posts', 'users', 'comments']); - recommendation = clone(getInitDb('recommendation').store); - - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - path: 'recommendations', - result: recommendation['1'], - }; - hookAfterArray = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - path: 'recommendations', - result: [recommendation['1'], recommendation['2'], recommendation['3']], - }; - - schema = { - permissions: '', - include: makeInclude(type, { - service: 'posts', - nameAs: 'post', - parentField: 'postId', - childField: 'id', - include: [ - { - // 1:1 - service: 'users', - permissions: '', - nameAs: 'authorInfo', - parentField: 'author', - childField: 'id', - }, - { - // 1:m - service: 'comments', - permissions: '', - nameAs: 'commentsInfo', - parentField: 'id', - childField: 'postId', - select: (_hook: any, _parent: any) => ({ - $limit: 6, - }), - asArray: true, - query: { - $limit: 5, - $select: ['title', 'content', 'postId'], - $sort: { createdAt: -1 }, - }, - }, - { - // m:1 - service: 'users', - permissions: '', - nameAs: 'readersInfo', - parentField: 'readers', - childField: 'id', - }, - ], - }), - }; - }); - - it('for one item', () => { - const hook = clone(hookAfter); - hook.app = app; // app is a func and wouldn't be cloned - - // @ts-ignore - return ( - // @ts-ignore - populate({ schema, checkPermissions: () => true, profile: 'test' })(hook) - // @ts-ignore - .then((hook1: any) => { - assert.deepEqual(hook1.result, { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - commentsInfo: [ - { - id: 1, - title: 'Comment 1', - content: 'Lorem ipsum dolor sit amet 1', - postId: 1, - }, - { - id: 3, - title: 'Comment 3', - content: 'Lorem ipsum dolor sit amet 3', - postId: 1, - }, - ], - readersInfo: [ - { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - }); - }) - ); - }); - - it('for an item array', () => { - const hook = clone(hookAfterArray); - hook.app = app; // app is a func and wouldn't be cloned - - return ( - // @ts-ignore - populate({ schema, checkPermissions: () => true, profile: 'test' })(hook) - // @ts-ignore - .then((hook1: any) => { - assert.deepEqual(hook1.result, [ - { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - commentsInfo: [ - { - id: 1, - title: 'Comment 1', - content: 'Lorem ipsum dolor sit amet 1', - postId: 1, - }, - { - id: 3, - title: 'Comment 3', - content: 'Lorem ipsum dolor sit amet 3', - postId: 1, - }, - ], - readersInfo: [ - { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - }, - { - userId: 'as61389dadhga62343hads6712', - postId: 2, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - id: 2, - title: 'Post 2', - content: 'Lorem ipsum dolor sit amet 5', - author: '167asdf3689348sdad7312131s', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - commentsInfo: [ - { - id: 2, - title: 'Comment 2', - content: 'Lorem ipsum dolor sit amet 2', - postId: 2, - }, - ], - readersInfo: [ - { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - }, - { - userId: '167asdf3689348sdad7312131s', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - commentsInfo: [ - { - id: 1, - title: 'Comment 1', - content: 'Lorem ipsum dolor sit amet 1', - postId: 1, - }, - { - id: 3, - title: 'Comment 3', - content: 'Lorem ipsum dolor sit amet 3', - postId: 1, - }, - ], - readersInfo: [ - { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - }, - ]); - }) - ); - }); - }); -}); - -// Helpers - -function makeInclude(type: any, obj: any) { - return type === 'obj' ? obj : [obj]; -} - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/populate-scaffolding.test.ts b/test/hooks/populate-scaffolding.test.ts deleted file mode 100755 index 07318e56..00000000 --- a/test/hooks/populate-scaffolding.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { assert } from 'vitest'; -import configApp from '../helpers/config-app'; - -describe('services populate - test scaffolding', () => { - it('can reinitialize database', async () => { - const app = configApp(['users', 'comments', 'posts', 'recommendation']); - const users = app.service('users'); - - await users - .find({ query: {} }) - .then((data: any) => { - assert.equal(data.length, 2); - }) - .then(() => { - return users.remove(0); - }) - .then(() => { - return users.find({ query: {} }); - }) - .then((data: any) => { - assert.equal(data.length, 1); - }) - .then(() => { - const app1 = configApp(['users', 'comments', 'posts', 'recommendation']); - const users1 = app1.service('users'); - - return users1.find({ query: {} }); - }) - .then((data: any) => { - assert.equal(data.length, 2); - }); - }); -}); diff --git a/test/hooks/prevent-changes.test.ts b/test/hooks/prevent-changes.test.ts deleted file mode 100755 index 2b67ebd6..00000000 --- a/test/hooks/prevent-changes.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { assert } from 'vitest'; -import { preventChanges } from '../../src'; - -let hookBefore: any; - -describe('services preventChanges', () => { - describe('allowed for before patch', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'patch', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - }); - - it('does not throw on before patch', () => { - preventChanges(true)(hookBefore); - }); - - ['before', 'after'].forEach(type => { - ['find', 'get', 'create', 'update', 'patch', 'remove'].forEach(method => { - if (type !== 'before' || method !== 'patch') { - it(`throws on ${type} ${method}`, () => { - hookBefore.type = type; - hookBefore.method = method; - assert.throws(() => preventChanges(true)(hookBefore)); - }); - } - }); - }); - }); - - describe('checks props', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'patch', - params: { provider: 'rest' }, - data: { - first: 'John', - last: 'Doe', - 'name.first': 'John', - a: { b: undefined, c: { d: { e: 1 } } }, - }, - }; - }); - - it('does not throw if props not found', () => { - preventChanges(true, 'address')(hookBefore); - preventChanges(true, 'x.y.z')(hookBefore); - }); - - it('throw if props found', () => { - // @ts-expect-error - assert.throw(() => preventChanges('name', 'first')(hookBefore)); - // @ts-expect-error - assert.throw(() => preventChanges('name', 'a')(hookBefore)); - // @ts-expect-error - assert.throw(() => preventChanges('name', 'a.b')(hookBefore)); - // @ts-expect-error - assert.throw(() => preventChanges('name', 'a.c')(hookBefore)); - // @ts-expect-error - assert.throw(() => preventChanges('name', 'a.c.d.e')(hookBefore)); - // @ts-expect-error - assert.throw(() => preventChanges('name.first')(hookBefore)); - }); - }); - - describe('throws if first param is "true"', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'patch', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe', a: { b: undefined, c: { d: { e: 1 } } } }, - }; - }); - - it('does not throw if props not found', () => { - preventChanges(true, 'name', 'address')(hookBefore); - preventChanges(true, 'name.x', 'x.y.z')(hookBefore); - }); - - it('throw if props found', () => { - assert.throw(() => preventChanges(true, 'name', 'first')(hookBefore)); - assert.throw(() => preventChanges(true, 'name', 'a')(hookBefore)); - assert.throw(() => preventChanges(true, 'name', 'a.b')(hookBefore)); - assert.throw(() => preventChanges(true, 'name', 'a.c')(hookBefore)); - assert.throw(() => preventChanges(true, 'name', 'a.c.d.e')(hookBefore)); - }); - }); - - describe('deletes if first param is "false"', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'patch', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe', a: { b: 'john', c: { d: { e: 1 } } } }, - }; - }); - - it('does not delete if props not found', () => { - let context: any = preventChanges(false, 'name', 'address')(clone(hookBefore)); - assert.deepEqual(context, hookBefore); - - context = preventChanges(false, 'name.x', 'x.y.z')(clone(hookBefore)); - assert.deepEqual(context, hookBefore); - }); - - it('deletes if props found', () => { - let context: any = preventChanges(false, 'name', 'first')(clone(hookBefore)); - assert.deepEqual(context.data, { last: 'Doe', a: { b: 'john', c: { d: { e: 1 } } } }, '1'); - - context = preventChanges(false, 'name', 'a')(clone(hookBefore)); - assert.deepEqual(context.data, { first: 'John', last: 'Doe' }, '2'); - - context = preventChanges(false, 'name', 'a.b')(clone(hookBefore)); - assert.deepEqual( - context.data, - { first: 'John', last: 'Doe', a: { c: { d: { e: 1 } } } }, - '3', - ); - - context = preventChanges(false, 'name', 'a.c')(clone(hookBefore)); - assert.deepEqual(context.data, { first: 'John', last: 'Doe', a: { b: 'john' } }, '4'); - - context = preventChanges(false, 'name', 'a.c.d.e')(clone(hookBefore)); - assert.deepEqual( - context.data, - { first: 'John', last: 'Doe', a: { b: 'john', c: { d: {} } } }, - '5', - ); - - context = preventChanges(false, 'first', 'last')(clone(hookBefore)); - assert.deepEqual(context.data, { a: { b: 'john', c: { d: { e: 1 } } } }); - - context = preventChanges(false, 'first', 'a.b', 'a.c.d.e')(clone(hookBefore)); - assert.deepEqual(context.data, { last: 'Doe', a: { c: { d: {} } } }); - }); - }); -}); - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/required.test.ts b/test/hooks/required.test.ts deleted file mode 100755 index 30f7a7c3..00000000 --- a/test/hooks/required.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { assert } from 'vitest'; -import { required } from '../../src'; - -let hookBefore: any; - -describe('services required', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }; - }); - - it('does 1 prop with no dots', () => { - required('empl')(hookBefore); - }); - - it('does multi props with 1 dot', () => { - required('empl.name', 'dept')(hookBefore); - }); - - it('does multi props with 2 dots', () => { - required('empl.name.last', 'empl.status', 'dept')(hookBefore); - }); - - it('throws on bad or missing paths', () => { - assert.throws(() => required('empl.name.first', 'empl.name.surname')(hookBefore)); - }); - - it('ignores bad or missing no dot path', () => { - assert.throws(() => required('xx')(hookBefore)); - }); -}); diff --git a/test/hooks/sequelize-convert.test.ts b/test/hooks/sequelize-convert.test.ts deleted file mode 100755 index 4a0935e3..00000000 --- a/test/hooks/sequelize-convert.test.ts +++ /dev/null @@ -1,428 +0,0 @@ -import { assert } from 'vitest'; -import { sequelizeConvert } from '../../src'; - -const converts: any = { - isInvitation: 'boolean', - isVerified: 'boolean', - verifyExpires: 'date', - verifyChanges: 'json', - resetExpires: 'date', - mfaExpires: 'date', - passwordHistory: 'json', -}; - -const convertDatetime = { - sql: (dateNow: any) => new Date(dateNow).toISOString(), - js: (sqlDate: any) => new Date(sqlDate).valueOf(), -}; - -describe('sequelize-convert.test.ts', function () { - describe('as before hook', () => { - let context: any; - let contextArray: any; - - beforeEach(() => { - context = { - type: 'before', - method: 'create', - data: { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - }; - - contextArray = { - type: 'before', - method: 'create', - data: [ - { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - { - isInvitation: true, - isVerified: false, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - ], - }; - }); - - it('converts single object', () => { - const newContext: any = sequelizeConvert(converts)(context); - - assert.deepEqual(newContext.data, { - isInvitation: 0, - isVerified: 1, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }); - }); - - it('converts array of objects', () => { - const newContext: any = sequelizeConvert(converts)(contextArray); - - assert.deepEqual(newContext.data, [ - { - isInvitation: 0, - isVerified: 1, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - { - isInvitation: 1, - isVerified: 0, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - ]); - }); - - it('uses datetime converter', () => { - const newContext: any = sequelizeConvert(converts, null, { date: convertDatetime })(context); - - assert.deepEqual(newContext.data, { - isInvitation: 0, - isVerified: 1, - verifyExpires: '1970-01-01T00:00:11.111Z', - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: '1970-01-01T00:00:22.222Z', - resetToken: '99999', - resetShortToken: '99', - mfaExpires: '1970-01-01T00:00:33.333Z', - mfaShortToken: '77777', - mfaType: '2fa', - }); - }); - - it('respects fields to ignore', () => { - const newContext: any = sequelizeConvert(converts, [ - 'isInvitation', - 'isVerified', - 'verifyChanges', - ])(context); - - assert.deepEqual(newContext.data, { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }); - }); - }); - - describe('as after hook', () => { - let context: any; - let contextISO: any; - let contextArray: any; - let contextPaginated: any; - - beforeEach(() => { - context = { - type: 'after', - method: 'create', - result: { - isInvitation: 0, - isVerified: 1, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - }; - - contextISO = { - type: 'after', - method: 'create', - result: { - isInvitation: 0, - isVerified: 1, - verifyExpires: '1970-01-01T00:00:11.111Z', - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: '1970-01-01T00:00:22.222Z', - resetToken: '99999', - resetShortToken: '99', - mfaExpires: '1970-01-01T00:00:33.333Z', - mfaShortToken: '77777', - mfaType: '2fa', - }, - }; - - contextArray = { - type: 'after', - method: 'create', - result: [ - { - isInvitation: 0, - isVerified: 1, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - { - isInvitation: 1, - isVerified: 0, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - ], - }; - - contextPaginated = { - type: 'after', - method: 'find', - result: { - data: [ - { - isInvitation: 0, - isVerified: 1, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - { - isInvitation: 1, - isVerified: 0, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - ], - }, - }; - }); - - it('converts single object', () => { - const newContext: any = sequelizeConvert(converts)(context); - - assert.deepEqual(newContext.result, { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }); - }); - - it('uses datetime converter', () => { - const newContext: any = sequelizeConvert(converts, null, { date: convertDatetime })( - contextISO, - ); - - assert.deepEqual(newContext.result, { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }); - }); - - it('converts array of objects, not paginated', () => { - const newContext: any = sequelizeConvert(converts)(contextArray); - - assert.deepEqual(newContext.result, [ - { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - { - isInvitation: true, - isVerified: false, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - ]); - }); - - it('converts array of objects, paginated', () => { - const newContext: any = sequelizeConvert(converts)(contextPaginated); - - assert.deepEqual(newContext.result.data, [ - { - isInvitation: false, - isVerified: true, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - { - isInvitation: true, - isVerified: false, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: { foo: 'bar', baz: 'bas' }, - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }, - ]); - }); - - it('respects fields to ignore', () => { - const newContext: any = sequelizeConvert(converts, [ - 'isInvitation', - 'isVerified', - 'verifyChanges', - ])(context); - - assert.deepEqual(newContext.result, { - isInvitation: 0, - isVerified: 1, - verifyExpires: 11111, - verifyToken: '00000', - verifyShortToken: '00', - verifyChanges: '{"foo":"bar","baz":"bas"}', - resetExpires: 22222, - resetToken: '99999', - resetShortToken: '99', - mfaExpires: 33333, - mfaShortToken: '77777', - mfaType: '2fa', - }); - }); - }); -}); diff --git a/test/hooks/serialize.test.ts b/test/hooks/serialize.test.ts deleted file mode 100755 index f095d3b0..00000000 --- a/test/hooks/serialize.test.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { assert } from 'vitest'; -import { serialize } from '../../src'; - -describe('services serialize', () => { - let hookAfter: any; - let schema: any; - - beforeEach(() => { - hookAfter = { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - path: 'recommendations', - result: {}, - }; - - schema = { - only: ['updatedAt'], - computed: { - commentsCount: (recommendation: any, _hook: any) => recommendation.post.commentsInfo.length, - }, - post: { - exclude: ['id', 'createdAt', 'author', 'readers', '_id'], - authorInfo: { - exclude: ['id', 'password', '_id', 'age'], - computed: { - isUnder18: (authorInfo: any, _hook: any) => authorInfo.age < 18, - }, - }, - readersInfo: { - exclude: 'id', - }, - commentsInfo: { - only: ['title', 'content'], - exclude: 'content', - }, - }, - }; - }); - - it('for one item', () => { - const hook = clone(hookAfter); - hook.result = { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - commentsInfo: [ - { - title: 'Comment 1', - content: 'Lorem ipsum dolor sit amet 1', - postId: 1, - }, - { - title: 'Comment 3', - content: 'Lorem ipsum dolor sit amet 3', - postId: 1, - }, - ], - readersInfo: [ - { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - }; - - const hook1 = serialize(schema)(hook); - - assert.deepEqual(hook1, { - type: 'after', - method: 'create', - params: { provider: 'rest' }, - path: 'recommendations', - result: { - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - name: 'Author 1', - email: 'author1@posties.com', - isUnder18: false, - _computed: ['isUnder18'], - }, - commentsInfo: [{ title: 'Comment 1' }, { title: 'Comment 3' }], - readersInfo: [ - { - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - commentsCount: 2, - _computed: ['commentsCount'], - }, - } as any); - }); - - it('schema param is not changed', () => { - const schema1 = (_hook: any) => { - return {}; - }; - - const hook = clone(hookAfter); - hook.result = { - userId: 'as61389dadhga62343hads6712', - postId: 1, - updatedAt: 1480793101475, - _include: ['post'], - _elapsed: { post: 1, total: 1 }, - post: { - id: 1, - title: 'Post 1', - content: 'Lorem ipsum dolor sit amet 4', - author: 'as61389dadhga62343hads6712', - readers: ['as61389dadhga62343hads6712', '167asdf3689348sdad7312131s'], - createdAt: 1480793101559, - _include: ['authorInfo', 'commentsInfo', 'readersInfo'], - _elapsed: { authorInfo: 2, commentsInfo: 2, readersInfo: 2, total: 2 }, - authorInfo: { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - commentsInfo: [ - { - title: 'Comment 1', - content: 'Lorem ipsum dolor sit amet 1', - postId: 1, - }, - { - title: 'Comment 3', - content: 'Lorem ipsum dolor sit amet 3', - postId: 1, - }, - ], - readersInfo: [ - { - id: 'as61389dadhga62343hads6712', - name: 'Author 1', - email: 'author1@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 55, - }, - { - id: '167asdf3689348sdad7312131s', - name: 'Author 2', - email: 'author2@posties.com', - password: '2347wjkadhad8y7t2eeiudhd98eu2rygr', - age: 16, - }, - ], - }, - }; - - assert.equal(typeof schema1, 'function'); - - for (let i = 1; i < 3; i++) { - serialize(schema1)(hook); - assert.equal(typeof schema1, 'function'); - } - - serialize(schema1)(hook); - assert.equal(typeof schema1, 'function'); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/set-now.test.ts b/test/hooks/set-now.test.ts deleted file mode 100755 index 5e6dbe3b..00000000 --- a/test/hooks/set-now.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { assert } from 'vitest'; -import { setNow } from '../../src'; - -let hookBefore: any; -let hookBefore2: any; -let hookAfter: any; -let hookFindPaginate: any; -let hookFind: any; - -describe('services setNow', () => { - describe('updated fields', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'after', method: 'create', result: { first: 'Jane', last: 'Doe' } }; - hookFindPaginate = { - type: 'after', - method: 'find', - result: { - total: 2, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }, - }; - hookFind = { - type: 'after', - method: 'find', - result: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - ], - }; - }); - - it('updates hook before::create', () => { - setNow('createdAt')(hookBefore); - checkHook(hookBefore.data, { first: 'John', last: 'Doe' }, 'createdAt'); - }); - - it('updates hook after::find with pagination', () => { - setNow('createdAt')(hookFindPaginate); - - checkHook(hookFindPaginate.result.data[0], { first: 'John', last: 'Doe' }, 'createdAt'); - checkHook(hookFindPaginate.result.data[1], { first: 'Jane', last: 'Doe' }, 'createdAt'); - }); - - it('updates hook after::find with no pagination', () => { - setNow('createdAt')(hookFind); - checkHook(hookFind.result[0], { first: 'John', last: 'Doe' }, 'createdAt'); - checkHook(hookFind.result[1], { first: 'Jane', last: 'Doe' }, 'createdAt'); - }); - - it('updates hook after', () => { - setNow('createdAt')(hookAfter); - checkHook(hookAfter.result, { first: 'Jane', last: 'Doe' }, 'createdAt'); - }); - - it('supports field name', () => { - setNow('createdAt2')(hookBefore); - checkHook(hookBefore.data, { first: 'John', last: 'Doe' }, 'createdAt2'); - }); - - it('supports multiple field names', () => { - setNow('createdAt1', 'createdAt2')(hookBefore); - checkHook(hookBefore.data, { first: 'John', last: 'Doe' }, ['createdAt1', 'createdAt2']); - }); - - it('requires field name', () => { - assert.throws(() => { - setNow()(hookBefore); - }); - }); - }); - - describe('handles dot notation', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - data: { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - }; - hookBefore2 = { - type: 'before', - method: 'create', - data: { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - created: { where: 'NYC' }, - }, - }; - }); - - it('prop with no dots', () => { - setNow('madeAt')(hookBefore); - checkHook( - hookBefore.data, - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - 'madeAt', - ); - }); - - it('props with no dots', () => { - setNow('madeAt', 'builtAt')(hookBefore); - checkHook( - hookBefore.data, - { empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, dept: 'Acct' }, - ['madeAt', 'builtAt'], - ); - }); - - it('prop with 1 dot', () => { - setNow('created.at')(hookBefore); - assert.instanceOf(hookBefore.data.created.at, Date, 'not instance of Date'); - assert.equal(Object.keys(hookBefore.data.created).length, 1); - delete hookBefore.data.created; - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - - it('prop with 1 dot in existing obj', () => { - setNow('created.at')(hookBefore2); - assert.instanceOf(hookBefore2.data.created.at, Date, 'not instance of Date'); - assert.equal(Object.keys(hookBefore2.data.created).length, 2); - delete hookBefore2.data.created.at; - assert.deepEqual(hookBefore2.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - created: { where: 'NYC' }, - }); - }); - - it('prop with 2 dots', () => { - setNow('created.at.time')(hookBefore); - assert.instanceOf(hookBefore.data.created.at.time, Date, 'not instance of Date'); - assert.equal(Object.keys(hookBefore.data.created.at).length, 1); - assert.equal(Object.keys(hookBefore.data.created).length, 1); - delete hookBefore.data.created; - assert.deepEqual(hookBefore.data, { - empl: { name: { first: 'John', last: 'Doe' }, status: 'AA' }, - dept: 'Acct', - }); - }); - }); - - describe('time advances', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - }); - - it('for 2 hooks', () => - new Promise(resolve => { - setNow('createdAt')(hookBefore); - const firstTime = hookBefore.data.createdAt; - - setTimeout(() => { - setNow('createdAt')(hookBefore); - assert.isAbove(hookBefore.data.createdAt.getTime(), firstTime.getTime()); - resolve(); - }, 50); - })); - }); -}); - -// Helpers - -function checkHook(item: any, template: any, dateFields: any) { - const item1 = clone(item); - if (typeof dateFields === 'string') { - dateFields = [dateFields]; - } - - dateFields.forEach((dateField: any) => { - assert.instanceOf(item[dateField], Date, 'not instance of Date'); - item1[dateField] = undefined; - delete item1[dateField]; - }); - - assert.deepEqual(item1, template, 'objects differ'); -} - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/set-slug.test.ts b/test/hooks/set-slug.test.ts deleted file mode 100755 index 41b1457c..00000000 --- a/test/hooks/set-slug.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { assert } from 'vitest'; - -import { setSlug } from '../../src'; - -let hook: any; - -describe('services setSlug', () => { - beforeEach(() => { - hook = { type: 'before', method: 'create', params: { provider: 'rest', query: { a: 'a' } } }; - }); - - describe('ignore feathers-socketio & feathers-rest clients', () => { - it('ignore feathers-socketio', () => { - hook.params.provider = 'socketio'; - setSlug('stockId')(hook); - assert.deepEqual(hook.params.query, { a: 'a' }); - }); - - it('ignore feathers-rest', () => { - hook.params.route = {}; - hook.params.route.storeId = ':storeId'; - setSlug('stockId')(hook); - assert.deepEqual(hook.params.query, { a: 'a' }); - }); - }); - - describe('handles raw HTTP clients', () => { - it('copies slug to query', () => { - hook.params.route = {}; - hook.params.route.storeId = '123'; - setSlug('storeId')(hook); - assert.deepEqual(hook.params.query, { a: 'a', storeId: '123' }); - }); - }); - - describe('handles field name', () => { - it('copies slug to query', () => { - hook.params.route = {}; - hook.params.route.storeId = '123'; - setSlug('storeId', 'slugger')(hook); - assert.equal(hook.params.slugger, '123'); - }); - }); - - describe('handles field name with dot notation', () => { - it('copies slug to query', () => { - hook.params.route = {}; - hook.params.route.storeId = '123'; - setSlug('storeId', 'query.slugger')(hook); - assert.deepEqual(hook.params.query, { a: 'a', slugger: '123' }); - }); - }); -}); diff --git a/test/hooks/sifter.test.ts b/test/hooks/sifter.test.ts deleted file mode 100755 index d83abc2a..00000000 --- a/test/hooks/sifter.test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { assert } from 'vitest'; - -import sift from 'sift'; -import { sifter } from '../../src'; - -const dataCanada = [ - { name: 'john', address: { city: 'montreal', country: 'canada' } }, - { name: 'david', address: { city: 'vancouver', country: 'canada' } }, -]; - -const dataUsa = [{ name: 'marshall', address: { city: 'utah', country: 'usa' } }]; - -const data = ([] as any[]).concat(dataCanada, dataUsa); - -const origHook = { type: 'after', method: 'find', result: data }; - -const origHookPaginated = { - type: 'after', - method: 'find', - result: { total: 1, limit: 10, skip: 0, data }, -}; - -const getCountry = (country: any) => (_hook: any) => sift({ 'address.country': country }); - -let hook: any; -let hookPaginated: any; - -describe('services shifter', () => { - beforeEach(() => { - hook = clone(origHook); - hookPaginated = clone(origHookPaginated); - }); - - it('sifts non-paginated data', () => { - const hook1: any = sifter(getCountry('canada'))(hook); - assert.deepEqual(hook1.result, dataCanada); - }); - - it('sifts paginated data', () => { - const hook1: any = sifter(getCountry('canada'))(hookPaginated); - assert.deepEqual(hook1.result.data, dataCanada); - }); - - it('throws if getSifter not a function', () => { - // @ts-expect-error throws if getSifter not a function - assert.throws(() => sifter({})(hookPaginated)); - }); - - it('throws if getSifter does not return a function', () => { - // @ts-expect-error throws if getSifter does not return a function - assert.throws(() => sifter((hook: any) => ({}))(hookPaginated)); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/soft-delete.test.ts b/test/hooks/soft-delete.test.ts deleted file mode 100755 index 12ad0bfa..00000000 --- a/test/hooks/soft-delete.test.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { assert, expect } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { softDelete } from '../../src'; - -const initialUsers = [ - { name: 'Jane Doe', key: 'a' }, - { name: 'Jack Doe', key: 'a' }, - { name: 'Jack Doe', key: 'a', deleted: true }, - { name: 'Rick Doe', key: 'b' }, - { name: 'Mick Doe', key: 'b' }, - { name: 'Mick Doe', key: 'b', deleted: true }, -]; - -describe('services softDelete', () => { - let userService: any; - - beforeEach(() => { - const app = feathers().use( - '/users', - new MemoryService({ - multi: ['create', 'patch', 'remove'], - }), - ); - - userService = app.service('users'); - userService.hooks({ - before: { - all: [softDelete()], - }, - }); - - userService.create(initialUsers); - }); - - describe('find', () => { - it('does not return deleted items', async () => { - const users = await userService.find(); - - assert.deepStrictEqual(users, [ - { name: 'Jane Doe', key: 'a', id: 0 }, - { name: 'Jack Doe', key: 'a', id: 1 }, - { name: 'Rick Doe', key: 'b', id: 3 }, - { name: 'Mick Doe', key: 'b', id: 4 }, - ]); - }); - - it('returns everything with params.disableSoftdelete', async () => { - const users = await userService.find({ - disableSoftDelete: true, - }); - - assert.deepStrictEqual(users, [ - { name: 'Jane Doe', key: 'a', id: 0 }, - { name: 'Jack Doe', key: 'a', id: 1 }, - { name: 'Jack Doe', key: 'a', deleted: true, id: 2 }, - { name: 'Rick Doe', key: 'b', id: 3 }, - { name: 'Mick Doe', key: 'b', id: 4 }, - { name: 'Mick Doe', key: 'b', deleted: true, id: 5 }, - ]); - }); - }); - - describe('get', () => { - it('returns an undeleted item', async () => { - const user = await userService.get(0); - - assert.deepStrictEqual(user, { - name: 'Jane Doe', - key: 'a', - id: 0, - }); - }); - - it('throws on deleted item', async () => { - await expect(async () => { - await userService.get(2); - }).rejects.toThrow(); - }); - - it('returns deleted when params.disableSoftDelete is set', async () => { - const user = await userService.get(2, { - disableSoftDelete: true, - }); - - assert.deepStrictEqual(user, { - name: 'Jack Doe', - key: 'a', - deleted: true, - id: 2, - }); - }); - - it('throws on missing item', async () => { - await expect(async () => { - await userService.get(99); - }).rejects.toThrow(); - }); - }); - - describe('update, with id', () => { - it('updates an undeleted item', async () => { - const user = await userService.update(0, { y: 'y' }); - - assert.deepStrictEqual(user, { y: 'y', id: 0 }); - }); - - it.skip('throws on deleted item', async () => { - await expect(async () => { - await userService.update(2, { y: 'y' }); - }).rejects.toThrow(); - }); - }); - - describe('patch', () => { - it('patches an undeleted item', async () => { - const user = await userService.patch(0, { y: 'y' }); - - assert.deepStrictEqual(user, { - name: 'Jane Doe', - key: 'a', - id: 0, - y: 'y', - }); - }); - - it('throws on deleted item', async () => { - await expect(() => userService.patch(2, { y: 'y' })).rejects.toThrow(); - }); - - it('multi updates on undeleted items', async () => { - const patched = await userService.patch(null, { x: 'x' }); - - assert.deepStrictEqual(patched, [ - { name: 'Jane Doe', key: 'a', id: 0, x: 'x' }, - { name: 'Jack Doe', key: 'a', id: 1, x: 'x' }, - { name: 'Rick Doe', key: 'b', id: 3, x: 'x' }, - { name: 'Mick Doe', key: 'b', id: 4, x: 'x' }, - ]); - }); - }); - - describe('remove, with id', () => { - it('marks item as deleted', async () => { - const user = await userService.remove(0); - - assert.deepStrictEqual(user, { - name: 'Jane Doe', - key: 'a', - id: 0, - deleted: true, - }); - - await expect(() => userService.get(0)).rejects.toThrow(); - }); - - it('throws if item already deleted', async () => { - await expect(() => userService.remove(2)).rejects.toThrow(); - }); - }); - - describe('remove, without id', () => { - it('marks filtered items as deleted', async () => { - const query = { key: 'a' }; - await userService.remove(null, { query }); - - const users = await userService.find({ query }); - - assert.strictEqual(users.length, 0); - }); - - it('handles nothing found', async () => { - const users = await userService.remove(null, { query: { key: 'z' } }); - - assert.strictEqual(users.length, 0); - }); - }); - - describe('with customization: deletedAt', () => { - let peopleService: any; - - beforeEach(() => { - const app = feathers().use( - '/people', - new MemoryService({ - multi: ['create', 'patch', 'remove'], - }), - ); - - peopleService = app.service('people'); - peopleService.hooks({ - before: { - all: [ - softDelete({ - deletedQuery: async () => { - return { deletedAt: null }; - }, - removeData: async () => { - return { deletedAt: new Date() }; - }, - }), - ], - create: [ - (context: any) => { - context.data.deletedAt = null; - }, - ], - }, - }); - }); - - it('works with setting deletedAt to date', async () => { - const user = await peopleService.create({ name: 'Jon Doe' }); - const deletedUser = await peopleService.remove(user.id); - - assert.ok(deletedUser.deletedAt !== null); - - await expect(() => peopleService.get(user.id)).rejects.toThrow(); - }); - }); -}); diff --git a/test/hooks/stash-before.test.ts b/test/hooks/stash-before.test.ts deleted file mode 100755 index e1c44372..00000000 --- a/test/hooks/stash-before.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { assert, expect } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { stashBefore } from '../../src'; - -const startId = 6; -const storeInit = { - 0: { name: 'Jane Doe', key: 'a', id: 0 }, - 1: { name: 'Jack Doe', key: 'a', id: 1 }, - 2: { name: 'John Doe', key: 'a', id: 2 }, - 3: { name: 'Rick Doe', key: 'b', id: 3 }, - 4: { name: 'Dick Doe', key: 'b', id: 4 }, - 5: { name: 'Dork Doe', key: 'b', id: 5 }, -}; - -let store; -let finalParams: any; -let innerCallParams: any; - -function services(this: any) { - const app = this; - app.configure(users); -} - -function users(this: any) { - const app = this; - store = clone(storeInit); - - app.use( - 'users', - new MemoryService({ - store, - startId, - multi: true, - }), - ); - - app.service('users').hooks({ - before: { - all: [ - (context: any) => { - if (context.params.disableStashBefore === true) { - innerCallParams = context.params; - } - }, - stashBefore(), - (context: any) => { - finalParams = context.params; - }, - ], - }, - }); -} - -describe('services stash-before', () => { - let app; - let users: any; - - beforeEach(() => { - innerCallParams = finalParams = null; - - app = feathers().configure(services); - - users = app.service('users'); - }); - - ['get', 'update', 'patch', 'remove'].forEach(method => { - it(`stashes on ${method}`, () => { - return users[method](0, {}).then(() => { - assert.deepEqual(finalParams.before, storeInit[0]); - }); - }); - }); - - it('Do not stash when query is used in remove', () => { - return users.remove(null, { query: {} }).then(() => { - assert.notProperty(finalParams, 'before'); - }); - }); - - ['create', 'find'].forEach(method => { - it(`throws on ${method}`, async () => { - await expect(users[method]({})).rejects.toThrow(); - }); - }); - - it('stashes on get with original params', () => { - return users.get(0, { provider: 'socketio', eyecatcher: -1 }).then(() => { - assert.equal(finalParams.provider, 'socketio'); - assert.equal(finalParams.eyecatcher, -1); - - assert.equal(innerCallParams.provider, 'socketio'); - assert.equal(innerCallParams.eyecatcher, -1); - assert.notProperty(innerCallParams, 'authenticated'); - assert.notProperty(innerCallParams, 'user'); - }); - }); - - it('stashes on patch with custom params', () => { - return users.patch(0, {}, { provider: 'socketio', eyecatcher: -1 }).then(() => { - assert.equal(finalParams.provider, 'socketio'); - assert.equal(finalParams.eyecatcher, -1); - - assert.equal(innerCallParams.provider, 'socketio'); - assert.notProperty(innerCallParams, 'eyecatcher'); - assert.property(innerCallParams, 'authenticated'); - assert.property(innerCallParams, 'user'); - }); - }); -}); - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/unless.test.ts b/test/hooks/unless.test.ts deleted file mode 100755 index cc15ec8e..00000000 --- a/test/hooks/unless.test.ts +++ /dev/null @@ -1,398 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { assert } from 'vitest'; -import { unless } from '../../src'; -import { isPromise } from '../../src/common'; - -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; -let hookFcnAsyncCalls: any; -let hookFcnCalls: any; -let predicateHook: any; -let predicateOptions: any; -let predicateValue: any; - -const predicateSync = (hook: any) => { - predicateHook = clone(hook); - return false; -}; - -const predicateSync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return false; -}; - -const predicateAsync = (hook: any) => { - predicateHook = clone(hook); - return new Promise(resolve => resolve(false)); -}; - -const predicateAsync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return new Promise(resolve => resolve(false)); -}; - -const predicateAsyncFunny = (hook: HookContext) => { - predicateHook = clone(hook); - return new Promise(resolve => { - predicateValue = null; - return resolve(predicateValue); - }); -}; - -const hookFcnSync = (hook: HookContext): HookContext => { - hookFcnSyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -const hookFcnAsync = (hook: HookContext) => - new Promise(resolve => { - hookFcnAsyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - resolve(hook); - }); - -const hookFcn = (hook: HookContext): HookContext => { - hookFcnCalls = +1; - - return hook; -}; - -describe('services unless - sync predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if falsey non-function', () => { - unless( - false, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if truthy non-function', () => { - const result = unless(true, hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); - - it('calls sync hook function if sync predicate falsey', () => { - unless( - () => false, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if sync predicate truthy', () => { - const result = unless(() => true, hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); -}); - -describe('services unless - sync predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if sync predicate falsey', async () => { - const result = unless(false, hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call async hook function if sync predicate truthy', () => { - const result = unless(true, hookFcnAsync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } - - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - - it('calls async hook function if sync predicate returns falsey', async () => { - const result = unless(() => false, hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -describe('services unless - async predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if aync predicate falsey', async () => { - const result = unless(() => new Promise(resolve => resolve(false)), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('does not call sync hook function if async predicate truthy', async () => { - const result = unless(() => new Promise(resolve => resolve(true)), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - }); -}); - -describe('services unless - async predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if aync predicate falsey', async () => { - const result = unless(() => new Promise(resolve => resolve(false)), hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('does not call async hook function if async predicate truthy', async () => { - const result = unless(() => new Promise(resolve => resolve(true)), hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - result.then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - }); -}); - -describe('services unless - sync predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - }); - - it('does not need to access hook', () => { - unless( - () => false, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('is passed hook as param', () => { - unless( - predicateSync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('a higher order predicate can pass more options', () => { - unless( - predicateSync2({ z: 'z' }), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateOptions, { z: 'z' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -describe('services unless - async predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - predicateValue = null; - }); - - it('is passed hook as param', async () => { - const result = unless(predicateAsync, hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('is resolved', async () => { - // @ts-ignore - const result = unless(predicateAsyncFunny, hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - - assert.equal(predicateValue, null); - }); - }); - - it('a higher order predicate can pass more options', async () => { - const result = unless(predicateAsync2({ y: 'y' }), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateOptions, { y: 'y' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); -}); - -describe('services unless - runs multiple hooks', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('runs successfully', async () => { - await unless( - false, - hookFcnSync, - hookFcnAsync, - hookFcn, - )(hook).then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/validate-schema.test.ts b/test/hooks/validate-schema.test.ts deleted file mode 100755 index ebb0300d..00000000 --- a/test/hooks/validate-schema.test.ts +++ /dev/null @@ -1,292 +0,0 @@ -import { assert, expect } from 'vitest'; - -import { validateSchema } from '../../src/hooks/validate-schema'; - -import Ajv from 'ajv'; - -const ajv = new Ajv({ allErrors: true }); -ajv.addFormat('startWithJo', '^Jo'); -ajv.addSchema({ - $id: 'syncSchema', - properties: { - first: { type: 'string', format: 'startWithJo' }, - last: { type: 'string' }, - nested: { - type: 'object', - additionalProperties: false, - }, - }, - required: ['first', 'last'], -}); - -describe('services validateSchema', () => { - let hookBefore: any; - let hookBeforeArray: any; - let hookBeforeArrayForAjvInstance: any; - let schema: any; - let schemaForAjvInstance: any; - let asyncSchema: any; - let ajvAsync: any; - - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: { first: 'John', last: 'Doe' }, - }; - hookBeforeArray = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Jane', last: 'Doe' }, - { first: 'Joe', last: 'Doe' }, - ], - }; - hookBeforeArrayForAjvInstance = { - type: 'before', - method: 'create', - params: { provider: 'rest' }, - data: [ - { first: 'John', last: 'Doe' }, - { first: 'Josh', last: 'Doe' }, - { first: 'Joe', last: 'Doe' }, - ], - }; - schema = { - properties: { - first: { type: 'string' }, - last: { type: 'string' }, - nested: { - additionalProperties: false, - }, - }, - required: ['first', 'last'], - }; - schemaForAjvInstance = { - properties: { - first: { type: 'string', format: 'startWithJo' }, - last: { type: 'string' }, - nested: { - additionalProperties: false, - }, - }, - required: ['first', 'last'], - }; - }); - - describe('Sync validation', () => { - beforeEach(() => { - schema = { - properties: { - first: { type: 'string' }, - last: { type: 'string' }, - }, - required: ['first', 'last'], - }; - }); - - it('works with valid single item', () => { - validateSchema(schema, Ajv)(hookBefore); - }); - - it('works with array of valid items', () => { - validateSchema(schema, Ajv)(hookBeforeArray); - }); - - it('works with valid single item when ajv instance is passed', () => { - validateSchema(schemaForAjvInstance, ajv)(hookBefore); - }); - - it('works with array of valid items when ajv instance is passed', () => { - validateSchema(schemaForAjvInstance, ajv)(hookBeforeArrayForAjvInstance); - }); - - it('works with valid single item with existing schema in ajv instance', () => { - validateSchema('syncSchema', ajv)(hookBefore); - }); - - it('works with array of valid items with existing schema in ajv instance', () => { - validateSchema('syncSchema', ajv)(hookBeforeArrayForAjvInstance); - }); - - it('fails with in valid single item', () => { - hookBefore.data = { first: 1 }; - - try { - validateSchema(schema, Ajv)(hookBefore); - assert.fail('test succeeds unexpectedly'); - } catch (err: any) { - assert.deepEqual(err.errors, [ - "'first' should be string", - "should have required property 'last'", - ]); - } - }); - - it('fails with array of invalid items', () => { - hookBeforeArray.data[0] = { first: 1 }; - delete hookBeforeArray.data[2].last; - - try { - validateSchema(schema, Ajv)(hookBeforeArray); - assert.fail('test succeeds unexpectedly'); - } catch (err: any) { - assert.deepEqual(err.errors, [ - "'in row 1 of 3, first' should be string", - "in row 1 of 3, should have required property 'last'", - "in row 3 of 3, should have required property 'last'", - ]); - } - }); - it('fails with invalid single item when ajv instance is passed', () => { - hookBefore.data = { first: 'Jane' }; - - try { - validateSchema(schemaForAjvInstance, ajv)(hookBefore); - assert.fail('test succeeds unexpectedly'); - } catch (err: any) { - assert.deepEqual(err.errors, [ - '\'first\' should match format "startWithJo"', - "should have required property 'last'", - ]); - } - }); - - it('fails with array of invalid items when ajv instance is passed', () => { - hookBeforeArray.data[0] = { first: 'Jane' }; - delete hookBeforeArray.data[2].last; - - try { - validateSchema(schemaForAjvInstance, ajv)(hookBeforeArray); - assert.fail('test succeeds unexpectedly'); - } catch (err: any) { - assert.deepEqual(err.errors, [ - '\'in row 1 of 3, first\' should match format "startWithJo"', - "in row 1 of 3, should have required property 'last'", - '\'in row 2 of 3, first\' should match format "startWithJo"', - "in row 3 of 3, should have required property 'last'", - ]); - } - }); - - it('properly displays incorrect additional properties in nested objects', () => { - hookBefore.data.nested = { foo: 'bar' }; - - try { - validateSchema(schemaForAjvInstance, ajv)(hookBefore); - assert.fail('test succeeds unexpectedly'); - } catch (err: any) { - assert.deepEqual(err.errors, ["'nested' should NOT have additional properties: 'foo'"]); - } - }); - }); - - describe('Async validation', () => { - beforeAll(() => { - ajvAsync = new Ajv({ allErrors: true }); - - ajvAsync.addKeyword('equalsDoe', { - async: true, - schema: false, - validate: (item: any) => - new Promise((resolve, reject) => { - setTimeout(() => { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - item === 'Doe' - ? resolve(true) - : // @ts-ignore - reject(new Ajv.ValidationError([{ message: 'should be Doe' }])); - }, 50); - }), - }); - - ajvAsync.addFormat('3or4chars', { - async: true, - validate: (item: any) => - new Promise((resolve, _reject) => { - setTimeout(() => { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - item.length === 3 || item.length === 4 ? resolve(true) : resolve(false); - }, 50); - }), - }); - - ajvAsync.addSchema({ - $id: 'asyncSchema', - $async: true, - properties: { - first: { - type: 'string', - format: '3or4chars', - }, - last: { - type: 'string', - equalsDoe: true, - }, - }, - required: ['first', 'last'], - }); - }); - - beforeEach(() => { - asyncSchema = { - $async: true, - properties: { - first: { - type: 'string', - format: '3or4chars', - }, - last: { - type: 'string', - equalsDoe: true, - }, - }, - required: ['first', 'last'], - }; - }); - - it('works with string schema id', async () => { - await validateSchema('asyncSchema', ajvAsync)(hookBefore); - }); - - it('works with valid single item', async () => { - await validateSchema(asyncSchema, ajvAsync)(hookBefore); - }); - - it('works with array of valid items', async () => { - await validateSchema(asyncSchema, ajvAsync)(hookBeforeArray); - }); - - it('fails with in valid single item', async () => { - hookBefore.data = { first: '1' }; - - await expect(validateSchema(asyncSchema, ajvAsync)(hookBefore)).rejects.toSatisfy( - (err: any) => { - assert.deepEqual(err.errors, [ - '\'first\' should match format "3or4chars"', - "should have required property 'last'", - ]); - return true; - }, - ); - }); - - it('fails with array of invalid items', async () => { - hookBeforeArray.data[0].last = 'not Doe'; - delete hookBeforeArray.data[2].last; - - await expect(validateSchema(asyncSchema, ajvAsync)(hookBeforeArray)).rejects.toSatisfy( - (err: any) => { - assert.deepEqual(err.errors, [ - "in row 3 of 3, should have required property 'last'", - "'in row 1 of 3, last' should be Doe", - ]); - return true; - }, - ); - }); - }); -}); diff --git a/test/hooks/validate.test.ts b/test/hooks/validate.test.ts deleted file mode 100755 index 196b392a..00000000 --- a/test/hooks/validate.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { assert, expect } from 'vitest'; -import { validate } from '../../src'; -import { BadRequest } from '@feathersjs/errors'; - -let fcnSync: any; -let fcnPromise: any; -let fcnPromiseSanitize: any; -let origHookOk: any; -let origHookBad: any; -let hookOk: any; -let hookBad: any; -let fcnHook: any; - -describe('services validate', () => { - origHookOk = { type: 'before', method: 'create', data: { email: ' a@a.com ' } }; - origHookBad = { type: 'before', method: 'create', data: { email: '' } }; - - describe('Sync function', () => { - beforeEach(() => { - hookOk = clone(origHookOk); - hookBad = clone(origHookBad); - fcnHook = {}; - - fcnSync = (values: any, hook: any) => { - fcnHook = hook; - - return values.email.trim() ? null : { email: 'Email is invalid' }; - }; - }); - - it('test passes on correct data', () => { - const hook = validate(fcnSync)(hookOk); - assert.deepEqual(hook, origHookOk); - assert.deepEqual(fcnHook, origHookOk); - }); - - it('test fails on errors', () => { - assert.throws(() => validate(fcnSync)(hookBad)); - }); - }); - - describe('Promise function', () => { - beforeEach(() => { - hookOk = clone(origHookOk); - hookBad = clone(origHookBad); - fcnHook = {}; - - fcnPromise = (values: any, hook: any) => { - fcnHook = hook; - - return new Promise((resolve, reject) => { - setTimeout(() => { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - values.email.trim() - ? resolve() - : // @ts-ignore - reject(new BadRequest({ email: 'Email is invalid' })); - }, 100); - }); - }; - - fcnPromiseSanitize = (values: any) => - new Promise((resolve, reject) => { - setTimeout(() => { - // eslint-disable-next-line @typescript-eslint/no-unused-expressions - values.email.trim() - ? resolve(Object.assign(values, { email: values.email.trim() })) - : // @ts-ignore - reject(new BadRequest({ email: 'Email is invalid' })); - }, 100); - }); - }); - - it('test passes on correct data', async () => { - const result = await validate(fcnPromise)(hookOk); - - assert.deepEqual(result, origHookOk); - assert.deepEqual(fcnHook, origHookOk); - }); - - it('test can sanitize correct data', async () => { - const result = await validate(fcnPromiseSanitize)(hookOk); - - assert.equal(result.data.email, 'a@a.com'); - }); - - it('test fails on errors', async () => { - await expect(validate(fcnPromiseSanitize)(hookBad)).rejects.toThrow(); - }); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/hooks/when.test.ts b/test/hooks/when.test.ts deleted file mode 100755 index 5cc51dd6..00000000 --- a/test/hooks/when.test.ts +++ /dev/null @@ -1,403 +0,0 @@ -import type { HookContext } from '@feathersjs/feathers'; -import { assert } from 'vitest'; -import { when } from '../../src'; -import { isPromise } from '../../src/common'; - -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; -let hookFcnAsyncCalls: any; -let hookFcnCalls: any; -let predicateHook: any; -let predicateOptions: any; -let predicateValue: any; - -const predicateSync = (hook: any) => { - predicateHook = clone(hook); - return true; -}; - -const predicateSync2 = (options: any) => (hook: any) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return true; -}; - -const predicateAsync = (hook: HookContext) => { - predicateHook = clone(hook); - return new Promise(resolve => resolve(true)); -}; - -const predicateAsync2 = (options: any) => (hook: HookContext) => { - predicateOptions = clone(options); - predicateHook = clone(hook); - return new Promise(resolve => resolve(true)); -}; - -const predicateAsyncFunny = (hook: HookContext) => { - predicateHook = clone(hook); - return new Promise(resolve => { - predicateValue = 'abc'; - return resolve(predicateValue); - }); -}; - -const hookFcnSync = (hook: HookContext) => { - hookFcnSyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -const hookFcnAsync = (hook: HookContext) => - new Promise(resolve => { - hookFcnAsyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - resolve(hook); - }); - -const hookFcn = (hook: any) => { - hookFcnCalls = +1; - - return hook; -}; - -describe('services when - sync predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if truthy non-function', () => { - when( - // @ts-ignore - 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if falsey non-function', () => { - // @ts-ignore - const result = when('', hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); - - it('calls sync hook function if sync predicate truthy', () => { - when( - // @ts-ignore - () => 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if sync predicate falsey', () => { - // @ts-ignore - const result = when(() => '', hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); -}); - -describe('services when - sync predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if sync predicate truthy', async () => { - const result = when(true, hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call async hook function if sync predicate falsey', () => { - const result = when(false, hookFcnAsync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); - - it('calls async hook function if sync predicate returns truthy', async () => { - const result = when(() => true, hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -describe('services when - async predicate, sync hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls sync hook function if async predicate truthy', async () => { - const result = when(() => new Promise(resolve => resolve(true)), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('does not call sync hook function if async predicate falsey', async () => { - const result = when(() => new Promise(resolve => resolve(false)), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - }); -}); - -describe('services when - async predicate, async hook', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('calls async hook function if async predicate truthy', async () => { - const result = when(() => new Promise(resolve => resolve(true)), hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnAsyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('does not call async hook function if async predicate falsey', async () => { - const result = when(() => new Promise(resolve => resolve(false)), hookFcnAsync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(result1, hookBefore); - assert.equal(hookFcnAsyncCalls, 0); - assert.deepEqual(hook, hookBefore); - }); - }); -}); - -describe('services when - sync predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - }); - - it('does not need to access hook', () => { - when( - // @ts-ignore - () => 'a', - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('is passed hook as param', () => { - when( - predicateSync, - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('a higher order predicate can pass more options', () => { - when( - predicateSync2({ z: 'z' }), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(predicateOptions, { z: 'z' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -describe('services when - async predicate', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - predicateHook = null; - predicateOptions = null; - predicateValue = null; - }); - - it('is passed hook as param', async () => { - // @ts-ignore - const result = when(predicateAsync, hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); - - it('is resolved', async () => { - const result = when(predicateAsyncFunny, hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - - assert.equal(predicateValue, 'abc'); - }); - }); - - it('a higher order predicate can pass more options', async () => { - const result = when(predicateAsync2({ y: 'y' }), hookFcnSync)(hook); - - if (!isPromise(result)) { - assert.fail('promise unexpectedly not returned'); - } - - await result.then((result1: any) => { - assert.deepEqual(predicateOptions, { y: 'y' }); - assert.deepEqual(predicateHook, hookBefore); - assert.deepEqual(result1, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(result1, hookAfter); - }); - }); -}); - -describe('services when - runs multiple hooks', () => { - beforeEach(() => { - hookBefore = { type: 'before', method: 'create', data: { first: 'John', last: 'Doe' } }; - hookAfter = { type: 'before', method: 'create', data: { first: 'john', last: 'Doe' } }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - hookFcnAsyncCalls = 0; - }); - - it('runs successfully', async () => { - await when( - true, - hookFcnSync, - hookFcnAsync, - hookFcn, - )(hook).then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.equal(hookFcnAsyncCalls, 1); - assert.equal(hookFcnCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/index.test.ts b/test/index.test.ts index c2908803..c121add6 100755 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,65 +1,95 @@ -import { assert } from 'vitest'; -import * as allExported from '../src'; +import { assert } from 'vitest' +import * as allExported from '../src/index.js' const members = [ - 'actOnDefault', - 'actOnDispatch', - 'alterItems', + // transform + 'transformData', + 'transformResult', + 'cache', 'callingParams', 'callingParamsDefaults', 'checkContext', 'checkContextIf', 'combine', + 'createRelated', 'debug', - 'dePopulate', 'disablePagination', 'disallow', - 'discard', - 'discardQuery', - 'fastJoin', - 'fgraphql', + + // omit + 'omitData', + 'omitResult', + 'omitQuery', + 'getItems', + 'getDataIsArray', + 'getResultIsArray', 'hookTypes', 'isProvider', - 'keep', - 'keepInArray', - 'keepQuery', - 'keepQueryInArray', - 'lowerCase', + + // pick + 'pickData', + 'pickResult', + 'pickQuery', + + // lowercase + 'lowercaseData', + 'lowercaseResult', + 'makeCallingParams', 'methodNames', - 'mongoKeys', 'paramsForServer', 'paramsFromClient', - 'populate', 'preventChanges', + + // replace 'replaceItems', - 'required', - 'runHook', + 'replaceData', + 'replaceResult', + + 'checkRequired', 'runParallel', - 'sequelizeConvert', - 'serialize', 'setField', - 'setNow', + + 'setNowData', + 'setNowResult', + 'setSlug', - 'sifter', 'softDelete', 'stashBefore', 'traverse', - 'validate', - 'validateSchema', + + // iff 'iffElse', 'iff', 'when', 'unless', + + // predicates 'some', 'every', - 'isNot', -].sort(); + 'not', + 'isMulti', + 'isPaginated', + 'isContext', + + 'getPaginate', + 'skipResult', + + 'trimData', + 'trimResult', + + 'throwIf', + 'throwIfIsMulti', + 'throwIfIsProvider', + + 'getExposedMethods', + 'transformParams', +].sort() describe('services exposed hooks', () => { it('no unexpected hooks', () => { - assert.deepEqual(Object.keys(allExported).sort(), [].concat(members).sort()); - }); -}); + assert.deepEqual(Object.keys(allExported).sort(), [...members].sort()) + }) +}) diff --git a/test/utils/check-context.test.ts b/test/utils/check-context.test.ts deleted file mode 100755 index 7eac289c..00000000 --- a/test/utils/check-context.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { assert } from 'vitest'; - -import { checkContext } from '../../src'; - -describe('util checkContext', () => { - var hook: any; // eslint-disable-line no-var - - beforeEach(() => { - hook = { type: 'before', method: 'create' }; - }); - - it('handles "any" type and method', () => { - assert.equal(checkContext(hook), undefined); - }); - - it('handles expected type', () => { - hook.type = 'before'; - assert.equal(checkContext(hook, 'before'), undefined); - }); - - it('handles unexpected type', () => { - hook.type = 'after'; - assert.throws(() => { - checkContext(hook, 'before'); - }); - }); - - it('handles undefined type', () => { - hook.type = 'after'; - assert.equal(checkContext(hook), undefined); - }); - - it('handles null type', () => { - hook.type = 'after'; - assert.equal(checkContext(hook, null), undefined); - }); - - it('handles expected type as array', () => { - hook.type = 'before'; - assert.equal(checkContext(hook, ['before', 'after']), undefined); - }); - - it('handles unexpected type as array', () => { - hook.type = 'error'; - assert.throws(() => { - checkContext(hook, ['before', 'after']); - }); - }); - - it('handles expected method as string', () => { - hook.method = 'create'; - assert.equal(checkContext(hook, null, 'create'), undefined); - }); - - it('handles unexpected method as string', () => { - hook.method = 'patch'; - assert.throws(() => { - checkContext(hook, null, 'create'); - }); - }); - - it('handles expected method as array', () => { - hook.method = 'create'; - assert.equal(checkContext(hook, null, ['create']), undefined); - assert.equal(checkContext(hook, null, ['create', 'update', 'remove']), undefined); - }); - - it('handles unexpected method as array', () => { - hook.method = 'patch'; - assert.throws(() => { - checkContext(hook, null, ['create']); - }); - assert.throws(() => { - checkContext(hook, null, ['create', 'update', 'remove']); - }); - }); - - it('handles undefined method', () => { - hook.method = 'patch'; - assert.equal(checkContext(hook, null), undefined); - }); - - it('handles null method', () => { - hook.method = 'patch'; - assert.equal(checkContext(hook, null, null), undefined); - }); - - it('handles expected type and method as array', () => { - hook.type = 'before'; - hook.method = 'create'; - assert.equal(checkContext(hook, 'before', ['create']), undefined); - assert.equal(checkContext(hook, 'before', ['create', 'update', 'remove']), undefined); - }); - - it('allows custom methods', () => { - hook.type = 'before'; - hook.method = 'custom'; - assert.equal(checkContext(hook, 'before', ['create']), undefined); - assert.equal(checkContext(hook, 'before', ['create', 'update', 'remove']), undefined); - }); -}); diff --git a/test/utils/combine.test.ts b/test/utils/combine.test.ts deleted file mode 100755 index 32000b5d..00000000 --- a/test/utils/combine.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { assert } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { combine } from '../../src'; - -const startId = 6; -const storeInit = { - 0: { name: 'Jane Doe', key: 'a', id: 0 }, - 1: { name: 'Jack Doe', key: 'a', id: 1 }, - 2: { name: 'Jack Doe', key: 'a', id: 2, deleted: true }, - 3: { name: 'Rick Doe', key: 'b', id: 3 }, - 4: { name: 'Dick Doe', key: 'b', id: 4 }, - 5: { name: 'Dick Doe', key: 'b', id: 5, deleted: true }, -}; -let store; - -function services(this: any) { - const app = this; - app.configure(user); -} - -function user(this: any) { - const app = this; - let service: any; - let hookId: any; - let hookData: any; - let hookParamsQuery: any; - store = clone(storeInit); - - app.use( - '/users', - new MemoryService({ - store, - startId, - }), - ); - - app.service('users').hooks({ - before: { - all: [ - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 0.'); - } - service = this; - - hook.data = { a: 'a' }; - - hookId = hook.id; - hookData = clone(hook.data); - hookParamsQuery = clone(hook.params.query); - - return hook; - }, - combine( - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 1.'); - } - if (service !== this) { - throw new Error('Service wrong 1.'); - } - hook.params.trace = ['sync1']; - return hook; - }, - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 2.'); - } - if (service !== this) { - throw new Error('Service wrong 2.'); - } - - if (hook.params.query.key === 'b') { - throw new Error('Requested throw.'); - } - - hook.params.trace.push('promise1'); - return Promise.resolve(hook); - }, - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 3.'); - } - if (service !== this) { - throw new Error('Service wrong 3.'); - } - hook.params.trace.push('sync2'); - }, - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 4.'); - } - if (service !== this) { - throw new Error('Service wrong 4.'); - } - hook.params.trace.push('cb1'); - - return hook; - }, - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 5.'); - } - if (service !== this) { - throw new Error('Service wrong 5.'); - } - hook.params.trace.push('sync3'); - return hook; - }, - ), - function (this: any, hook: any) { - if (hook.app !== app) { - throw new Error('App wrong 9.'); - } - if (service !== this) { - throw new Error('Service wrong 9.'); - } - - assert.equal(hook.id, hookId); - assert.deepEqual(hook.data, hookData); - assert.deepEqual(hook.params.query, hookParamsQuery); - - assert.deepEqual(hook.params.trace, ['sync1', 'promise1', 'sync2', 'cb1', 'sync3']); - }, - ], - }, - }); -} - -describe('util combine', () => { - let app; - let user: any; - - beforeEach(() => { - app = feathers().configure(services); - user = app.service('users'); - }); - - it('runs successful hooks', async () => { - await user.find({ query: { key: 'a' } }); - }); - - it('throws on unsuccessful hook', async () => { - await user - .find({ query: { key: 'b' } }) - .then((_data: any) => { - assert.fail(true, false); - }) - .catch(() => {}); - }); -}); - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/utils/is-not.test.ts b/test/utils/is-not.test.ts deleted file mode 100755 index 6ed3d4e1..00000000 --- a/test/utils/is-not.test.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { assert } from 'vitest'; -import { iff, isNot, isProvider } from '../../src'; -import { isPromise } from '../../src/common'; - -let hookServer: any; -let hook: any; -let hookBefore: any; -let hookAfter: any; -let hookFcnSyncCalls: any; -let predicateCalls: any; - -const predicateSync = (value: any) => () => { - predicateCalls = +1; - return value; -}; - -const predicateAsync = - (value: T) => - () => - new Promise(resolve => { - predicateCalls = +1; - return resolve(value); - }); - -const hookFcnSync = (hook: any) => { - hookFcnSyncCalls = +1; - hook.data.first = hook.data.first.toLowerCase(); - - return hook; -}; - -describe('util isNot - predicate', () => { - beforeEach(() => { - hookServer = { type: 'before', method: 'create', params: { provider: '' } }; - predicateCalls = 0; - }); - - it('expects a function param', () => { - assert.throws(() => { - // @ts-ignore - isNot('not a function'); - }); - }); - - it('negates a sync function 1', () => { - const hook = clone(hookServer); - const result = isNot(predicateSync(true))(hook); - - assert.equal(predicateCalls, 1); - assert.equal(result, false); - }); - - it('negates a sync function 2', () => { - const hook = clone(hookServer); - const result = isNot(predicateSync(false))(hook); - - assert.equal(predicateCalls, 1); - assert.equal(result, true); - }); - - it('negates an async function 1', async () => { - const hook = clone(hookServer); - - await isNot(predicateAsync(true))(hook) - // @ts-ignore - .then((result: any) => { - assert.equal(predicateCalls, 1); - assert.equal(result, false); - }) - .catch(() => { - assert.fail('unexpected catch'); - }); - }); - - it('negates an async function 2', async () => { - const hook = clone(hookServer); - await isNot(predicateAsync(false))(hook) - // @ts-ignore - .then((result: any) => { - assert.equal(predicateCalls, 1); - assert.equal(result, true); - }) - .catch(() => { - assert.fail('unexpected catch'); - }); - }); -}); - -describe('services isNot - works with iff and isProvider', () => { - beforeEach(() => { - hookBefore = { - type: 'before', - method: 'create', - data: { first: 'John' }, - params: { provider: 'rest' }, - }; - hookAfter = { - type: 'before', - method: 'create', - data: { first: 'john' }, - params: { provider: 'rest' }, - }; - hook = clone(hookBefore); - hookFcnSyncCalls = 0; - }); - - it('calls sync hook function if truthy', () => { - iff( - isNot(isProvider('server')), - hookFcnSync, - )(hook) - // @ts-ignore - .then((hook: any) => { - assert.deepEqual(hook, hookAfter); - assert.equal(hookFcnSyncCalls, 1); - assert.deepEqual(hook, hookAfter); - }); - }); - - it('does not call sync hook function if falsey', () => { - const result = iff(isNot(isProvider('rest')), hookFcnSync)(hook); - - if (isPromise(result)) { - assert.fail('promise unexpectedly returned'); - } else { - assert.deepEqual(result, hookBefore); - assert.equal(hookFcnSyncCalls, 0); - assert.deepEqual(hook, hookBefore); - } - }); -}); - -// Helpers - -function clone(obj: any) { - return JSON.parse(JSON.stringify(obj)); -} diff --git a/test/utils/params-for-server.test.ts b/test/utils/params-for-server.test.ts deleted file mode 100755 index bec8f3b4..00000000 --- a/test/utils/params-for-server.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { assert } from 'vitest'; - -import { paramsForServer } from '../../src'; - -describe('util paramsToServer', () => { - it('handles empty params', () => { - const res = paramsForServer(); - assert.deepEqual(res, { query: { $client: {} } }); - }); - - it('handles params with query only', () => { - const res = paramsForServer({ query: { x: 'x', y: 1 } }); - assert.deepEqual(res, { query: { x: 'x', y: 1, $client: {} } }); - }); - - it('copies all params without query', () => { - const res: any = paramsForServer({ a: 'a', b: 1 } as any); - assert.deepEqual(res, { query: { $client: { a: 'a', b: 1 } } }); - }); - - it('copies all params with query', () => { - const res: any = paramsForServer({ query: { x: 'x', y: 1 }, a: 'a', b: 1 } as any); - assert.deepEqual(res, { query: { x: 'x', y: 1, $client: { a: 'a', b: 1 } } }); - }); - - it('copies whitelist props', () => { - const res: any = paramsForServer({ a: 'a', b: 1 } as any, 'a', 'b'); - assert.deepEqual(res, { query: { $client: { a: 'a', b: 1 } } }); - }); - - it('ignores non whitelist props', () => { - const res: any = paramsForServer({ a: 'a', b: 1 } as any, 'b'); - assert.deepEqual(res, { query: { $client: { b: 1 } } }); - }); -}); diff --git a/test/utils/run-hook.test.ts b/test/utils/run-hook.test.ts deleted file mode 100755 index e92d9fe4..00000000 --- a/test/utils/run-hook.test.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { assert } from 'vitest'; -import { fastJoin, keep, runHook } from '../../src'; - -const app = { a: 'a' }; -const params = { p: 'p' }; -const service = { s: 's' }; -let runHooks1: any; -let runHooks2: any; -let hook: any; - -const testHook = (hook1: any) => { - hook = hook1; - - hook1._called = 'called'; - return hook1; -}; - -describe('util runHooks', () => { - beforeEach(() => { - runHooks1 = runHook({ app, params, service } as any); - runHooks2 = runHook(); - }); - - it('get expected hook & object result', () => { - const data = { name: 'john' }; - - return Promise.resolve(data) - .then(runHooks1(testHook)) - .then(result => { - assert.deepEqual(result, data, 'test result'); - assert.deepEqual( - hook, - { - app, - params, - service, - _called: 'called', - result: data, - type: 'after', - }, - 'test hook', - ); - }); - }); - - it('get expected array result', () => { - const data = [{ name: 'john' }]; - - return Promise.resolve(data) - .then(runHooks1(testHook)) - .then(result => { - assert.deepEqual(result, data, 'test result'); - }); - }); - - it('get expected find result', () => { - const data = { total: 1, data: [{ name: 'john' }] }; - - return Promise.resolve(data) - .then(runHooks1(testHook)) - .then(result => { - assert.deepEqual(result, data, 'test result'); - }); - }); - - it('test using keep hook', () => { - const data: any[] = [ - { name: 'John', job: 'dev', address: { city: 'Montreal', postal: 'H4T 2A1' } }, - ]; - - return Promise.resolve(data) - .then(runHooks2(keep('name', 'address.city'))) - .then(result => { - assert.deepEqual(result, [{ name: 'John', address: { city: 'Montreal' } }]); - }); - }); - - it('test using fastJoin hook', () => { - const paymentsRecords = [ - { _id: 101, amount: 100, patientId: 1 }, - { _id: 102, amount: 105, patientId: 1 }, - { _id: 103, amount: 110, patientId: 1 }, - { _id: 104, amount: 115, patientId: 2 }, - { _id: 105, amount: 120, patientId: 3 }, - { _id: 106, amount: 125, patientId: 3 }, - ]; - - const patientsRecords = [ - { _id: 1, name: 'John' }, - { _id: 2, name: 'Marshall' }, - { _id: 3, name: 'David' }, - ]; - - const paymentResolvers = { - joins: { - patient: () => (payment: any) => { - payment.patient = patientsRecords.filter(patient => patient._id === payment.patientId)[0]; - }, - }, - }; - - const expected = [ - { _id: 101, amount: 100, patientId: 1, patient: { _id: 1, name: 'John' } }, - { _id: 102, amount: 105, patientId: 1, patient: { _id: 1, name: 'John' } }, - { _id: 103, amount: 110, patientId: 1, patient: { _id: 1, name: 'John' } }, - { _id: 104, amount: 115, patientId: 2, patient: { _id: 2, name: 'Marshall' } }, - { _id: 105, amount: 120, patientId: 3, patient: { _id: 3, name: 'David' } }, - { _id: 106, amount: 125, patientId: 3, patient: { _id: 3, name: 'David' } }, - ]; - - return ( - Promise.resolve(paymentsRecords) - // @ts-ignore - .then(runHooks2(fastJoin(paymentResolvers))) - .then(result => { - assert.deepEqual(result, expected); - }) - ); - }); -}); diff --git a/test/utils/some.test.ts b/test/utils/some.test.ts deleted file mode 100755 index 5958a048..00000000 --- a/test/utils/some.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { assert } from 'vitest'; -import { feathers } from '@feathersjs/feathers'; -import { MemoryService } from '@feathersjs/memory'; -import { iff, some, isNot } from '../../src'; - -describe('util some', () => { - let app: any; - - beforeEach(() => { - app = feathers().use('/users', new MemoryService()); - }); - - describe('when at least 1 hook is truthy', () => { - beforeEach(() => { - app.service('users').hooks({ - before: { - all: [ - iff( - some( - (_hook: any) => false, - (_hook: any) => Promise.resolve(false), - (_hook: any) => Promise.resolve(true), - (_hook: any) => true, - // @ts-ignore - (_hook: any) => 1, - (_hook: any) => {}, - ), - (hook: any) => Promise.resolve(hook), - ), - ], - }, - }); - }); - - it('returns true', () => { - return app - .service('users') - .find() - .then((result: any) => { - assert.deepEqual(result, []); - }); - }); - }); - - describe('when a hook throws an error', () => { - beforeEach(() => { - app.service('users').hooks({ - before: { - all: [ - iff( - some( - (_hook: any) => true, - (_hook: any) => { - throw new Error('Hook 2 errored'); - }, - (_hook: any) => true, - ), - (hook: any) => Promise.resolve(hook), - ), - ], - }, - }); - }); - - it('rejects with the error', () => { - return app - .service('users') - .find() - .catch((error: any) => { - assert.equal(error.message, 'Hook 2 errored'); - }); - }); - }); - - describe('when a hook rejects with an error', () => { - beforeEach(() => { - app.service('users').hooks({ - before: { - all: [ - iff( - some( - (_hook: any) => true, - (_hook: any) => Promise.reject(Error('Hook 2 errored')), - (_hook: any) => true, - ), - (hook: any) => Promise.resolve(hook), - ), - ], - }, - }); - }); - - it('rejects with the error', () => { - return app - .service('users') - .find() - .catch((error: any) => { - assert.equal(error.message, 'Hook 2 errored'); - }); - }); - }); - - describe('when all hooks are falsey', () => { - beforeEach(() => { - app.service('users').hooks({ - before: { - all: [ - iff( - isNot( - some( - (_hook: any) => false, - (_hook: any) => Promise.resolve(false), - // @ts-ignore - (_hook: any) => null, - (_hook: any) => undefined, - // @ts-ignore - (_hook: any) => 0, - ), - ), - () => Promise.reject(new Error('All hooks returned false')), - ), - ], - }, - }); - }); - - it('returns false', () => { - return app - .service('users') - .find() - .catch((error: any) => { - assert.equal(error.message, 'All hooks returned false'); - }); - }); - }); -}); diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json new file mode 100644 index 00000000..fb9c7721 --- /dev/null +++ b/tsconfig.eslint.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "include": [ + "src/**/*", + "test/**/*", + "tsdown.config.ts", + "vite.config.ts", + "docs/**/*", + "docs/.vitepress/**/*", + ], +} + \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1eadbd48..32894ae4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,15 @@ { + "extends": "@tsconfig/node22/tsconfig.json", "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "Node", + "outDir": "./dist", + "rootDir": "./src", "esModuleInterop": true, - "strict": true, - "types": ["vitest/globals"] + "types": ["vitest/globals", "vitest/importMeta"], + "declaration": true, + "paths": { + "feathers-commons": ["./src/index.ts"] + } }, - "include": ["src/**/*", "test/**/*"], - "exclude": ["node_modules"] + "include": ["src/**/*"] } + \ No newline at end of file diff --git a/tsdown.config.ts b/tsdown.config.ts new file mode 100644 index 00000000..842e872f --- /dev/null +++ b/tsdown.config.ts @@ -0,0 +1,36 @@ +import { defineConfig } from 'tsdown' +import pkg from './package.json' + +export default defineConfig({ + entry: { + index: 'src/index.ts', + hooks: 'src/hooks/index.ts', + utils: 'src/utils/index.ts', + predicates: 'src/predicates/index.ts', + resolvers: 'src/resolvers/index.ts', + }, + clean: true, + sourcemap: true, + dts: true, + format: ['esm'], + outDir: 'dist', + define: { + 'import.meta.vitest': 'undefined', + }, + target: 'esnext', + platform: 'neutral', + outExtensions: ctx => { + if (ctx.format === 'es') { + return { js: '.js', dts: '.ts' } + } + return {} + }, + external: [ + // regex for "node:*" imports + /^node:.*/, + ...Object.keys(pkg.dependencies), + ...Object.keys(pkg.devDependencies), + ], + treeshake: true, + unused: true, +}) diff --git a/vite.config.ts b/vite.config.ts index 4ceeee18..cc32bbea 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,19 +1,24 @@ -import { defineConfig } from "vitest/config"; +import { defineConfig } from 'vitest/config' export default defineConfig({ test: { globals: true, coverage: { - provider: "v8", - reporter: ["text", "lcov"], - include: ["src/**/*.{js,ts}"], - exclude: ["**/*.test.{js,ts}", "src/types.ts"], + provider: 'v8', + reporter: ['text', 'lcov'], + include: ['src/**/*.{js,ts}'], + exclude: [ + '**/*.test.{js,ts}', + 'src/types.ts', + 'src/resolvers/index.ts', + 'src/resolvers/hooks/index.ts', + ], thresholds: { lines: 85, functions: 85, branches: 85, statements: 85, - } + }, }, }, -}); +})