diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 0d92402c..00000000 --- a/.eslintignore +++ /dev/null @@ -1,5 +0,0 @@ -.github -.nyc_output -coverage -docs/* -node_modules diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 8e36b31a..00000000 --- a/.eslintrc +++ /dev/null @@ -1,54 +0,0 @@ -{ - "extends": "eslint:recommended", - "env": { - "node": true, - "mocha": true, - "es6": true - }, - "parserOptions": { - "ecmaVersion": 9, - "sourceType": "module", - "ecmaFeatures" : { - "globalReturn": false, - "impliedStrict": true, - "jsx": false - } - }, - "rules": { - "indent": [ - "error", - 2 - ], - "linebreak-style": [ - "error", - "unix" - ], - "quotes": [ - "error", - "single" - ], - "semi": [ - "error", - "always" - ], - "no-console": [ - "error" - ], - "no-var": [ - "error" - ], - "prefer-const": ["error", { - "destructuring": "any", - "ignoreReadBeforeAssign": false - }], - "no-unused-vars": [ - "error", - { - "vars": "all", - "args": "none", - "ignoreRestSiblings": false - } - ] - } -} - \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 90819cf4..8da764b9 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,7 +14,7 @@ on: jobs: lint: - name: Javascript standard lint + name: Javascript Biome lint/format runs-on: ubuntu-latest steps: - name: Checkout repository @@ -28,8 +28,10 @@ jobs: with: node-version: 24 cache: npm - - run: npm clean-install - - run: npm run lint + - run: | + npm clean-install + npm run lint + npm run format unittest: name: unit tests diff --git a/README.md b/README.md index 5f01c4af..93599574 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,12 @@ Complete, compliant and well tested module for implementing an OAuth2 server in [![Tests](https://github.com/node-oauth/node-oauth2-server/actions/workflows/tests.yml/badge.svg)](https://github.com/node-oauth/node-oauth2-server/actions/workflows/tests.yml) [![CodeQL Semantic Analysis](https://github.com/node-oauth/node-oauth2-server/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/node-oauth/node-oauth2-server/actions/workflows/codeql-analysis.yml) -[![Tests for Release](https://github.com/node-oauth/node-oauth2-server/actions/workflows/tests-release.yml/badge.svg)](https://github.com/node-oauth/node-oauth2-server/actions/workflows/tests-release.yml) [![Documentation Status](https://readthedocs.org/projects/node-oauthoauth2-server/badge/?version=latest)](https://node-oauthoauth2-server.readthedocs.io/en/latest/?badge=latest) [![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) [![npm Version](https://img.shields.io/npm/v/@node-oauth/oauth2-server?label=version)](https://www.npmjs.com/package/@node-oauth/oauth2-server) [![npm Downloads/Week](https://img.shields.io/npm/dw/@node-oauth/oauth2-server)](https://www.npmjs.com/package/@node-oauth/oauth2-server) [![GitHub License](https://img.shields.io/github/license/node-oauth/node-oauth2-server)](https://github.com/node-oauth/node-oauth2-server/blob/master/LICENSE) +[![Formatted with Biome](https://img.shields.io/badge/Formatted_with-Biome-60a5fa?style=flat&logo=biome)](https://biomejs.dev/) NOTE: This project has been forked from [oauthjs/node-oauth2-server](https://github.com/oauthjs/node-oauth2-server) and is a continuation due to the project appearing to be abandoned. Please see [our issue board](https://github.com/node-oauth/node-oauth2-server/issues) to talk about next steps and the future of this project. diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..081db071 --- /dev/null +++ b/biome.json @@ -0,0 +1,59 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.5.0/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true, + "includes": ["index.js", "lib/**/*.js", "test/**/*.js"] + }, + "formatter": { + "enabled": true, + "indentStyle": "tab" + }, + "linter": { + "enabled": true, + "rules": { + "preset": "recommended", + "suspicious": { + "noRedundantUseStrict": "off", + "noPrototypeBuiltins": "off", + "useIsArray": "off", + "noGlobalAssign": "off" + }, + "complexity": { + "useArrowFunction": "off", + "useDateNow": "off", + "useOptionalChain": "off", + "useLiteralKeys": "off", + "noUselessThisAlias": "off" + }, + "correctness": { + "noUnusedFunctionParameters": "off", + "noUnusedVariables": "off" + }, + "style": { + "useNodejsImportProtocol": "off", + "useTemplate": "off" + } + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single", + "indentStyle": "space", + "trailingCommas": "none", + "lineWidth": 120 + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/index.js b/index.js index f4f940ab..070b74a4 100644 --- a/index.js +++ b/index.js @@ -32,4 +32,3 @@ exports.UnauthorizedClientError = require('./lib/errors/unauthorized-client-erro exports.UnauthorizedRequestError = require('./lib/errors/unauthorized-request-error'); exports.UnsupportedGrantTypeError = require('./lib/errors/unsupported-grant-type-error'); exports.UnsupportedResponseTypeError = require('./lib/errors/unsupported-response-type-error'); - diff --git a/lib/errors/access-denied-error.js b/lib/errors/access-denied-error.js index e207f052..a573ebbd 100644 --- a/lib/errors/access-denied-error.js +++ b/lib/errors/access-denied-error.js @@ -13,10 +13,10 @@ const OAuthError = require('./oauth-error'); */ class AccessDeniedError extends OAuthError { /** - * @constructor - * @param message {string} - * @param properties {object=} - */ + * @constructor + * @param message {string} + * @param properties {object=} + */ constructor(message, properties) { properties = { code: 400, diff --git a/lib/errors/insufficient-scope-error.js b/lib/errors/insufficient-scope-error.js index e0fb876c..3ff9bc48 100644 --- a/lib/errors/insufficient-scope-error.js +++ b/lib/errors/insufficient-scope-error.js @@ -17,7 +17,7 @@ class InsufficientScopeError extends OAuthError { * @constructor * @param message {string} * @param properties {object=} - */ + */ constructor(message, properties) { properties = { code: 403, diff --git a/lib/errors/invalid-argument-error.js b/lib/errors/invalid-argument-error.js index 46ba642d..9c68b13d 100644 --- a/lib/errors/invalid-argument-error.js +++ b/lib/errors/invalid-argument-error.js @@ -16,7 +16,7 @@ class InvalidArgumentError extends OAuthError { * @constructor * @param message {string} * @param properties {object=} - */ + */ constructor(message, properties) { properties = { code: 500, diff --git a/lib/errors/invalid-client-error.js b/lib/errors/invalid-client-error.js index 33b15035..7fe53146 100644 --- a/lib/errors/invalid-client-error.js +++ b/lib/errors/invalid-client-error.js @@ -15,10 +15,10 @@ const OAuthError = require('./oauth-error'); class InvalidClientError extends OAuthError { /** - * @constructor - * @param message {string} - * @param properties {object=} - */ + * @constructor + * @param message {string} + * @param properties {object=} + */ constructor(message, properties) { properties = { code: 400, diff --git a/lib/errors/invalid-grant-error.js b/lib/errors/invalid-grant-error.js index b91841f7..171b39c4 100644 --- a/lib/errors/invalid-grant-error.js +++ b/lib/errors/invalid-grant-error.js @@ -16,10 +16,10 @@ const OAuthError = require('./oauth-error'); class InvalidGrantError extends OAuthError { /** - * @constructor - * @param message {string} - * @param properties {object=} - */ + * @constructor + * @param message {string} + * @param properties {object=} + */ constructor(message, properties) { properties = { code: 400, diff --git a/lib/errors/oauth-error.js b/lib/errors/oauth-error.js index 1291d913..c4c33a68 100644 --- a/lib/errors/oauth-error.js +++ b/lib/errors/oauth-error.js @@ -11,10 +11,10 @@ const http = require('http'); */ class OAuthError extends Error { /** - * @constructor - * @param messageOrError - * @param properties - */ + * @constructor + * @param messageOrError + * @param properties + */ constructor(messageOrError, properties) { super(messageOrError, properties); diff --git a/lib/grant-types/abstract-grant-type.js b/lib/grant-types/abstract-grant-type.js index bfaa8d92..19a4a88b 100644 --- a/lib/grant-types/abstract-grant-type.js +++ b/lib/grant-types/abstract-grant-type.js @@ -15,16 +15,16 @@ const { parseScope } = require('../utils/scope-util'); */ class AbstractGrantType { /** - * @constructor - * @param options {object} - * @param options.accessTokenLifetime {number} access token lifetime in seconds - * @param options.model {Model} the model - * @param options.refreshTokenLifetime {number} - * @param [options.alwaysIssueNewRefreshToken=true] {boolean=} Always revoke the used refresh token and issue a new one for the `refresh_token` grant. - * @throws {InvalidArgumentError} if {options.accessTokenLifeTime} is missing - * @throws {InvalidArgumentError} if {options.model} is missing - */ - constructor (options) { + * @constructor + * @param options {object} + * @param options.accessTokenLifetime {number} access token lifetime in seconds + * @param options.model {Model} the model + * @param options.refreshTokenLifetime {number} + * @param [options.alwaysIssueNewRefreshToken=true] {boolean=} Always revoke the used refresh token and issue a new one for the `refresh_token` grant. + * @throws {InvalidArgumentError} if {options.accessTokenLifeTime} is missing + * @throws {InvalidArgumentError} if {options.model} is missing + */ + constructor(options) { options = options || {}; if (!options.accessTokenLifetime) { @@ -42,17 +42,17 @@ class AbstractGrantType { } /** - * Generate access token. - * If the model implements `generateAccessToken` then - * this implementation will be used. - * Otherwise, falls back to an internal implementation from `TokenUtil.generateRandomToken`. - * - * @param client - * @param user - * @param scope - * @return {Promise} - */ - async generateAccessToken (client, user, scope) { + * Generate access token. + * If the model implements `generateAccessToken` then + * this implementation will be used. + * Otherwise, falls back to an internal implementation from `TokenUtil.generateRandomToken`. + * + * @param client + * @param user + * @param scope + * @return {Promise} + */ + async generateAccessToken(client, user, scope) { if (this.model.generateAccessToken) { // We should not fall back to a random accessToken, if the model did not // return a token, in order to prevent unintended token-issuing. @@ -63,9 +63,9 @@ class AbstractGrantType { } /** - * Generate refresh token. - */ - async generateRefreshToken (client, user, scope) { + * Generate refresh token. + */ + async generateRefreshToken(client, user, scope) { if (this.model.generateRefreshToken) { // We should not fall back to a random refreshToken, if the model did not // return a token, in order to prevent unintended token-issuing. @@ -76,19 +76,17 @@ class AbstractGrantType { } /** - * Get access token expiration date. - */ + * Get access token expiration date. + */ getAccessTokenExpiresAt() { return new Date(Date.now() + this.accessTokenLifetime * 1000); } - - /** * Get refresh token expiration date (now + refresh token lifetime) * @returns {Date} */ - getRefreshTokenExpiresAt () { + getRefreshTokenExpiresAt() { return new Date(Date.now() + this.refreshTokenLifetime * 1000); } @@ -97,7 +95,7 @@ class AbstractGrantType { * @param request {Request} * @returns {string|undefined} */ - getScope (request) { + getScope(request) { return parseScope(request.body.scope); } @@ -112,7 +110,7 @@ class AbstractGrantType { * @return {string} the validated scope * @throws {InvalidScopeError} if the {Model#validateScope} method returned a falsy value */ - async validateScope (user, client, scope) { + async validateScope(user, client, scope) { if (this.model.validateScope) { const validatedScope = await this.model.validateScope(user, client, scope); diff --git a/lib/grant-types/authorization-code-grant-type.js b/lib/grant-types/authorization-code-grant-type.js index 56df29ec..810ba257 100644 --- a/lib/grant-types/authorization-code-grant-type.js +++ b/lib/grant-types/authorization-code-grant-type.js @@ -18,9 +18,9 @@ const pkce = require('../pkce/pkce'); */ class AuthorizationCodeGrantType extends AbstractGrantType { /** - * @constructor - * @param options - */ + * @constructor + * @param options + */ constructor(options = {}) { if (!options.model) { throw new InvalidArgumentError('Missing parameter: `model`'); @@ -45,12 +45,12 @@ class AuthorizationCodeGrantType extends AbstractGrantType { } /** - * Handle authorization code grant. - * - * @param request {Request} - * @param client {ClientData} - * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 - */ + * Handle authorization code grant. + * + * @param request {Request} + * @param client {ClientData} + * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 + */ async handle(request, client) { if (!request) { @@ -73,11 +73,11 @@ class AuthorizationCodeGrantType extends AbstractGrantType { } /** - * Get the authorization code. - * @param request {Request} - * @param client {ClientData} - * @return {Promise<{user}>} - */ + * Get the authorization code. + * @param request {Request} + * @param client {ClientData} + * @return {Promise<{user}>} + */ async getAuthorizationCode(request, client) { if (!request.body.code) { @@ -163,8 +163,7 @@ class AuthorizationCodeGrantType extends AbstractGrantType { if (!this.hashesAreEqual(hash, code.codeChallenge)) { throw new InvalidGrantError('Invalid grant: code verifier is invalid'); } - } - else { + } else { if (request.body.code_verifier) { // No code challenge but code_verifier was passed in. throw new InvalidGrantError('Invalid grant: code verifier is invalid'); @@ -191,16 +190,16 @@ class AuthorizationCodeGrantType extends AbstractGrantType { } /** - * Validate the redirect URI. - * - * "The authorization server MUST ensure that the redirect_uri parameter is - * present if the redirect_uri parameter was included in the initial - * authorization request as described in Section 4.1.1, and if included - * ensure that their values are identical." - * @param request {Request} - * @param code {AuthorizationCodeData} - * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 - */ + * Validate the redirect URI. + * + * "The authorization server MUST ensure that the redirect_uri parameter is + * present if the redirect_uri parameter was included in the initial + * authorization request as described in Section 4.1.1, and if included + * ensure that their values are identical." + * @param request {Request} + * @param code {AuthorizationCodeData} + * @see https://tools.ietf.org/html/rfc6749#section-4.1.3 + */ validateRedirectUri(request, code) { if (!code.redirectUri) { @@ -219,14 +218,14 @@ class AuthorizationCodeGrantType extends AbstractGrantType { } /** - * Revoke the authorization code. - * - * "The authorization code MUST expire shortly after it is issued to mitigate - * the risk of leaks. [...] If an authorization code is used more than once, - * the authorization server MUST deny the request." - * @param code {AuthorizationCodeData} - * @see https://tools.ietf.org/html/rfc6749#section-4.1.2 - */ + * Revoke the authorization code. + * + * "The authorization code MUST expire shortly after it is issued to mitigate + * the risk of leaks. [...] If an authorization code is used more than once, + * the authorization server MUST deny the request." + * @param code {AuthorizationCodeData} + * @see https://tools.ietf.org/html/rfc6749#section-4.1.2 + */ async revokeAuthorizationCode(code) { const status = await this.model.revokeAuthorizationCode(code); @@ -238,16 +237,15 @@ class AuthorizationCodeGrantType extends AbstractGrantType { return code; } - /** - * Save token. + * Save token. * * @param user {object} * @param client {ClientData} * @param authorizationCode {string} * @param requestedScope {string} - * - */ + * + */ async saveToken(user, client, authorizationCode, requestedScope) { const validatedScope = await this.validateScope(user, client, requestedScope); @@ -262,7 +260,7 @@ class AuthorizationCodeGrantType extends AbstractGrantType { accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, - scope: validatedScope, + scope: validatedScope }; return this.model.saveToken(token, client, user); diff --git a/lib/grant-types/client-credentials-grant-type.js b/lib/grant-types/client-credentials-grant-type.js index 5e6e74f6..604d2dfc 100644 --- a/lib/grant-types/client-credentials-grant-type.js +++ b/lib/grant-types/client-credentials-grant-type.js @@ -30,10 +30,10 @@ class ClientCredentialsGrantType extends AbstractGrantType { } /** - * Handle client credentials grant. - * - * @see https://tools.ietf.org/html/rfc6749#section-4.4.2 - */ + * Handle client credentials grant. + * + * @see https://tools.ietf.org/html/rfc6749#section-4.4.2 + */ async handle(request, client) { if (!request) { @@ -51,8 +51,8 @@ class ClientCredentialsGrantType extends AbstractGrantType { } /** - * Retrieve the user using client credentials. - */ + * Retrieve the user using client credentials. + */ async getUserFromClient(client) { const user = await this.model.getUserFromClient(client); @@ -65,8 +65,8 @@ class ClientCredentialsGrantType extends AbstractGrantType { } /** - * Save token. - */ + * Save token. + */ async saveToken(user, client, requestedScope) { const validatedScope = await this.validateScope(user, client, requestedScope); @@ -75,7 +75,7 @@ class ClientCredentialsGrantType extends AbstractGrantType { const token = { accessToken, accessTokenExpiresAt, - scope: validatedScope, + scope: validatedScope }; return this.model.saveToken(token, client, user); diff --git a/lib/grant-types/password-grant-type.js b/lib/grant-types/password-grant-type.js index bcb32c3a..b2dee312 100644 --- a/lib/grant-types/password-grant-type.js +++ b/lib/grant-types/password-grant-type.js @@ -33,10 +33,10 @@ class PasswordGrantType extends AbstractGrantType { } /** - * Retrieve the user from the model using a username/password combination. - * - * @see https://tools.ietf.org/html/rfc6749#section-4.3.2 - */ + * Retrieve the user from the model using a username/password combination. + * + * @see https://tools.ietf.org/html/rfc6749#section-4.3.2 + */ async handle(request, client) { if (!request) { @@ -54,8 +54,8 @@ class PasswordGrantType extends AbstractGrantType { } /** - * Get user using a username/password combination. - */ + * Get user using a username/password combination. + */ async getUser(request, client) { if (!request.body.username) { @@ -84,8 +84,8 @@ class PasswordGrantType extends AbstractGrantType { } /** - * Save token. - */ + * Save token. + */ async saveToken(user, client, requestedScope) { const validatedScope = await this.validateScope(user, client, requestedScope); @@ -99,7 +99,7 @@ class PasswordGrantType extends AbstractGrantType { accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, - scope: validatedScope, + scope: validatedScope }; return this.model.saveToken(token, client, user); diff --git a/lib/grant-types/refresh-token-grant-type.js b/lib/grant-types/refresh-token-grant-type.js index 54b04222..26ac3309 100644 --- a/lib/grant-types/refresh-token-grant-type.js +++ b/lib/grant-types/refresh-token-grant-type.js @@ -38,10 +38,10 @@ class RefreshTokenGrantType extends AbstractGrantType { } /** - * Handle refresh token grant. - * - * @see https://tools.ietf.org/html/rfc6749#section-6 - */ + * Handle refresh token grant. + * + * @see https://tools.ietf.org/html/rfc6749#section-6 + */ async handle(request, client) { if (!request) { @@ -64,8 +64,8 @@ class RefreshTokenGrantType extends AbstractGrantType { } /** - * Get refresh token. - */ + * Get refresh token. + */ async getRefreshToken(request, client) { if (!request.body.refresh_token) { @@ -106,10 +106,10 @@ class RefreshTokenGrantType extends AbstractGrantType { } /** - * Revoke the refresh token. - * - * @see https://tools.ietf.org/html/rfc6749#section-6 - */ + * Revoke the refresh token. + * + * @see https://tools.ietf.org/html/rfc6749#section-6 + */ async revokeToken(token) { if (this.alwaysIssueNewRefreshToken === false) { @@ -126,8 +126,8 @@ class RefreshTokenGrantType extends AbstractGrantType { } /** - * Save token. - */ + * Save token. + */ async saveToken(user, client, scope) { const accessToken = await this.generateAccessToken(client, user, scope); @@ -137,7 +137,7 @@ class RefreshTokenGrantType extends AbstractGrantType { const token = { accessToken, accessTokenExpiresAt, - scope, + scope }; if (this.alwaysIssueNewRefreshToken !== false) { @@ -148,7 +148,7 @@ class RefreshTokenGrantType extends AbstractGrantType { return this.model.saveToken(token, client, user); } - getScope (request, token) { + getScope(request, token) { const requestedScope = super.getScope(request); const originalScope = token.scope; @@ -164,7 +164,7 @@ class RefreshTokenGrantType extends AbstractGrantType { return originalScope; } - const valid = requestedScope.every(scope => { + const valid = requestedScope.every((scope) => { return originalScope.includes(scope); }); diff --git a/lib/handlers/authenticate-handler.js b/lib/handlers/authenticate-handler.js index 54674334..4072f385 100644 --- a/lib/handlers/authenticate-handler.js +++ b/lib/handlers/authenticate-handler.js @@ -21,16 +21,16 @@ const { parseScope } = require('../utils/scope-util'); */ class AuthenticateHandler { /** - * @constructor - * @param options {object} Server options. - * @param options.model {Model} The Model; this is always required. - * @param options.scope {string[]|undefined} The scope(s) to authenticate. - * @param [options.addAcceptedScopesHeader=true] {boolean=} Set the `X-Accepted-OAuth-Scopes` HTTP header on response objects. - * @param [options.addAuthorizedScopesHeader=true] {boolean=} Set the `X-OAuth-Scopes` HTTP header on response objects. - * @param [options.allowBearerTokensInQueryString=false] {boolean=} Allow clients to pass bearer tokens in the query string of a request. - * @throws {InvalidArgumentError} if {model} is missing or does not implement `getAccessToken` - */ - constructor (options) { + * @constructor + * @param options {object} Server options. + * @param options.model {Model} The Model; this is always required. + * @param options.scope {string[]|undefined} The scope(s) to authenticate. + * @param [options.addAcceptedScopesHeader=true] {boolean=} Set the `X-Accepted-OAuth-Scopes` HTTP header on response objects. + * @param [options.addAuthorizedScopesHeader=true] {boolean=} Set the `X-OAuth-Scopes` HTTP header on response objects. + * @param [options.allowBearerTokensInQueryString=false] {boolean=} Allow clients to pass bearer tokens in the query string of a request. + * @throws {InvalidArgumentError} if {model} is missing or does not implement `getAccessToken` + */ + constructor(options) { options = options || {}; if (!options.model) { @@ -61,12 +61,12 @@ class AuthenticateHandler { } /** - * Handles the authentication - * @param request {Request} - * @param response {Response} - * @return {Promise<*>} - */ - async handle (request, response) { + * Handles the authentication + * @param request {Request} + * @param response {Response} + * @return {Promise<*>} + */ + async handle(request, response) { if (!(request instanceof Request)) { throw new InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); } @@ -120,7 +120,7 @@ class AuthenticateHandler { * @param {Request} * @see {https://tools.ietf.org/html/rfc6750#section-2} */ - getTokenFromRequest (request) { + getTokenFromRequest(request) { const headerToken = request.get('Authorization'); const queryToken = request.query.access_token; const bodyToken = request.body.access_token; @@ -151,7 +151,7 @@ class AuthenticateHandler { * @see {http://tools.ietf.org/html/rfc6750#section-2.1} */ - getTokenFromRequestHeader (request) { + getTokenFromRequestHeader(request) { const token = request.get('Authorization'); const matches = token.match(/^Bearer ([0-9a-zA-Z-._~+/]+=*)$/); @@ -177,7 +177,7 @@ class AuthenticateHandler { * @see http://tools.ietf.org/html/rfc6750#section-2.3 */ - getTokenFromRequestQuery (request) { + getTokenFromRequestQuery(request) { if (!this.allowBearerTokensInQueryString) { throw new InvalidRequestError('Invalid request: do not send bearer tokens in query URLs'); } @@ -194,7 +194,7 @@ class AuthenticateHandler { * @see http://tools.ietf.org/html/rfc6750#section-2.2 */ - getTokenFromRequestBody (request) { + getTokenFromRequestBody(request) { if (request.method === 'GET') { throw new InvalidRequestError('Invalid request: token may not be passed in the body when using the GET verb'); } @@ -211,7 +211,7 @@ class AuthenticateHandler { * @param token */ - async getAccessToken (token) { + async getAccessToken(token) { const accessToken = await this.model.getAccessToken(token); if (!accessToken) { @@ -229,7 +229,7 @@ class AuthenticateHandler { * Validate access token. */ - validateAccessToken (accessToken) { + validateAccessToken(accessToken) { if (!(accessToken.accessTokenExpiresAt instanceof Date)) { throw new ServerError('Server error: `accessTokenExpiresAt` must be a Date instance'); } @@ -245,7 +245,7 @@ class AuthenticateHandler { * Verify scope. */ - async verifyScope (accessToken) { + async verifyScope(accessToken) { const scope = await this.model.verifyScope(accessToken, this.scope); if (!scope) { @@ -257,7 +257,7 @@ class AuthenticateHandler { * Update response. */ - updateResponse (response, accessToken) { + updateResponse(response, accessToken) { if (accessToken.scope == null) { return; } diff --git a/lib/handlers/authorize-handler.js b/lib/handlers/authorize-handler.js index c5f0db17..34e3dcc6 100644 --- a/lib/handlers/authorize-handler.js +++ b/lib/handlers/authorize-handler.js @@ -27,7 +27,7 @@ const { parseScope } = require('../utils/scope-util'); */ const responseTypes = { - code: require('../response-types/code-response-type'), + code: require('../response-types/code-response-type') //token: require('../response-types/token-response-type') }; @@ -36,7 +36,7 @@ const responseTypes = { */ class AuthorizeHandler { - constructor (options) { + constructor(options) { options = options || {}; if (options.authenticateHandler && !options.authenticateHandler.handle) { @@ -70,7 +70,7 @@ class AuthorizeHandler { * Authorize Handler. */ - async handle (request, response) { + async handle(request, response) { if (!(request instanceof Request)) { throw new InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); } @@ -135,7 +135,7 @@ class AuthorizeHandler { * Generate authorization code. */ - async generateAuthorizationCode (client, user, scope) { + async generateAuthorizationCode(client, user, scope) { if (this.model.generateAuthorizationCode) { return this.model.generateAuthorizationCode(client, user, scope); } @@ -146,7 +146,7 @@ class AuthorizeHandler { * Get authorization code lifetime. */ - getAuthorizationCodeLifetime () { + getAuthorizationCodeLifetime() { const expires = new Date(); expires.setSeconds(expires.getSeconds() + this.authorizationCodeLifetime); @@ -157,7 +157,7 @@ class AuthorizeHandler { * Get the client from the model. */ - async getClient (request) { + async getClient(request) { const self = this; const clientId = request.body.client_id || request.query.client_id; @@ -207,7 +207,7 @@ class AuthorizeHandler { /** * Validate requested scope. */ - async validateScope (user, client, scope) { + async validateScope(user, client, scope) { if (this.model.validateScope) { const validatedScope = await this.model.validateScope(user, client, scope); @@ -225,7 +225,7 @@ class AuthorizeHandler { * Get scope from the request. */ - getScope (request) { + getScope(request) { const scope = request.body.scope || request.query.scope; return parseScope(scope); @@ -235,15 +235,13 @@ class AuthorizeHandler { * Get state from the request. */ - getState (request) { + getState(request) { const state = request.body.state || request.query.state; const stateExists = state && state.length > 0; - const stateIsValid = stateExists - ? isFormat.vschar(state) - : this.allowEmptyState; + const stateIsValid = stateExists ? isFormat.vschar(state) : this.allowEmptyState; if (!stateIsValid) { - const message = (!stateExists) ? 'Missing' : 'Invalid'; + const message = !stateExists ? 'Missing' : 'Invalid'; throw new InvalidRequestError(`${message} parameter: \`state\``); } @@ -254,12 +252,10 @@ class AuthorizeHandler { * Get user by calling the authenticate middleware. */ - async getUser (request, response) { + async getUser(request, response) { if (this.authenticateHandler instanceof AuthenticateHandler) { const handled = await this.authenticateHandler.handle(request, response); - return handled - ? handled.user - : undefined; + return handled ? handled.user : undefined; } const user = await this.authenticateHandler.handle(request, response); @@ -275,7 +271,7 @@ class AuthorizeHandler { * Get redirect URI. */ - getRedirectUri (request, client) { + getRedirectUri(request, client) { return request.body.redirect_uri || request.query.redirect_uri || client.redirectUris[0]; } @@ -283,7 +279,16 @@ class AuthorizeHandler { * Save authorization code. */ - async saveAuthorizationCode (authorizationCode, expiresAt, scope, client, redirectUri, user, codeChallenge, codeChallengeMethod) { + async saveAuthorizationCode( + authorizationCode, + expiresAt, + scope, + client, + redirectUri, + user, + codeChallenge, + codeChallengeMethod + ) { let code = { authorizationCode: authorizationCode, expiresAt: expiresAt, @@ -291,18 +296,20 @@ class AuthorizeHandler { scope: scope }; - if(codeChallenge && codeChallengeMethod){ - code = Object.assign({ - codeChallenge: codeChallenge, - codeChallengeMethod: codeChallengeMethod - }, code); + if (codeChallenge && codeChallengeMethod) { + code = Object.assign( + { + codeChallenge: codeChallenge, + codeChallengeMethod: codeChallengeMethod + }, + code + ); } return this.model.saveAuthorizationCode(code, client, user); } - - async validateRedirectUri (redirectUri, client) { + async validateRedirectUri(redirectUri, client) { if (this.model.validateRedirectUri) { return this.model.validateRedirectUri(redirectUri, client); } @@ -313,7 +320,7 @@ class AuthorizeHandler { * Get response type. */ - getResponseType (request) { + getResponseType(request) { const responseType = request.body.response_type || request.query.response_type; if (!responseType) { @@ -331,7 +338,7 @@ class AuthorizeHandler { * Build a successful response that redirects the user-agent to the client-provided url. */ - buildSuccessRedirectUri (redirectUri, responseType) { + buildSuccessRedirectUri(redirectUri, responseType) { return responseType.buildRedirectUri(redirectUri); } @@ -339,7 +346,7 @@ class AuthorizeHandler { * Build an error response that redirects the user-agent to the client-provided url. */ - buildErrorRedirectUri (redirectUri, error) { + buildErrorRedirectUri(redirectUri, error) { const uri = url.parse(redirectUri); uri.query = { @@ -357,7 +364,7 @@ class AuthorizeHandler { * Update response with the redirect uri and the state parameter, if available. */ - updateResponse (response, redirectUri, state) { + updateResponse(response, redirectUri, state) { redirectUri.query = redirectUri.query || {}; if (state) { @@ -367,7 +374,7 @@ class AuthorizeHandler { response.redirect(url.format(redirectUri)); } - getCodeChallenge (request) { + getCodeChallenge(request) { return request.body.code_challenge || request.query.code_challenge; } @@ -383,7 +390,7 @@ class AuthorizeHandler { * @throws {InvalidRequestError} if request contains unsupported code_challenge_method * (see https://www.rfc-editor.org/rfc/rfc7636#section-4.4) */ - getCodeChallengeMethod (request) { + getCodeChallengeMethod(request) { const algorithm = request.body.code_challenge_method || request.query.code_challenge_method; if (algorithm && !pkce.isValidMethod(algorithm)) { diff --git a/lib/handlers/token-handler.js b/lib/handlers/token-handler.js index 3b983072..d09fc256 100644 --- a/lib/handlers/token-handler.js +++ b/lib/handlers/token-handler.js @@ -35,7 +35,7 @@ const grantTypes = { */ class TokenHandler { - constructor (options) { + constructor(options) { options = options || {}; if (!options.accessTokenLifetime) { @@ -68,7 +68,7 @@ class TokenHandler { * Token Handler. */ - async handle (request, response) { + async handle(request, response) { if (!(request instanceof Request)) { throw new InvalidArgumentError('Invalid argument: `request` must be an instance of Request'); } @@ -88,7 +88,9 @@ class TokenHandler { try { const client = await this.getClient(request, response); const data = await this.handleGrantType(request, client); - const model = new TokenModel(data, { allowExtendedTokenAttributes: this.allowExtendedTokenAttributes }); + const model = new TokenModel(data, { + allowExtendedTokenAttributes: this.allowExtendedTokenAttributes + }); const tokenType = this.getTokenType(model); this.updateSuccessResponse(response, tokenType); @@ -110,7 +112,7 @@ class TokenHandler { * Get the client from the model. */ - async getClient (request, response) { + async getClient(request, response) { const credentials = await this.getClientCredentials(request); const grantType = request.body.grant_type; const codeVerifier = request.body.code_verifier; @@ -153,7 +155,7 @@ class TokenHandler { // attempted to authenticate via the "Authorization" request header. // // @see https://tools.ietf.org/html/rfc6749#section-5.2. - if ((e instanceof InvalidClientError) && request.get('authorization')) { + if (e instanceof InvalidClientError && request.get('authorization')) { response.set('WWW-Authenticate', 'Basic realm="Service"'); throw new InvalidClientError(e, { code: 401 }); } @@ -171,7 +173,7 @@ class TokenHandler { * @see https://tools.ietf.org/html/rfc6749#section-2.3.1 */ - getClientCredentials (request) { + getClientCredentials(request) { const credentials = auth(request); const grantType = request.body.grant_type; const codeVerifier = request.body.code_verifier; @@ -181,17 +183,20 @@ class TokenHandler { } if (request.body.client_id && request.body.client_secret) { - return { clientId: request.body.client_id, clientSecret: request.body.client_secret }; + return { + clientId: request.body.client_id, + clientSecret: request.body.client_secret + }; } if (pkce.isPKCERequest({ grantType, codeVerifier })) { - if(request.body.client_id) { + if (request.body.client_id) { return { clientId: request.body.client_id }; } } if (!this.isClientAuthenticationRequired(grantType)) { - if(request.body.client_id) { + if (request.body.client_id) { return { clientId: request.body.client_id }; } } @@ -203,7 +208,7 @@ class TokenHandler { * Handle grant type. */ - async handleGrantType (request, client) { + async handleGrantType(request, client) { const grantType = request.body.grant_type; if (!grantType) { @@ -241,7 +246,7 @@ class TokenHandler { * Get access token lifetime. */ - getAccessTokenLifetime (client) { + getAccessTokenLifetime(client) { return client.accessTokenLifetime || this.accessTokenLifetime; } @@ -249,7 +254,7 @@ class TokenHandler { * Get refresh token lifetime. */ - getRefreshTokenLifetime (client) { + getRefreshTokenLifetime(client) { return client.refreshTokenLifetime || this.refreshTokenLifetime; } @@ -257,15 +262,21 @@ class TokenHandler { * Get token type. */ - getTokenType (model) { - return new BearerTokenType(model.accessToken, model.accessTokenLifetime, model.refreshToken, model.scope, model.customAttributes); + getTokenType(model) { + return new BearerTokenType( + model.accessToken, + model.accessTokenLifetime, + model.refreshToken, + model.scope, + model.customAttributes + ); } /** * Update response when a token is generated. */ - updateSuccessResponse (response, tokenType) { + updateSuccessResponse(response, tokenType) { response.body = tokenType.valueOf(); // for compliance reasons we rebuild the internal scope to be a string @@ -282,7 +293,7 @@ class TokenHandler { * Update response when an error is thrown. */ - updateErrorResponse (response, error) { + updateErrorResponse(response, error) { response.body = { error: error.name, error_description: error.message @@ -294,9 +305,11 @@ class TokenHandler { /** * Given a grant type, check if client authentication is required */ - isClientAuthenticationRequired (grantType) { + isClientAuthenticationRequired(grantType) { if (Object.keys(this.requireClientAuthentication).length > 0) { - return (typeof this.requireClientAuthentication[grantType] !== 'undefined') ? this.requireClientAuthentication[grantType] : true; + return typeof this.requireClientAuthentication[grantType] !== 'undefined' + ? this.requireClientAuthentication[grantType] + : true; } else { return true; } diff --git a/lib/model.js b/lib/model.js index b426aa94..719124da 100644 --- a/lib/model.js +++ b/lib/model.js @@ -63,21 +63,20 @@ const ServerError = require('./errors/server-error'); * getClient: () => { ... } * }) */ -class Model { // eslint-disable-line no-unused-vars +class Model { + // eslint-disable-line no-unused-vars /** * Factory function to create a model form your implementation. * @static * @param impl {object} an object containing your model function implementations * @return {Model} the model instance. */ - static from (impl) { + static from(impl) { const m = new Model(); const nullFns = {}; - Object - .getOwnPropertyNames(Model.prototype) - .forEach((key) => { - nullFns[key] = null; - }); + Object.getOwnPropertyNames(Model.prototype).forEach((key) => { + nullFns[key] = null; + }); Object.assign(m, nullFns, impl); return m; } @@ -89,84 +88,84 @@ class Model { // eslint-disable-line no-unused-vars */ /** - * Invoked to retrieve a client using a client id or a client id/client secret combination, depending on the grant type. - * This model function is **required** for all grant types. - * **Invoked during:** - * - * - `authorization_code` grant - * - `client_credentials` grant - * - `refresh_token` grant - * - `password` grant - * - * - * @async - * @param clientId {string} The client id of the client to retrieve. - * @param clientSecret {string?} The client secret of the client to retrieve. Can be `null`. - * @returns {Promise.} - * @fulfil {ClientData} - An `Object` representing the client and associated data, or a falsy value if no such client could be found. - * @reject {Error} - An Error type - */ + * Invoked to retrieve a client using a client id or a client id/client secret combination, depending on the grant type. + * This model function is **required** for all grant types. + * **Invoked during:** + * + * - `authorization_code` grant + * - `client_credentials` grant + * - `refresh_token` grant + * - `password` grant + * + * + * @async + * @param clientId {string} The client id of the client to retrieve. + * @param clientSecret {string?} The client secret of the client to retrieve. Can be `null`. + * @returns {Promise.} + * @fulfil {ClientData} - An `Object` representing the client and associated data, or a falsy value if no such client could be found. + * @reject {Error} - An Error type + */ async getClient(clientId, clientSecret) { throw new ServerError('getClient not implemented'); } /** - * Invoked to save an access token and optionally a refresh token, depending on the grant type. - * This model function is **required** for all grant types. - * - * **Invoked during:** - * - `authorization_code` grant - * - `client_credentials` grant - * - `refresh_token` grant - * - `password` grant - * - * If the `allowExtendedTokenAttributes` server option is enabled (see `OAuth2Server#token() `) any additional attributes set on the result are copied to the token response sent to the client. - * - * @async - * @instance - * @param token {object} The token(s) to be saved. - * @param token.accessToken {string} The access token to be saved. - * @param token.accessTokenExpiresAt {Date} The expiry time of the access token. - * @param token.refreshToken {string} The refresh token to be saved. - * @param token.refreshTokenExpiresAt {Date} The expiry time of the refresh token. - * @param token.scope {string[]} The authorized scope of the token(s) - * @param client {ClientData} The client associated with the token(s). - * @param user {object} The user associated with the token(s). - * @return {Promise} + * Invoked to save an access token and optionally a refresh token, depending on the grant type. + * This model function is **required** for all grant types. + * + * **Invoked during:** + * - `authorization_code` grant + * - `client_credentials` grant + * - `refresh_token` grant + * - `password` grant + * + * If the `allowExtendedTokenAttributes` server option is enabled (see `OAuth2Server#token() `) any additional attributes set on the result are copied to the token response sent to the client. + * + * @async + * @instance + * @param token {object} The token(s) to be saved. + * @param token.accessToken {string} The access token to be saved. + * @param token.accessTokenExpiresAt {Date} The expiry time of the access token. + * @param token.refreshToken {string} The refresh token to be saved. + * @param token.refreshTokenExpiresAt {Date} The expiry time of the refresh token. + * @param token.scope {string[]} The authorized scope of the token(s) + * @param client {ClientData} The client associated with the token(s). + * @param user {object} The user associated with the token(s). + * @return {Promise} * @fulfil {{accessToken:string,accessTokenExpiresAt:Date,refreshToken: string,refreshTokenExpiresAt: Date,scope: string[],client: ClientData,user: object}} An `Object` representing the token(s) and associated data. - * @example - * function saveToken(token, client, user) { - * // imaginary DB queries - * let fns = [ - * db.saveAccessToken({ - * access_token: token.accessToken, - * expires_at: token.accessTokenExpiresAt, - * scope: token.scope, - * client_id: client.id, - * user_id: user.id - * }), - * db.saveRefreshToken({ - * refresh_token: token.refreshToken, - * expires_at: token.refreshTokenExpiresAt, - * scope: token.scope, - * client_id: client.id, - * user_id: user.id - * }) - * ]; - * return Promise.all(fns); - * .spread(function(accessToken, refreshToken) { - * return { - * accessToken: accessToken.access_token, - * accessTokenExpiresAt: accessToken.expires_at, - * refreshToken: refreshToken.refresh_token, - * refreshTokenExpiresAt: refreshToken.expires_at, - * scope: accessToken.scope, - * client: {id: accessToken.client_id}, - * user: {id: accessToken.user_id} - * }; - * }); - * } - */ + * @example + * function saveToken(token, client, user) { + * // imaginary DB queries + * let fns = [ + * db.saveAccessToken({ + * access_token: token.accessToken, + * expires_at: token.accessTokenExpiresAt, + * scope: token.scope, + * client_id: client.id, + * user_id: user.id + * }), + * db.saveRefreshToken({ + * refresh_token: token.refreshToken, + * expires_at: token.refreshTokenExpiresAt, + * scope: token.scope, + * client_id: client.id, + * user_id: user.id + * }) + * ]; + * return Promise.all(fns); + * .spread(function(accessToken, refreshToken) { + * return { + * accessToken: accessToken.access_token, + * accessTokenExpiresAt: accessToken.expires_at, + * refreshToken: refreshToken.refresh_token, + * refreshTokenExpiresAt: refreshToken.expires_at, + * scope: accessToken.scope, + * client: {id: accessToken.client_id}, + * user: {id: accessToken.user_id} + * }; + * }); + * } + */ async saveToken(token, client, user) { throw new ServerError('saveToken not implemented'); } @@ -179,51 +178,51 @@ class Model { // eslint-disable-line no-unused-vars */ /** - * Invoked to retrieve a user using a username/password combination. - * This model function is **required** if the `password` grant is used. - * Please note, that password grant is considered unsafe. - * It is still supported but marked deprecated. - * - * **Invoked during:** - * - `password` grant - * - * @deprecated - * @async - * @param username {string} The username of the user to retrieve. - * @param password {string} The user's password. - * @param client {ClientData=} The client. - * @return {Promise} An `Object` representing the user, or a falsy value if no such user could be found. The user object is completely transparent to *oauth2-server* and is simply used as input to other model functions. - * @example - * function getUser(username, password) { - * // imaginary DB query - * return db.queryUser({username: username, password: password}); - * } - */ + * Invoked to retrieve a user using a username/password combination. + * This model function is **required** if the `password` grant is used. + * Please note, that password grant is considered unsafe. + * It is still supported but marked deprecated. + * + * **Invoked during:** + * - `password` grant + * + * @deprecated + * @async + * @param username {string} The username of the user to retrieve. + * @param password {string} The user's password. + * @param client {ClientData=} The client. + * @return {Promise} An `Object` representing the user, or a falsy value if no such user could be found. The user object is completely transparent to *oauth2-server* and is simply used as input to other model functions. + * @example + * function getUser(username, password) { + * // imaginary DB query + * return db.queryUser({username: username, password: password}); + * } + */ async getUser(username, password, client) { throw new ServerError('getUser not implemented'); } /** - * Invoked to retrieve the user associated with the specified client. - * This model function is **required** if the `client_credentials` grant is used. - * - * **Invoked during:** - * - `client_credentials` grant - * - * **Remarks:** - * - * `client` is the object previously obtained through `Model#getClient() `. - * - * @async - * @instance - * @param client {ClientData} The client to retrieve the associated user for. - * @return {Promise} An `Object` representing the user, or a falsy value if the client does not have an associated user. The user object is completely transparent to *oauth2-server* and is simply used as input to other model functions. - * @example - * function getUserFromClient(client) { - * // imaginary DB query - * return db.queryUser({id: client.user_id}); - * } - */ + * Invoked to retrieve the user associated with the specified client. + * This model function is **required** if the `client_credentials` grant is used. + * + * **Invoked during:** + * - `client_credentials` grant + * + * **Remarks:** + * + * `client` is the object previously obtained through `Model#getClient() `. + * + * @async + * @instance + * @param client {ClientData} The client to retrieve the associated user for. + * @return {Promise} An `Object` representing the user, or a falsy value if the client does not have an associated user. The user object is completely transparent to *oauth2-server* and is simply used as input to other model functions. + * @example + * function getUserFromClient(client) { + * // imaginary DB query + * return db.queryUser({id: client.user_id}); + * } + */ async getUserFromClient(client) { throw new ServerError('getUserFromClient not implemented'); } @@ -416,20 +415,20 @@ class Model { // eslint-disable-line no-unused-vars } /** - * Invoked to revoke an authorization code. - * This model function is **required** if the `authorization_code` grant is used. - * - * **Invoked during:** - * - `authorization_code` grant - * - * **Remarks:** - * `code` is the authorization code object previously obtained through {@link Model#getAuthorizationCode}. - * - * @async - * @method - * @param code {AuthorizationCodeData} - * @return {Promise} Return `true` if the revocation was successful or `false` if the authorization code could not be found. - */ + * Invoked to revoke an authorization code. + * This model function is **required** if the `authorization_code` grant is used. + * + * **Invoked during:** + * - `authorization_code` grant + * + * **Remarks:** + * `code` is the authorization code object previously obtained through {@link Model#getAuthorizationCode}. + * + * @async + * @method + * @param code {AuthorizationCodeData} + * @return {Promise} Return `true` if the revocation was successful or `false` if the authorization code could not be found. + */ async revokeAuthorizationCode(code) { throw new ServerError('revokeAuthorizationCode not implemented'); } @@ -465,7 +464,6 @@ class Model { // eslint-disable-line no-unused-vars throw new ServerError('verifyScope not implemented'); } - /*------------------------------------------------------------------------- | OPTIONAL *------------------------------------------------------------------------- @@ -618,5 +616,4 @@ class Model { // eslint-disable-line no-unused-vars } } - -module.exports = Model; \ No newline at end of file +module.exports = Model; diff --git a/lib/models/token-model.js b/lib/models/token-model.js index ff24ae81..5bb4af7d 100644 --- a/lib/models/token-model.js +++ b/lib/models/token-model.js @@ -28,20 +28,12 @@ const modelAttributes = new Set([ */ class TokenModel { /** - * @constructor - * @param data - * @param options - */ + * @constructor + * @param data + * @param options + */ constructor(data = {}, options = {}) { - const { - accessToken, - accessTokenExpiresAt, - refreshToken, - refreshTokenExpiresAt, - scope, - client, - user, - } = data; + const { accessToken, accessTokenExpiresAt, refreshToken, refreshTokenExpiresAt, scope, client, user } = data; if (!accessToken) { throw new InvalidArgumentError('Missing parameter: `accessToken`'); @@ -80,7 +72,7 @@ class TokenModel { if (allowExtendedTokenAttributes) { this.customAttributes = {}; - Object.keys(data).forEach(key => { + Object.keys(data).forEach((key) => { if (!modelAttributes.has(key)) { this.customAttributes[key] = data[key]; } diff --git a/lib/pkce/pkce.js b/lib/pkce/pkce.js index f72bdca5..fc3941a4 100644 --- a/lib/pkce/pkce.js +++ b/lib/pkce/pkce.js @@ -21,7 +21,6 @@ const codeChallengeAndVerifierRegexp = /^([\u0041-\u005a\u0061-\u007A0-9.\-_~]){ * @module pkce */ - /** * Return hash for code-challenge method-type. * @@ -57,11 +56,10 @@ function getHashForCodeChallenge({ method, verifier }) { * @param codeChallenge {String} * @return {Boolean} */ -function codeChallengeMatchesABNF (codeChallenge) { +function codeChallengeMatchesABNF(codeChallenge) { return typeof codeChallenge === 'string' && codeChallengeAndVerifierRegexp.test(codeChallenge); } - /** * Check if the request is a PCKE request. We assume PKCE if grant type is * 'authorization_code' and code verifier is present. @@ -70,11 +68,10 @@ function codeChallengeMatchesABNF (codeChallenge) { * @param codeVerifier {String} * @return {boolean} */ -function isPKCERequest ({ grantType, codeVerifier }) { +function isPKCERequest({ grantType, codeVerifier }) { return grantType === 'authorization_code' && !!codeVerifier; } - /** * Checks if the code challenge method is one of the supported methods * 'sha256' or 'plain' @@ -82,7 +79,7 @@ function isPKCERequest ({ grantType, codeVerifier }) { * @param method {String} * @return {boolean} */ -function isValidMethod (method) { +function isValidMethod(method) { return method === 'S256' || method === 'plain'; } diff --git a/lib/request.js b/lib/request.js index f42960ca..c1cd37e8 100644 --- a/lib/request.js +++ b/lib/request.js @@ -20,15 +20,15 @@ const typeis = require('type-is'); */ class Request { /** - * Creates a new request instance - * @constructor - * @param headers {object} key-value object of headers - * @param method {string} the HTTP method - * @param query {object} key-value object of query parameters - * @param body {object=} optional key-value object of body parameters - * @param otherOptions {...object} any other properties that should be assigned to the request by your webserver - * @throws {InvalidArgumentError} if one of headers, method or query are missing. - */ + * Creates a new request instance + * @constructor + * @param headers {object} key-value object of headers + * @param method {string} the HTTP method + * @param query {object} key-value object of query parameters + * @param body {object=} optional key-value object of body parameters + * @param otherOptions {...object} any other properties that should be assigned to the request by your webserver + * @throws {InvalidArgumentError} if one of headers, method or query are missing. + */ constructor({ headers, method, query, body, ...otherOptions } = {}) { if (!headers) { throw new InvalidArgumentError('Missing parameter: `headers`'); diff --git a/lib/response-types/code-response-type.js b/lib/response-types/code-response-type.js index ccafdd22..d53770b7 100644 --- a/lib/response-types/code-response-type.js +++ b/lib/response-types/code-response-type.js @@ -13,10 +13,10 @@ const url = require('url'); */ class CodeResponseType { /** - * @constructor - * @param code - * @throws {InvalidArgumentError} if {code} is missing - */ + * @constructor + * @param code + * @throws {InvalidArgumentError} if {code} is missing + */ constructor(code) { if (!code) { throw new InvalidArgumentError('Missing parameter: `code`'); @@ -26,10 +26,10 @@ class CodeResponseType { } /** - * @param redirectUri - * @return {UrlWithParsedQuery} - * @throws {InvalidArgumentError} if redirectUri is missing - */ + * @param redirectUri + * @return {UrlWithParsedQuery} + * @throws {InvalidArgumentError} if redirectUri is missing + */ buildRedirectUri(redirectUri) { if (!redirectUri) { throw new InvalidArgumentError('Missing parameter: `redirectUri`'); diff --git a/lib/response-types/token-response-type.js b/lib/response-types/token-response-type.js index e06f9fc3..95196717 100644 --- a/lib/response-types/token-response-type.js +++ b/lib/response-types/token-response-type.js @@ -12,9 +12,9 @@ const ServerError = require('../errors/server-error'); */ class TokenResponseType { /** - * @constructor - * @throws {ServerError} not implemented yet - */ + * @constructor + * @throws {ServerError} not implemented yet + */ constructor() { throw new ServerError('Not implemented.'); } diff --git a/lib/response.js b/lib/response.js index 5afec5c8..41a47136 100644 --- a/lib/response.js +++ b/lib/response.js @@ -12,15 +12,14 @@ * } */ class Response { - /** - * Create a new Response instance. - * @constructor - * @param headers {object} key-value object of headers - * @param method {string} the HTTP method - * @param body {object=} optional key-value object of body parameters - * @param otherOptions {...object} any other properties that should be assigned to the request by your webserver - */ + * Create a new Response instance. + * @constructor + * @param headers {object} key-value object of headers + * @param method {string} the HTTP method + * @param body {object=} optional key-value object of body parameters + * @param otherOptions {...object} any other properties that should be assigned to the request by your webserver + */ constructor({ headers = {}, body = {}, ...otherOptions } = {}) { this.status = 200; this.body = body; diff --git a/lib/server.js b/lib/server.js index 320ddea7..10af1a8d 100644 --- a/lib/server.js +++ b/lib/server.js @@ -17,7 +17,6 @@ require('./model'); * const OAuth2Server = require('@node-oauth/oauth2-server'); */ class OAuth2Server { - /** * Instantiates `OAuth2Server` using the supplied model. * **Remarks:** @@ -61,7 +60,7 @@ class OAuth2Server { * accessTokenLifetime: 4 * 60 * 60 * }); */ - constructor (options) { + constructor(options) { options = options || {}; if (!options.model) { @@ -98,12 +97,16 @@ class OAuth2Server { * } * } */ - authenticate (request, response, options) { - options = Object.assign({ - addAcceptedScopesHeader: true, - addAuthorizedScopesHeader: true, - allowBearerTokensInQueryString: false - }, this.options, options); + authenticate(request, response, options) { + options = Object.assign( + { + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + allowBearerTokensInQueryString: false + }, + this.options, + options + ); return new AuthenticateHandler(options).handle(request, response); } @@ -163,11 +166,15 @@ class OAuth2Server { * } * } */ - authorize (request, response, options) { - options = Object.assign({ - allowEmptyState: false, - authorizationCodeLifetime: 5 * 60 // 5 minutes. - }, this.options, options); + authorize(request, response, options) { + options = Object.assign( + { + allowEmptyState: false, + authorizationCodeLifetime: 5 * 60 // 5 minutes. + }, + this.options, + options + ); return new AuthorizeHandler(options).handle(request, response); } @@ -224,13 +231,17 @@ class OAuth2Server { * } * } */ - token (request, response, options) { - options = Object.assign({ - accessTokenLifetime: 60 * 60, // 1 hour. - refreshTokenLifetime: 60 * 60 * 24 * 14, // 2 weeks. - allowExtendedTokenAttributes: false, - requireClientAuthentication: {} // defaults to true for all grant types - }, this.options, options); + token(request, response, options) { + options = Object.assign( + { + accessTokenLifetime: 60 * 60, // 1 hour. + refreshTokenLifetime: 60 * 60 * 24 * 14, // 2 weeks. + allowExtendedTokenAttributes: false, + requireClientAuthentication: {} // defaults to true for all grant types + }, + this.options, + options + ); return new TokenHandler(options).handle(request, response); } diff --git a/lib/token-types/bearer-token-type.js b/lib/token-types/bearer-token-type.js index 373d8731..6ffb474d 100644 --- a/lib/token-types/bearer-token-type.js +++ b/lib/token-types/bearer-token-type.js @@ -11,15 +11,14 @@ const InvalidArgumentError = require('../errors/invalid-argument-error'); * @classDesc */ class BearerTokenType { - /** - * @constructor - * @param accessToken - * @param accessTokenLifetime - * @param refreshToken - * @param scope - * @param customAttributes - */ + * @constructor + * @param accessToken + * @param accessTokenLifetime + * @param refreshToken + * @param scope + * @param customAttributes + */ constructor(accessToken, accessTokenLifetime, refreshToken, scope, customAttributes) { if (!accessToken) { throw new InvalidArgumentError('Missing parameter: `accessToken`'); @@ -36,10 +35,10 @@ class BearerTokenType { } /** - * Retrieve the value representation. - */ + * Retrieve the value representation. + */ - valueOf () { + valueOf() { const object = { access_token: this.accessToken, token_type: 'Bearer' @@ -58,7 +57,7 @@ class BearerTokenType { } for (const key in this.customAttributes) { - if ( Object.prototype.hasOwnProperty.call(this.customAttributes, key) ) { + if (Object.prototype.hasOwnProperty.call(this.customAttributes, key)) { object[key] = this.customAttributes[key]; } } diff --git a/lib/token-types/mac-token-type.js b/lib/token-types/mac-token-type.js index 02a90114..ce620c8b 100644 --- a/lib/token-types/mac-token-type.js +++ b/lib/token-types/mac-token-type.js @@ -8,10 +8,10 @@ const ServerError = require('../errors/server-error'); */ class MacTokenType { /** - * @constructor - * @throws {ServerError} not yet implemented - */ - constructor() { + * @constructor + * @throws {ServerError} not yet implemented + */ + constructor() { throw new ServerError('Not implemented.'); } } diff --git a/lib/utils/crypto-util.js b/lib/utils/crypto-util.js index d19942cc..6a3f7104 100644 --- a/lib/utils/crypto-util.js +++ b/lib/utils/crypto-util.js @@ -17,11 +17,8 @@ const crypto = require('crypto'); * @param output {'base64'|'base64url'|'binary'|'hex'|undefined} optional, the desired output type * @return {Buffer|string} if {output} is undefined, a {Buffer} is returned, otherwise a {String} */ -const createHash = function({ algorithm = 'sha256', data, output, encoding }) { - return crypto - .createHash(algorithm) - .update(data, encoding) - .digest(output); +const createHash = function ({ algorithm = 'sha256', data, output, encoding }) { + return crypto.createHash(algorithm).update(data, encoding).digest(output); }; module.exports = { createHash }; diff --git a/lib/utils/date-util.js b/lib/utils/date-util.js index 4fe32f97..6675a042 100644 --- a/lib/utils/date-util.js +++ b/lib/utils/date-util.js @@ -16,5 +16,5 @@ function getLifetimeFromExpiresAt(expiresAt) { } module.exports = { - getLifetimeFromExpiresAt, + getLifetimeFromExpiresAt }; diff --git a/lib/utils/scope-util.js b/lib/utils/scope-util.js index 5ed4bbd3..4cf98dff 100644 --- a/lib/utils/scope-util.js +++ b/lib/utils/scope-util.js @@ -17,7 +17,7 @@ const whiteSpace = /\s+/g; * @return {undefined|string[]} * @see {https://github.com/node-oauth/formats} */ -function parseScope (requestedScope) { +function parseScope(requestedScope) { if (requestedScope == null) { return undefined; } @@ -30,7 +30,7 @@ function parseScope (requestedScope) { // treated as valid nqchar by making them empty strings requestedScope = requestedScope.trim(); - if(!isFormat.nqschar(requestedScope)) { + if (!isFormat.nqschar(requestedScope)) { throw new InvalidScopeError('Invalid parameter: `scope`'); } diff --git a/lib/utils/string-util.js b/lib/utils/string-util.js index 2835b6d6..3d0f26e9 100644 --- a/lib/utils/string-util.js +++ b/lib/utils/string-util.js @@ -11,10 +11,7 @@ * @return {string} */ function base64URLEncode(str) { - return str.toString('base64') - .replace(/\+/g, '-') - .replace(/\//g, '_') - .replace(/=/g, ''); + return str.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, ''); } module.exports = { base64URLEncode }; diff --git a/package-lock.json b/package-lock.json index db300ba9..993dbc89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7 +1,7 @@ { "name": "@node-oauth/oauth2-server", "version": "5.3.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { @@ -14,39 +14,26 @@ "type-is": "2.1.0" }, "devDependencies": { + "@biomejs/biome": "2.5.0", "chai": "6.2.2", - "eslint": "8.57.1", "jsdoc-to-markdown": "^9.1.3", - "mocha": "11.7.5", + "mocha": "^11.7.6", "nyc": "18.0.0", - "sinon": "21.0.3", - "vitepress": "^2.0.0-alpha.15" + "sinon": "^22.0.0", + "vitepress": "^2.0.0-alpha.17" }, "engines": { "node": ">=16.0.0" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -55,30 +42,32 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -97,41 +86,46 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@babel/core/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, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.24.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -144,71 +138,45 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -217,35 +185,10 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -253,9 +196,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -263,35 +206,37 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -301,89 +246,246 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, "engines": { - "node": ">=4" + "node": ">=6.9.0" } }, - "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "node_modules/@biomejs/biome": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.0.tgz", + "integrity": "sha512-4kURkd9hAPrdDM3C9n82ycYgx8hvQcW6MjKTEejruj8rK0N8P3OPpdy8BvI8kt3KWY4ycF5XtDOrktetEfhfuw==", "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.5.0", + "@biomejs/cli-darwin-x64": "2.5.0", + "@biomejs/cli-linux-arm64": "2.5.0", + "@biomejs/cli-linux-arm64-musl": "2.5.0", + "@biomejs/cli-linux-x64": "2.5.0", + "@biomejs/cli-linux-x64-musl": "2.5.0", + "@biomejs/cli-win32-arm64": "2.5.0", + "@biomejs/cli-win32-x64": "2.5.0" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-Mn3Fwi3SA5fgmfCPqmzpWF2DLZnms3BVAhM088nTnGrTZmHS3wwIjcoZPqpXeNgd3DrrLH6xp8vTLIBuJoZiXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.0.tgz", + "integrity": "sha512-rg3VPL5P8mYro6pqlXYXuJWph21slVp3SZtAqWSrkZs40d2gTzYmHF8E/X1iTID25btmNKltNDJ926sqVBp7DQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.0.tgz", + "integrity": "sha512-tl+LW8fdD96/xdeWtWwc82LIOc5CoY7N2AsogLTp5R4ECErYt+8Jl/N68ezN9vzSiqPTxw6vjcihoLPYKZHrlw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-vQdM4oSGaf7ZNeGO9w5+Y8SBtyser9M6znxYbm7Ec8wInxJu1WiKxFYZW5Auj2d80bcVvefuGGRxoFOE0eee8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.0.tgz", + "integrity": "sha512-zpEGf4RQbFEh8Vt7OmavLyyOzRbtcE9osCqrS1kfvt8jDvxwhKXLSf7n0ebr/ov0RJ9ssP+lhs6C8a9WwFvrQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.0.tgz", + "integrity": "sha512-+9hIcMngJ+yGUahXqZuZ8CoWKJE9SAZsFsM3QDvXpNsLbXZ9lqVzgBhOk/jTSYkOA0GLP9eu3teukqpLUojHMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.0.tgz", + "integrity": "sha512-jB0wAvTLI4itx5VidqVUejPQFhRUxiZ9l9FvZ26D5fl6t3qme+ZB4PD3bTSeL1vZ8NI2Rx/zj6H9zcESuGHKGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.0.tgz", + "integrity": "sha512-VT/lF+GId+67j8aDfLkxdxNoVApsPSTbyAtB3jJq0IWTrY77WXfbPfpngxq0bA6JCEv/7k8C9qWjDRKRznDlyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" } }, "node_modules/@docsearch/css": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.5.3.tgz", - "integrity": "sha512-kUpHaxn0AgI3LQfyzTYkNUuaFY4uEz/Ym9/N/FvyDE+PzSgZsCyDH9jE49B6N6f1eLCm9Yp64J9wENd6vypdxA==", - "dev": true + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.6.3.tgz", + "integrity": "sha512-nlOwcXcsNAptQl4vlL4MA78qNJKO0Qlds5GuBjCoePgkebTXLSf8Qt1oyZ3YBshYupKXG9VRGEsk1zr23d+bzQ==", + "dev": true, + "license": "MIT" }, "node_modules/@docsearch/js": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-4.5.3.tgz", - "integrity": "sha512-rcBiUMCXbZLqrLIT6F6FDcrG/tyvM2WM0zum6NPbIiQNDQxbSgmNc+/bToS0rxBsXaxiU64esiWoS02WqrWLsg==", - "dev": true + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-4.6.3.tgz", + "integrity": "sha512-qUIX2b4Apew3tv4F0qhmgShsl/Lfw4m6mqv/5/5dWNxwTcDdLMp2s3YwZ+NMGh3IKCg0pBaXm7Q5VdyU5Rj+cQ==", + "dev": true, + "license": "MIT" }, "node_modules/@docsearch/sidepanel-js": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@docsearch/sidepanel-js/-/sidepanel-js-4.5.3.tgz", - "integrity": "sha512-DmcZYc1ZMMcabtKrCU2RIf1z09LwazKCyoPFU/ijJiBg2LdqMLmkyDKHGy1OIYEyUx4ok5RIbkVGaRfD55BqZQ==", - "dev": true + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/@docsearch/sidepanel-js/-/sidepanel-js-4.6.3.tgz", + "integrity": "sha512-grGSmvXzG0if+mrzdIKykvpIAuEQ9u0sEJ2eLRRCaQfJvsWqh2C2/aY04bIzWvDh7myi5rvl8D+tUNsVrjYQ3A==", + "dev": true, + "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -393,13 +495,14 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -409,13 +512,14 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -425,13 +529,14 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -441,13 +546,14 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -457,13 +563,14 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -473,13 +580,14 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -489,13 +597,14 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -505,13 +614,14 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -521,13 +631,14 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -537,13 +648,14 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -553,13 +665,14 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -569,13 +682,14 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -585,13 +699,14 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -601,13 +716,14 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -617,13 +733,14 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -633,13 +750,14 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -649,13 +767,14 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -665,13 +784,14 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -681,13 +801,14 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -697,13 +818,14 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -713,13 +835,14 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openharmony" @@ -729,13 +852,14 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -745,13 +869,14 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -761,13 +886,14 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -777,13 +903,14 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -792,102 +919,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==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", - "dev": true, - "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==", - "dev": true, - "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" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@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, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, "node_modules/@iconify-json/simple-icons": { - "version": "1.2.69", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.69.tgz", - "integrity": "sha512-T/rhy5n7pzE0ZOxQVlF68SNPCYYjRBpddjgjrJO5WWVRG8es5BQmvxIE9kKF+t2hhPGvuGQFpXmUyqbOtnxirQ==", + "version": "1.2.86", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.86.tgz", + "integrity": "sha512-t3jck5qPQuK1qy+bRn9eCoDQhIB7XSazKz1Fjp8hcan3XOAsTI5Mq/s3F0ekOKSvMQqkVORYK6ns6o6T9f5EMA==", "dev": true, + "license": "CC0-1.0", "dependencies": { "@iconify/types": "*" } @@ -896,13 +933,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", - "dev": true + "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", @@ -915,99 +954,21 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "engines": { - "node": ">=12" + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" }, - "funding": { - "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, - "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 - }, - "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, - "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/@isaacs/cliui/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/@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, - "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/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" + "engines": { + "node": ">=8" } }, "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { @@ -1015,6 +976,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -1024,6 +986,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -1037,6 +1000,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -1050,6 +1014,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -1062,6 +1027,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -1077,6 +1043,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -1084,36 +1051,36 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "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/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, - "engines": { - "node": ">=8" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -1121,15 +1088,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "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" } @@ -1142,23 +1101,24 @@ "license": "MIT" }, "node_modules/@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==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@jsdoc/salty": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", - "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.12.tgz", + "integrity": "sha512-TuB0x50EoAvEX/UEWITd8Mkn3WhiTjSvbTMCLj0BhsQEl5iUzjXdA0bETEVpTk+5TGTLR6QktI9H4hLviVeaAQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "lodash": "^4.17.21" + "lodash": "^4.18.1" }, "engines": { "node": ">=v12.0.0" @@ -1167,13 +1127,15 @@ "node_modules/@node-oauth/formats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@node-oauth/formats/-/formats-1.0.0.tgz", - "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA==" + "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA==", + "license": "MIT" }, "node_modules/@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, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1187,6 +1149,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" } @@ -1196,6 +1159,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" @@ -1209,408 +1173,442 @@ "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": ">=14" } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", - "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", + "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", + "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", + "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", + "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", + "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", + "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", + "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", + "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", + "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", + "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", + "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", + "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", + "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", + "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", + "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", + "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", + "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", + "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", + "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", + "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", + "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openharmony" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", + "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", + "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", + "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", + "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@shikijs/core": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.22.0.tgz", - "integrity": "sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.23.0.tgz", + "integrity": "sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.22.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4", "hast-util-to-html": "^9.0.5" } }, "node_modules/@shikijs/engine-javascript": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.22.0.tgz", - "integrity": "sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.23.0.tgz", + "integrity": "sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.22.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "oniguruma-to-es": "^4.3.4" } }, "node_modules/@shikijs/engine-oniguruma": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz", - "integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.22.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2" } }, "node_modules/@shikijs/langs": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz", - "integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.22.0" + "@shikijs/types": "3.23.0" } }, "node_modules/@shikijs/themes": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz", - "integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/types": "3.22.0" + "@shikijs/types": "3.23.0" } }, "node_modules/@shikijs/transformers": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-3.22.0.tgz", - "integrity": "sha512-E7eRV7mwDBjueLF6852n2oYeJYxBq3NSsDk+uyruYAXONv4U8holGmIrT+mPRJQ1J1SNOH6L8G19KRzmBawrFw==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-3.23.0.tgz", + "integrity": "sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/core": "3.22.0", - "@shikijs/types": "3.22.0" + "@shikijs/core": "3.23.0", + "@shikijs/types": "3.23.0" } }, "node_modules/@shikijs/types": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz", - "integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", "dev": true, + "license": "MIT", "dependencies": { "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" @@ -1620,31 +1618,35 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", - "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.4.0.tgz", + "integrity": "sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" } }, "node_modules/@sinonjs/samsam": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz", - "integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==", + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-10.0.2.tgz", + "integrity": "sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", "type-detect": "^4.1.0" @@ -1655,21 +1657,24 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" }, "node_modules/@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, + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -1697,6 +1702,7 @@ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "*" } @@ -1712,27 +1718,31 @@ "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 + "dev": true, + "license": "MIT" }, "node_modules/@types/web-bluetooth": { "version": "0.0.21", "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", + "integrity": "sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==", + "dev": true, + "license": "ISC" }, "node_modules/@vitejs/plugin-vue": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", - "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.7.tgz", + "integrity": "sha512-km+p+XdSz9Sxm5rqUbqcSfZYaAniKxWBj1KURl+Jr7UaPvvX7BmaWMdP69I5rrFDeQGyxAG7NXdc57vz+snhWg==", "dev": true, + "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "1.0.0-rc.2" + "@rolldown/pluginutils": "^1.0.1" }, "engines": { "node": "^20.19.0 || >=22.12.0" @@ -1743,150 +1753,167 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", - "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/@vue/compiler-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", - "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", - "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.30", - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.15", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", - "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/devtools-api": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.5.tgz", - "integrity": "sha512-DgVcW8H/Nral7LgZEecYFFYXnAvGuN9C3L3DtWekAncFBedBczpNW8iHKExfaM559Zm8wQWrwtYZ9lXthEHtDw==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.1.3.tgz", + "integrity": "sha512-73NMCvxXh8Hyozc/jiwqTFWVcCMyi11U1zmrq4DoukQJnuo8JHt6FsNu4HdeUDa8SpIp5vb7Q22GWgIq0efsXg==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-kit": "^8.0.5" + "@vue/devtools-kit": "^8.1.3" } }, "node_modules/@vue/devtools-kit": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.5.tgz", - "integrity": "sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.1.3.tgz", + "integrity": "sha512-cRn7GXiCQkMYU2Z3h3pM4YO/ndbx9FY1yLDAqIqPLcmIq4H6zAOJHein6tvZU3AfPwgrodqLiPBEF+YQaS8AxA==", "dev": true, "license": "MIT", "dependencies": { - "@vue/devtools-shared": "^8.0.5", + "@vue/devtools-shared": "^8.1.3", "birpc": "^2.6.1", "hookable": "^5.5.3", - "mitt": "^3.0.1", - "perfect-debounce": "^2.0.0", - "speakingurl": "^14.0.1", - "superjson": "^2.2.2" + "perfect-debounce": "^2.0.0" } }, "node_modules/@vue/devtools-shared": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.5.tgz", - "integrity": "sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.1.3.tgz", + "integrity": "sha512-CM3uIPL+v+lrJUk33+pxspYo0MhuMWlCvf7zC9fybifvCPyM2jUbYRPwoYEJgYbwRqPikm5HozbUhp60MF2QuA==", "dev": true, - "license": "MIT", - "dependencies": { - "rfdc": "^1.4.1" - } + "license": "MIT" }, "node_modules/@vue/reactivity": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", - "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/shared": "3.5.30" + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", - "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", - "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", + "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/runtime-core": "3.5.30", - "@vue/shared": "3.5.30", + "@vue/reactivity": "3.5.38", + "@vue/runtime-core": "3.5.38", + "@vue/shared": "3.5.38", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", - "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", + "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { - "vue": "3.5.30" + "vue": "3.5.38" } }, "node_modules/@vue/shared": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", - "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", - "dev": true + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "dev": true, + "license": "MIT" }, "node_modules/@vueuse/core": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz", - "integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.3.0.tgz", + "integrity": "sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==", "dev": true, + "license": "MIT", "dependencies": { "@types/web-bluetooth": "^0.0.21", - "@vueuse/metadata": "14.2.1", - "@vueuse/shared": "14.2.1" + "@vueuse/metadata": "14.3.0", + "@vueuse/shared": "14.3.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -1896,13 +1923,14 @@ } }, "node_modules/@vueuse/integrations": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-14.2.1.tgz", - "integrity": "sha512-2LIUpBi/67PoXJGqSDQUF0pgQWpNHh7beiA+KG2AbybcNm+pTGWT6oPGlBgUoDWmYwfeQqM/uzOHqcILpKL7nA==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-14.3.0.tgz", + "integrity": "sha512-76I5FT2ESvCmCaSwapI+a/u/CFtNXmzl9f9lNp1hRtx8vKB8hfiokJr8IvQqcQG5ckGXElyXK516b54ozV3MvA==", "dev": true, + "license": "MIT", "dependencies": { - "@vueuse/core": "14.2.1", - "@vueuse/shared": "14.2.1" + "@vueuse/core": "14.3.0", + "@vueuse/shared": "14.3.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -1962,19 +1990,21 @@ } }, "node_modules/@vueuse/metadata": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.2.1.tgz", - "integrity": "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.3.0.tgz", + "integrity": "sha512-BwxmbAzwAVF50+MW57GXOUEV61nFBGnlBvrTqj49PqWJu3uw7hdu72ztXeZ33RdZtDY6kO+bfCAE1PCn88Tktw==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/shared": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.2.1.tgz", - "integrity": "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==", + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.3.0.tgz", + "integrity": "sha512-bZpge9eSXwa4ToSiqJ7j6KRwhAsneMFoSz3LMWKQDkqimm3D/tbFlrklrs/IOqC8tEcYmXQZJ6N0UrjhBirVCg==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/antfu" }, @@ -1982,32 +2012,12 @@ "vue": "^3.5.0" } }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/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, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^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, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -2016,29 +2026,17 @@ "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==", - "dev": true, - "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/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -2046,6 +2044,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" }, @@ -2061,6 +2060,7 @@ "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", "dev": true, + "license": "MIT", "dependencies": { "default-require-extensions": "^3.0.0" }, @@ -2072,18 +2072,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true + "dev": true, + "license": "MIT" }, "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 + "dev": true, + "license": "Python-2.0" }, "node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.3.tgz", + "integrity": "sha512-SGDvmg6QTYiTxCBkYVmThcoa67uLl35pyzRHdpCGBOcqFy6BtwnphoFPk7LhJshD+Yk1Kt35WGWeZPTgwR4Fhw==", "dev": true, "license": "MIT", "engines": { @@ -2094,12 +2096,27 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.37", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.37.tgz", + "integrity": "sha512-girxaJ7WZssDOFhzCGZTDKoTa1gk6A1TbflaYTpykLJ4UU9Fz9kx1aREM8JCuoVHbL8X8T/mJg7w2oYSq72Oig==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -2125,13 +2142,13 @@ "license": "MIT" }, "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.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, + "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -2151,12 +2168,13 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", "dev": true, "funding": [ { @@ -2172,11 +2190,13 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" + "baseline-browser-mapping": "^2.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" }, "bin": { "browserslist": "cli.js" @@ -2211,6 +2231,7 @@ "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", "dev": true, + "license": "MIT", "dependencies": { "hasha": "^5.0.0", "make-dir": "^3.0.0", @@ -2221,28 +2242,20 @@ "node": ">=8" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", + "version": "1.0.30001799", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", + "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", "dev": true, "funding": [ { @@ -2257,7 +2270,8 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/catharsis": { "version": "0.9.0", @@ -2277,6 +2291,7 @@ "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2287,6 +2302,7 @@ "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" } @@ -2296,6 +2312,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" @@ -2328,6 +2345,7 @@ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2338,6 +2356,7 @@ "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": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -2364,6 +2383,7 @@ "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2383,11 +2403,75 @@ "node": ">=12" } }, + "node_modules/cliui/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" + } + }, + "node_modules/cliui/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, + "license": "MIT" + }, + "node_modules/cliui/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", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/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, + "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" + } + }, "node_modules/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, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2399,29 +2483,31 @@ "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/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/command-line-args": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", - "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.2.tgz", + "integrity": "sha512-AIjYVxrV9X752LmPDLbVYv8aMCuHPSLZJXEo2qo/xJfv+NYhaZ4sMSF01rM+gHPaMgvPM0l5D/F+Qx+i2WfSmQ==", "dev": true, "license": "MIT", "dependencies": { - "array-back": "^6.2.2", + "array-back": "^6.2.3", "find-replace": "^5.0.2", "lodash.camelcase": "^4.3.0", - "typical": "^7.2.0" + "typical": "^7.3.0" }, "engines": { "node": ">=12.20" @@ -2436,16 +2522,16 @@ } }, "node_modules/command-line-usage": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", - "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.4.tgz", + "integrity": "sha512-85UdvzTNx/+s5CkSgBm/0hzP80RFHAa7PsfeADE5ezZF3uHz3/Tqj9gIKGT9PTtpycc3Ua64T0oVulGfKxzfqg==", "dev": true, "license": "MIT", "dependencies": { "array-back": "^6.2.2", "chalk-template": "^0.4.0", - "table-layout": "^4.1.0", - "typical": "^7.1.1" + "table-layout": "^4.1.1", + "typical": "^7.3.0" }, "engines": { "node": ">=12.20.0" @@ -2465,13 +2551,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "dev": true - }, - "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 + "dev": true, + "license": "MIT" }, "node_modules/config-master": { "version": "3.1.0", @@ -2497,6 +2578,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", "engines": { "node": ">=18" }, @@ -2509,23 +2591,8 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/copy-anything": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", - "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", "dev": true, - "license": "MIT", - "dependencies": { - "is-what": "^5.2.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -2546,7 +2613,8 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/current-module-paths": { "version": "1.1.3", @@ -2559,12 +2627,13 @@ } }, "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.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2580,21 +2649,17 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.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/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", "dev": true, + "license": "MIT", "dependencies": { "strip-bom": "^4.0.0" }, @@ -2610,6 +2675,7 @@ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -2619,6 +2685,7 @@ "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", "dev": true, + "license": "MIT", "dependencies": { "dequal": "^2.0.0" }, @@ -2664,54 +2731,33 @@ } } }, - "node_modules/dmd/node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "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 + "dev": true, + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.0.tgz", - "integrity": "sha512-Vb3xHHYnLseK8vlMJQKJYXJ++t4u1/qJ3vykuVrVjvdiOEhYyT1AuP4x03G8EnPmYvYOhe9T+dADTmthjRQMkA==", - "dev": true + "version": "1.5.375", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz", + "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", + "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 + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" }, "node_modules/entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "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.12" }, @@ -2723,14 +2769,16 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/esbuild": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -2738,153 +2786,52 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.4", - "@esbuild/android-arm": "0.27.4", - "@esbuild/android-arm64": "0.27.4", - "@esbuild/android-x64": "0.27.4", - "@esbuild/darwin-arm64": "0.27.4", - "@esbuild/darwin-x64": "0.27.4", - "@esbuild/freebsd-arm64": "0.27.4", - "@esbuild/freebsd-x64": "0.27.4", - "@esbuild/linux-arm": "0.27.4", - "@esbuild/linux-arm64": "0.27.4", - "@esbuild/linux-ia32": "0.27.4", - "@esbuild/linux-loong64": "0.27.4", - "@esbuild/linux-mips64el": "0.27.4", - "@esbuild/linux-ppc64": "0.27.4", - "@esbuild/linux-riscv64": "0.27.4", - "@esbuild/linux-s390x": "0.27.4", - "@esbuild/linux-x64": "0.27.4", - "@esbuild/netbsd-arm64": "0.27.4", - "@esbuild/netbsd-x64": "0.27.4", - "@esbuild/openbsd-arm64": "0.27.4", - "@esbuild/openbsd-x64": "0.27.4", - "@esbuild/openharmony-arm64": "0.27.4", - "@esbuild/sunos-x64": "0.27.4", - "@esbuild/win32-arm64": "0.27.4", - "@esbuild/win32-ia32": "0.27.4", - "@esbuild/win32-x64": "0.27.4" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "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": ">=6" } }, "node_modules/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, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@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" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "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==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/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, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "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": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=8" } }, "node_modules/esprima": { @@ -2892,6 +2839,7 @@ "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" @@ -2900,59 +2848,12 @@ "node": ">=4" } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/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, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/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 - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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==", - "dev": true + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.3", @@ -2971,69 +2872,16 @@ "node": ">=8.6.0" } }, - "node_modules/fast-glob/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==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "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==", - "dev": true - }, - "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/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": 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==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, "node_modules/file-set": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.3.0.tgz", @@ -3074,6 +2922,7 @@ "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", "dev": true, + "license": "MIT", "dependencies": { "commondir": "^1.0.1", "make-dir": "^3.0.2", @@ -3109,6 +2958,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" @@ -3125,50 +2975,36 @@ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true, + "license": "BSD-3-Clause", "bin": { "flat": "cli.js" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/focus-trap": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-8.0.0.tgz", - "integrity": "sha512-Aa84FOGHs99vVwufDMdq2qgOwXPC2e9U66GcqBhn1/jEHPDhJaP8PYhkIbqG9lhfL5Kddk/567lj46LLHYCRUw==", + "node_modules/focus-trap": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-8.2.1.tgz", + "integrity": "sha512-6CxwrrFRquH7pDXb1mWxudkU9LSfYBMRZutpgddb2o6iwCk7cIRrBhyY3c8SGKcmIKdeMTrGSNg4Bedh2RSF/w==", "dev": true, + "license": "MIT", "dependencies": { "tabbable": "^6.4.0" } }, "node_modules/foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "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", - "signal-exit": "^3.0.2" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/fromentries": { @@ -3189,13 +3025,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] - }, - "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 + ], + "license": "MIT" }, "node_modules/fsevents": { "version": "2.3.3", @@ -3203,6 +3034,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -3216,6 +3048,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -3225,6 +3058,7 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -3234,6 +3068,7 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -3242,7 +3077,9 @@ "version": "10.5.0", "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -3259,101 +3096,31 @@ } }, "node_modules/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, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/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, - "engines": { - "node": ">=14" - }, - "funding": { - "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==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6" } }, "node_modules/graceful-fs": { "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 - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/handlebars": { "version": "4.7.9", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", @@ -3375,6 +3142,7 @@ "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" } @@ -3384,6 +3152,7 @@ "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", "dev": true, + "license": "MIT", "dependencies": { "is-stream": "^2.0.0", "type-fest": "^0.8.0" @@ -3395,20 +3164,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/hasha/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "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", @@ -3432,6 +3193,7 @@ "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, + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0" }, @@ -3445,6 +3207,7 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true, + "license": "MIT", "bin": { "he": "bin/he" } @@ -3460,48 +3223,26 @@ "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/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/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "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==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "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" } @@ -3511,32 +3252,17 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "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, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "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/is-extglob": { "version": "2.1.1", "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" } @@ -3546,6 +3272,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" } @@ -3555,6 +3282,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" }, @@ -3577,6 +3305,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3586,6 +3315,7 @@ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3595,6 +3325,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -3606,13 +3337,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -3620,24 +3353,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-what": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", - "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/mesqueeb" - } - }, "node_modules/is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3646,13 +3367,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "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" } @@ -3662,6 +3385,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "append-transform": "^2.0.0" }, @@ -3674,6 +3398,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -3686,117 +3411,20 @@ } }, "node_modules/istanbul-lib-processinfo": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-3.0.0.tgz", - "integrity": "sha512-P7nLXRRlo7Sqinty6lNa7+4o9jBUYGpqtejqCOZKfgXlRoxY/QArflcB86YO500Ahj4pDJEG34JjMRbQgePLnQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-3.0.1.tgz", + "integrity": "sha512-s3mX05h5wGZeScG6XnOanygPh4SJu5ujMc9YbvpnLGXWy1cRiGbp0NdVcjHxgoZt3WfQppfBsa0y+gWdYJ2pGQ==", "dev": true, + "license": "ISC", "dependencies": { "archy": "^1.0.0", "cross-spawn": "^7.0.3", "istanbul-lib-coverage": "^3.2.0", "p-map": "^3.0.0", - "rimraf": "^6.1.3", - "uuid": "^8.3.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "dependencies": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" + "rimraf": "^6.1.3" }, "engines": { "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/istanbul-lib-report": { @@ -3804,6 +3432,7 @@ "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", @@ -3818,6 +3447,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" }, @@ -3833,6 +3463,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -3843,10 +3474,11 @@ } }, "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==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -3860,6 +3492,7 @@ "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" }, @@ -3878,15 +3511,26 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", + "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/js2xmlparser": { @@ -3930,19 +3574,19 @@ } }, "node_modules/jsdoc-api": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.5.tgz", - "integrity": "sha512-TQwh1jA8xtCkIbVwm/XA3vDRAa5JjydyKx1cC413Sh3WohDFxcMdwKSvn4LOsq2xWyAmOU/VnSChTQf6EF0R8g==", + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.6.tgz", + "integrity": "sha512-8JW0532+rXVw8LoZ1LIAeKofsV8QQZhnY3chxMHV9hQdsuDTshsajwk0b4EMxCqen2vZ2op/r/qeEsqZxsEQyg==", "dev": true, "license": "MIT", "dependencies": { - "array-back": "^6.2.2", + "array-back": "^6.2.3", "cache-point": "^3.0.1", - "current-module-paths": "^1.1.2", + "current-module-paths": "^1.1.3", "file-set": "^5.3.0", - "jsdoc": "^4.0.4", + "jsdoc": "^4.0.5", "object-to-spawn-args": "^2.0.1", - "walk-back": "^5.1.1" + "walk-back": "^5.1.2" }, "engines": { "node": ">=12.17" @@ -4002,64 +3646,25 @@ } } }, - "node_modules/jsdoc/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/jsdoc/node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "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": ">=4" + "node": ">=6" } }, - "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-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 - }, - "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 - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -4067,15 +3672,6 @@ "node": ">=6" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/klaw": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", @@ -4086,24 +3682,21 @@ "graceful-fs": "^4.1.9" } }, - "node_modules/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, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { "uc.micro": "^2.0.0" @@ -4114,6 +3707,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" }, @@ -4125,10 +3719,11 @@ } }, "node_modules/lodash": { - "version": "4.17.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", - "dev": true + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" }, "node_modules/lodash.camelcase": { "version": "4.3.0", @@ -4141,19 +3736,15 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "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 + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -4170,6 +3761,7 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } @@ -4179,6 +3771,7 @@ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } @@ -4188,6 +3781,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -4203,6 +3797,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -4215,15 +3810,25 @@ "license": "MIT" }, "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], "license": "MIT", "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", - "linkify-it": "^5.0.0", + "linkify-it": "^5.0.1", "mdurl": "^2.0.0", "punycode.js": "^2.3.1", "uc.micro": "^2.1.0" @@ -4243,17 +3848,17 @@ "markdown-it": "*" } }, - "node_modules/markdown-it/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/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" + "license": "MIT", + "bin": { + "marked": "bin/marked.js" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "engines": { + "node": ">= 12" } }, "node_modules/mdast-util-to-hast": { @@ -4261,6 +3866,7 @@ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "dev": true, + "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", @@ -4318,6 +3924,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" @@ -4337,7 +3944,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-sanitize-uri": { "version": "2.0.1", @@ -4354,6 +3962,7 @@ "url": "https://opencollective.com/unified" } ], + "license": "MIT", "dependencies": { "micromark-util-character": "^2.0.0", "micromark-util-encode": "^2.0.0", @@ -4374,7 +3983,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromark-util-types": { "version": "2.0.2", @@ -4390,7 +4000,8 @@ "type": "OpenCollective", "url": "https://opencollective.com/unified" } - ] + ], + "license": "MIT" }, "node_modules/micromatch": { "version": "4.0.8", @@ -4406,19 +4017,6 @@ "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -4429,27 +4027,35 @@ } }, "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "license": "MIT", "dependencies": { "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.2" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -4467,6 +4073,7 @@ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": ">=16 || 14 >=14.17" } @@ -4478,13 +4085,6 @@ "dev": true, "license": "MIT" }, - "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, - "license": "MIT" - }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -4499,10 +4099,11 @@ } }, "node_modules/mocha": { - "version": "11.7.5", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", - "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", + "version": "11.7.6", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.6.tgz", + "integrity": "sha512-nS9xOGbw2I3cjCpxwZAEJ9xK9lmJ08vEkQvLtz4du9ZrF9UrjRpeJGiIgl2Z+Qs++pmB4ecDe48Fwsh+j+j7xA==", "dev": true, + "license": "MIT", "dependencies": { "browser-stdout": "^1.3.1", "chokidar": "^4.0.1", @@ -4534,42 +4135,25 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "node_modules/mocha/node_modules/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, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.2" - }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mocha/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 - }, "node_modules/mocha/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -4581,15 +4165,16 @@ } }, "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==", - "dev": true + "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/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "dev": true, "funding": [ { @@ -4597,6 +4182,7 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -4604,12 +4190,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "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/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -4622,6 +4202,7 @@ "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", "dev": true, + "license": "MIT", "dependencies": { "process-on-spawn": "^1.0.0" }, @@ -4630,16 +4211,21 @@ } }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true + "version": "2.0.47", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.47.tgz", + "integrity": "sha512-Uzmd6LXpouKo8EUK68IjH4+E01w/hXyV3R3g/geCJo+rXLNfh1xucB+LOzYEOQPSiUK3h/xZf0cQGcSsmyL2Og==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/nyc": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/nyc/-/nyc-18.0.0.tgz", "integrity": "sha512-G5UyHinFkB1BxqGTrmZdB6uIYH0+v7ZnVssuflUDi+J+RhKWyAhRT1RCehBSI6jLFLuUUgFDyLt49mUtdO1XeQ==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", @@ -4676,20 +4262,32 @@ "node": "20 || >=22" } }, + "node_modules/nyc/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" + } + }, "node_modules/nyc/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, + "license": "MIT", "engines": { "node": "18 || 20 || >=22" } }, "node_modules/nyc/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, @@ -4702,17 +4300,26 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, + "node_modules/nyc/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, + "license": "MIT" + }, "node_modules/nyc/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4721,39 +4328,12 @@ "node": ">=8" } }, - "node_modules/nyc/node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/nyc/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==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/nyc/node_modules/glob": { "version": "13.0.6", "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", @@ -4771,6 +4351,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -4779,21 +4360,23 @@ } }, "node_modules/nyc/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/nyc/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -4807,6 +4390,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -4822,6 +4406,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -4834,6 +4419,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" @@ -4845,32 +4431,39 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/nyc/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==", + "node_modules/nyc/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, + "license": "ISC" + }, + "node_modules/nyc/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", + "strip-ansi": "^6.0.1" + }, "engines": { "node": ">=8" } }, - "node_modules/nyc/node_modules/rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", + "node_modules/nyc/node_modules/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, + "license": "MIT", "dependencies": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" + "ansi-regex": "^5.0.1" }, "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=8" } }, "node_modules/nyc/node_modules/wrap-ansi": { @@ -4878,6 +4471,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -4891,13 +4485,15 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/nyc/node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -4920,6 +4516,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -4938,54 +4535,31 @@ "node": ">=8.0.0" } }, - "node_modules/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, - "dependencies": { - "wrappy": "1" - } - }, "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 + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.2.tgz", + "integrity": "sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==", + "dev": true, + "license": "MIT" }, "node_modules/oniguruma-to-es": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", - "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.6.tgz", + "integrity": "sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==", "dev": true, + "license": "MIT", "dependencies": { - "oniguruma-parser": "^0.12.1", - "regex": "^6.0.1", + "oniguruma-parser": "^0.12.2", + "regex": "^6.1.0", "regex-recursion": "^6.0.2" } }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "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" }, @@ -5001,6 +4575,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" }, @@ -5016,6 +4591,7 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -5028,6 +4604,7 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5037,6 +4614,7 @@ "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", "dev": true, + "license": "ISC", "dependencies": { "graceful-fs": "^4.1.15", "hasha": "^5.0.0", @@ -5051,43 +4629,25 @@ "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 - }, - "node_modules/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, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } + "license": "BlueOak-1.0.0" }, "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" } }, - "node_modules/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, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/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, + "license": "MIT", "engines": { "node": ">=8" } @@ -5097,6 +4657,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -5112,12 +4673,13 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/perfect-debounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", - "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", "dev": true, "license": "MIT" }, @@ -5129,12 +4691,13 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -5145,6 +4708,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -5157,6 +4721,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -5170,6 +4735,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -5182,6 +4748,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -5197,6 +4764,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -5205,9 +4773,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "dev": true, "funding": [ { @@ -5223,8 +4791,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -5232,20 +4801,12 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/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, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", "dev": true, + "license": "MIT", "dependencies": { "fromentries": "^1.2.0" }, @@ -5254,24 +4815,16 @@ } }, "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==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.2.0.tgz", + "integrity": "sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/punycode.js": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", @@ -5300,13 +4853,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -5330,6 +4885,7 @@ "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", "dev": true, + "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" } @@ -5339,6 +4895,7 @@ "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", "dev": true, + "license": "MIT", "dependencies": { "regex-utilities": "^2.3.0" } @@ -5347,13 +4904,15 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", "dev": true, + "license": "ISC", "dependencies": { "es6-error": "^4.0.1" }, @@ -5366,6 +4925,7 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5374,7 +4934,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/requizzle": { "version": "0.2.4", @@ -5387,75 +4948,138 @@ } }, "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==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "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==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", + "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "glob": "^7.1.3" + "glob": "^13.0.3", + "package-json-from-dist": "^1.0.1" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/rimraf/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", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, + "license": "BlueOak-1.0.0", "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" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "version": "4.62.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", + "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -5465,31 +5089,31 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", + "@rollup/rollup-android-arm-eabi": "4.62.0", + "@rollup/rollup-android-arm64": "4.62.0", + "@rollup/rollup-darwin-arm64": "4.62.0", + "@rollup/rollup-darwin-x64": "4.62.0", + "@rollup/rollup-freebsd-arm64": "4.62.0", + "@rollup/rollup-freebsd-x64": "4.62.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", + "@rollup/rollup-linux-arm-musleabihf": "4.62.0", + "@rollup/rollup-linux-arm64-gnu": "4.62.0", + "@rollup/rollup-linux-arm64-musl": "4.62.0", + "@rollup/rollup-linux-loong64-gnu": "4.62.0", + "@rollup/rollup-linux-loong64-musl": "4.62.0", + "@rollup/rollup-linux-ppc64-gnu": "4.62.0", + "@rollup/rollup-linux-ppc64-musl": "4.62.0", + "@rollup/rollup-linux-riscv64-gnu": "4.62.0", + "@rollup/rollup-linux-riscv64-musl": "4.62.0", + "@rollup/rollup-linux-s390x-gnu": "4.62.0", + "@rollup/rollup-linux-x64-gnu": "4.62.0", + "@rollup/rollup-linux-x64-musl": "4.62.0", + "@rollup/rollup-openbsd-x64": "4.62.0", + "@rollup/rollup-openharmony-arm64": "4.62.0", + "@rollup/rollup-win32-arm64-msvc": "4.62.0", + "@rollup/rollup-win32-ia32-msvc": "4.62.0", + "@rollup/rollup-win32-x64-gnu": "4.62.0", + "@rollup/rollup-win32-x64-msvc": "4.62.0", "fsevents": "~2.3.2" } }, @@ -5512,6 +5136,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -5519,13 +5144,15 @@ "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==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -5538,6 +5165,7 @@ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -5546,13 +5174,15 @@ "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 + "dev": true, + "license": "ISC" }, "node_modules/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, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -5565,43 +5195,52 @@ "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" } }, "node_modules/shiki": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.22.0.tgz", - "integrity": "sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.23.0.tgz", + "integrity": "sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==", "dev": true, + "license": "MIT", "dependencies": { - "@shikijs/core": "3.22.0", - "@shikijs/engine-javascript": "3.22.0", - "@shikijs/engine-oniguruma": "3.22.0", - "@shikijs/langs": "3.22.0", - "@shikijs/themes": "3.22.0", - "@shikijs/types": "3.22.0", + "@shikijs/core": "3.23.0", + "@shikijs/engine-javascript": "3.23.0", + "@shikijs/engine-oniguruma": "3.23.0", + "@shikijs/langs": "3.23.0", + "@shikijs/themes": "3.23.0", + "@shikijs/types": "3.23.0", "@shikijs/vscode-textmate": "^10.0.2", "@types/hast": "^3.0.4" } }, "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 + "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/sinon": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.3.tgz", - "integrity": "sha512-0x8TQFr8EjADhSME01u1ZK31yv2+bd6Z5NrBCHVM+n4qL1wFqbxftmeyi3bwlr49FbbzRfrqSFOpyHCOh/YmYA==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-22.0.0.tgz", + "integrity": "sha512-sq/6DpdXOrLyfbKlXLg/Usc7xu8YXPeLkOFZRvA3bNUSA2lhbrZ06yuXbH1fkzBPCbz9O10+7hznzUsjaYNm0Q==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^15.1.1", - "@sinonjs/samsam": "^9.0.3", - "diff": "^8.0.3", - "supports-color": "^7.2.0" + "@sinonjs/fake-timers": "^15.4.0", + "@sinonjs/samsam": "^10.0.2", + "diff": "^9.0.0" }, "funding": { "type": "opencollective", @@ -5609,10 +5248,11 @@ } }, "node_modules/sinon/node_modules/diff": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", - "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -5644,6 +5284,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -5653,6 +5294,7 @@ "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" } @@ -5662,6 +5304,7 @@ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -5672,6 +5315,7 @@ "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-3.0.0.tgz", "integrity": "sha512-z+s5vv4KzFPJVddGab0xX2n7kQPGMdNUX5l9T8EJqsXdKTWpcxmAqWHpsgHEXoC1taGBCc7b79bi62M5kdbrxQ==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "cross-spawn": "^7.0.6", "foreground-child": "^2.0.0", @@ -5685,124 +5329,59 @@ "node": ">=8" } }, - "node_modules/spawn-wrap/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/spawn-wrap/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", "dev": true, + "license": "ISC", "dependencies": { - "balanced-match": "^4.0.2" + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": ">=8.0.0" } }, - "node_modules/spawn-wrap/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "node_modules/spawn-wrap/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, - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } + "license": "ISC" }, - "node_modules/spawn-wrap/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "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, - "engines": { - "node": "20 || >=22" - } + "license": "BSD-3-Clause" }, - "node_modules/spawn-wrap/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "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": { - "brace-expansion": "^5.0.2" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": "18 || 20 || >=22" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/spawn-wrap/node_modules/path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/spawn-wrap/node_modules/rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "dependencies": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/speakingurl": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "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 - }, - "node_modules/string-width": { + "node_modules/string-width-cjs": { + "name": "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", @@ -5812,16 +5391,31 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "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==", + "node_modules/string-width-cjs/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" + } + }, + "node_modules/string-width-cjs/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, + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/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, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" @@ -5832,6 +5426,7 @@ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "dev": true, + "license": "MIT", "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" @@ -5842,15 +5437,19 @@ } }, "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-ansi-cjs": { @@ -5859,6 +5458,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" }, @@ -5866,11 +5466,22 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs/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" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5880,6 +5491,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" }, @@ -5887,24 +5499,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/superjson": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", - "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "copy-anything": "^4" - }, - "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, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5916,7 +5516,8 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/table-layout": { "version": "4.1.1", @@ -5937,6 +5538,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^13.0.6", @@ -5951,15 +5553,17 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", "dev": true, + "license": "MIT", "engines": { "node": "18 || 20 || >=22" } }, "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, @@ -5972,6 +5576,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", @@ -5985,21 +5590,23 @@ } }, "node_modules/test-exclude/node_modules/lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", "dev": true, + "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" } }, "node_modules/test-exclude/node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^5.0.2" + "brace-expansion": "^5.0.5" }, "engines": { "node": "18 || 20 || >=22" @@ -6013,6 +5620,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^11.0.0", "minipass": "^7.1.2" @@ -6024,20 +5632,15 @@ "url": "https://github.com/sponsors/isaacs" } }, - "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/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, + "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -6046,6 +5649,37 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6064,48 +5698,37 @@ "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" } }, - "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, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.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==", "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==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/type-is": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "license": "MIT", "dependencies": { "content-type": "^2.0.0", "media-typer": "^1.1.0", @@ -6124,6 +5747,7 @@ "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, + "license": "MIT", "dependencies": { "is-typedarray": "^1.0.0" } @@ -6160,9 +5784,9 @@ } }, "node_modules/underscore": { - "version": "1.13.7", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", - "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", "dev": true, "license": "MIT" }, @@ -6171,6 +5795,7 @@ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6184,6 +5809,7 @@ "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6197,6 +5823,7 @@ "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", "dependencies": { "@types/unist": "^3.0.0" }, @@ -6210,6 +5837,7 @@ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0", @@ -6225,6 +5853,7 @@ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-is": "^6.0.0" @@ -6235,9 +5864,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -6253,9 +5882,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -6264,29 +5894,12 @@ "browserslist": ">= 4.21.0" } }, - "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, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "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": { "@types/unist": "^3.0.0", "vfile-message": "^4.0.0" @@ -6301,6 +5914,7 @@ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", "dev": true, + "license": "MIT", "dependencies": { "@types/unist": "^3.0.0", "unist-util-stringify-position": "^4.0.0" @@ -6311,10 +5925,11 @@ } }, "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", "dev": true, + "license": "MIT", "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -6384,11 +5999,43 @@ } } }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/vitepress": { "version": "2.0.0-alpha.17", "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-2.0.0-alpha.17.tgz", "integrity": "sha512-Z3VPUpwk/bHYqt1uMVOOK1/4xFiWQov1GNc2FvMdz6kvje4JRXEOngVI9C+bi5jeedMSHiA4dwKkff1NCvbZ9Q==", "dev": true, + "license": "MIT", "dependencies": { "@docsearch/css": "^4.5.3", "@docsearch/js": "^4.5.3", @@ -6431,16 +6078,17 @@ } }, "node_modules/vue": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", - "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", + "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", "dev": true, + "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-sfc": "3.5.30", - "@vue/runtime-dom": "3.5.30", - "@vue/server-renderer": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-sfc": "3.5.38", + "@vue/runtime-dom": "3.5.38", + "@vue/server-renderer": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { "typescript": "*" @@ -6452,13 +6100,21 @@ } }, "node_modules/walk-back": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz", - "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.2.tgz", + "integrity": "sha512-uCgzIY1U7fyXvJm+mesY0xjf2HXu7mtTnptONwVQ11ur1JhMrUyQJn2fDje1CGFQDnTFTo1Slr1vRuvUS9PYoQ==", "dev": true, "license": "MIT", "engines": { "node": ">=12.17" + }, + "peerDependencies": { + "@75lb/nature": "latest" + }, + "peerDependenciesMeta": { + "@75lb/nature": { + "optional": true + } } }, "node_modules/which": { @@ -6466,6 +6122,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -6480,16 +6137,8 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "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, - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, "node_modules/wordwrap": { "version": "1.0.0", @@ -6509,25 +6158,25 @@ } }, "node_modules/workerpool": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz", - "integrity": "sha512-Xz4Nm9c+LiBHhDR5bDLnNzmj6+5F+cyEAWPMkbs2awq/dYazR/efelZzUAjB/y3kNHL+uzkHvxVVpaOfGCPV7A==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, "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==", + "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": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -6539,6 +6188,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -6551,25 +6201,85 @@ "url": "https://github.com/chalk/wrap-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==", + "node_modules/wrap-ansi-cjs/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, - "dependencies": { - "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/xmlcreate": { + "node_modules/wrap-ansi-cjs/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, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/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", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/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, + "license": "ISC" + }, + "node_modules/xmlcreate": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", @@ -6590,7 +6300,8 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/yargs": { "version": "17.7.2", @@ -6626,6 +6337,7 @@ "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", "dev": true, + "license": "MIT", "dependencies": { "camelcase": "^6.0.0", "decamelize": "^4.0.0", @@ -6641,6 +6353,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -6653,6 +6366,7 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -6660,11 +6374,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yargs/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" + } + }, + "node_modules/yargs/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, + "license": "MIT" + }, + "node_modules/yargs/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", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/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, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "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, + "license": "MIT", "engines": { "node": ">=10" }, @@ -6677,4524 +6437,11 @@ "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" } } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - } - }, - "@babel/compat-data": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.9.tgz", - "integrity": "sha512-e701mcfApCJqMMueQI0Fb68Amflj83+dvAvHawoBpAz+GDjCIyGHzNwnefjsWJ3xiYAqqiQFoWbspGYBdb2/ng==", - "dev": true - }, - "@babel/core": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.9.tgz", - "integrity": "sha512-5e3FI4Q3M3Pbr21+5xJwCv6ZT6KmGkI0vw3Tozy5ODAQFTIWe37iT8Cr7Ice2Ntb+M3iSKCEWMB1MBgKrW3whg==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.9", - "@babel/helper-compilation-targets": "^7.24.8", - "@babel/helper-module-transforms": "^7.24.9", - "@babel/helpers": "^7.24.8", - "@babel/parser": "^7.24.8", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.9", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "dependencies": { - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.24.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.10.tgz", - "integrity": "sha512-o9HBZL1G2129luEUlG1hB4N/nlYNWHnpwlND9eOMclRqqu1YDy2sSYVCFUZwl8I1Gxh+QSRrP2vD7EpUmFVXxg==", - "dev": true, - "requires": { - "@babel/types": "^7.24.9", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz", - "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.24.8", - "@babel/helper-validator-option": "^7.24.8", - "browserslist": "^4.23.1", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "requires": { - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "requires": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "requires": { - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.9.tgz", - "integrity": "sha512-oYbh+rtFKj/HwBQkFlUzvcybzklmVdVV3UU+mN7n2t/q3yGHbuVdNxyFvSBO1tfvjyArpHNcWMAzsSPdyI46hw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "requires": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "requires": { - "@babel/types": "^7.24.7" - } - }, - "@babel/helper-string-parser": { - "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 - }, - "@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", - "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", - "dev": true - }, - "@babel/helpers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.1.tgz", - "integrity": "sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ==", - "dev": true, - "requires": { - "@babel/template": "^7.27.1", - "@babel/types": "^7.27.1" - } - }, - "@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", - "dev": true, - "requires": { - "@babel/types": "^7.29.0" - } - }, - "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - } - }, - "@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - } - }, - "@docsearch/css": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-4.5.3.tgz", - "integrity": "sha512-kUpHaxn0AgI3LQfyzTYkNUuaFY4uEz/Ym9/N/FvyDE+PzSgZsCyDH9jE49B6N6f1eLCm9Yp64J9wENd6vypdxA==", - "dev": true - }, - "@docsearch/js": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-4.5.3.tgz", - "integrity": "sha512-rcBiUMCXbZLqrLIT6F6FDcrG/tyvM2WM0zum6NPbIiQNDQxbSgmNc+/bToS0rxBsXaxiU64esiWoS02WqrWLsg==", - "dev": true - }, - "@docsearch/sidepanel-js": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/@docsearch/sidepanel-js/-/sidepanel-js-4.5.3.tgz", - "integrity": "sha512-DmcZYc1ZMMcabtKrCU2RIf1z09LwazKCyoPFU/ijJiBg2LdqMLmkyDKHGy1OIYEyUx4ok5RIbkVGaRfD55BqZQ==", - "dev": true - }, - "@esbuild/aix-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", - "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.4.tgz", - "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", - "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.4.tgz", - "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", - "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", - "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", - "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", - "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", - "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", - "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", - "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", - "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", - "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", - "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", - "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", - "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", - "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", - "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", - "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", - "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", - "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", - "dev": true, - "optional": true - }, - "@esbuild/openharmony-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", - "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", - "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", - "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", - "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", - "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", - "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.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", - "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.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^2.0.3", - "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.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true - }, - "@iconify-json/simple-icons": { - "version": "1.2.69", - "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.69.tgz", - "integrity": "sha512-T/rhy5n7pzE0ZOxQVlF68SNPCYYjRBpddjgjrJO5WWVRG8es5BQmvxIE9kKF+t2hhPGvuGQFpXmUyqbOtnxirQ==", - "dev": true, - "requires": { - "@iconify/types": "*" - } - }, - "@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 - }, - "@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.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true - }, - "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 - }, - "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" - } - }, - "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" - } - } - } - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "@jridgewell/resolve-uri": { - "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 - }, - "@jridgewell/set-array": { - "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 - }, - "@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "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" - } - }, - "@jsdoc/salty": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.9.tgz", - "integrity": "sha512-yYxMVH7Dqw6nO0d5NIV8OQWnitU8k6vXH8NtgqAfIa/IUqRMxRv/NUJJ08VEKbAakwxlgBl5PJdrU0dMPStsnw==", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "@node-oauth/formats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@node-oauth/formats/-/formats-1.0.0.tgz", - "integrity": "sha512-DwSbLtdC8zC5B5gTJkFzJj5s9vr9SGzOgQvV9nH7tUVuMSScg0EswAczhjIapOmH3Y8AyP7C4Jv7b8+QJObWZA==" - }, - "@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" - } - }, - "@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 - }, - "@rolldown/pluginutils": { - "version": "1.0.0-rc.2", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", - "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", - "dev": true - }, - "@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "dev": true, - "optional": true - }, - "@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "dev": true, - "optional": true - }, - "@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "dev": true, - "optional": true - }, - "@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "dev": true, - "optional": true - }, - "@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "dev": true, - "optional": true - }, - "@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "dev": true, - "optional": true - }, - "@shikijs/core": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.22.0.tgz", - "integrity": "sha512-iAlTtSDDbJiRpvgL5ugKEATDtHdUVkqgHDm/gbD2ZS9c88mx7G1zSYjjOxp5Qa0eaW0MAQosFRmJSk354PRoQA==", - "dev": true, - "requires": { - "@shikijs/types": "3.22.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4", - "hast-util-to-html": "^9.0.5" - } - }, - "@shikijs/engine-javascript": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.22.0.tgz", - "integrity": "sha512-jdKhfgW9CRtj3Tor0L7+yPwdG3CgP7W+ZEqSsojrMzCjD1e0IxIbwUMDDpYlVBlC08TACg4puwFGkZfLS+56Tw==", - "dev": true, - "requires": { - "@shikijs/types": "3.22.0", - "@shikijs/vscode-textmate": "^10.0.2", - "oniguruma-to-es": "^4.3.4" - } - }, - "@shikijs/engine-oniguruma": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.22.0.tgz", - "integrity": "sha512-DyXsOG0vGtNtl7ygvabHd7Mt5EY8gCNqR9Y7Lpbbd/PbJvgWrqaKzH1JW6H6qFkuUa8aCxoiYVv8/YfFljiQxA==", - "dev": true, - "requires": { - "@shikijs/types": "3.22.0", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "@shikijs/langs": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.22.0.tgz", - "integrity": "sha512-x/42TfhWmp6H00T6uwVrdTJGKgNdFbrEdhaDwSR5fd5zhQ1Q46bHq9EO61SCEWJR0HY7z2HNDMaBZp8JRmKiIA==", - "dev": true, - "requires": { - "@shikijs/types": "3.22.0" - } - }, - "@shikijs/themes": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz", - "integrity": "sha512-o+tlOKqsr6FE4+mYJG08tfCFDS+3CG20HbldXeVoyP+cYSUxDhrFf3GPjE60U55iOkkjbpY2uC3It/eeja35/g==", - "dev": true, - "requires": { - "@shikijs/types": "3.22.0" - } - }, - "@shikijs/transformers": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-3.22.0.tgz", - "integrity": "sha512-E7eRV7mwDBjueLF6852n2oYeJYxBq3NSsDk+uyruYAXONv4U8holGmIrT+mPRJQ1J1SNOH6L8G19KRzmBawrFw==", - "dev": true, - "requires": { - "@shikijs/core": "3.22.0", - "@shikijs/types": "3.22.0" - } - }, - "@shikijs/types": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.22.0.tgz", - "integrity": "sha512-491iAekgKDBFE67z70Ok5a8KBMsQ2IJwOWw3us/7ffQkIBCyOQfm/aNwVMBUriP02QshIfgHCBSIYAl3u2eWjg==", - "dev": true, - "requires": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "@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 - }, - "@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz", - "integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.1" - } - }, - "@sinonjs/samsam": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz", - "integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.1", - "type-detect": "^4.1.0" - }, - "dependencies": { - "type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true - } - } - }, - "@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": 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/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/markdown-it": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", - "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", - "dev": true, - "requires": { - "@types/linkify-it": "^5", - "@types/mdurl": "^2" - } - }, - "@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, - "requires": { - "@types/unist": "*" - } - }, - "@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/unist": { - "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 - }, - "@types/web-bluetooth": { - "version": "0.0.21", - "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", - "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", - "dev": true - }, - "@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": "6.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", - "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", - "dev": true, - "requires": { - "@rolldown/pluginutils": "1.0.0-rc.2" - } - }, - "@vue/compiler-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", - "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", - "dev": true, - "requires": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.30", - "entities": "^7.0.1", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "@vue/compiler-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", - "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", - "dev": true, - "requires": { - "@vue/compiler-core": "3.5.30", - "@vue/shared": "3.5.30" - } - }, - "@vue/compiler-sfc": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", - "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", - "dev": true, - "requires": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.30", - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.21", - "postcss": "^8.5.8", - "source-map-js": "^1.2.1" - } - }, - "@vue/compiler-ssr": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", - "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", - "dev": true, - "requires": { - "@vue/compiler-dom": "3.5.30", - "@vue/shared": "3.5.30" - } - }, - "@vue/devtools-api": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-8.0.5.tgz", - "integrity": "sha512-DgVcW8H/Nral7LgZEecYFFYXnAvGuN9C3L3DtWekAncFBedBczpNW8iHKExfaM559Zm8wQWrwtYZ9lXthEHtDw==", - "dev": true, - "requires": { - "@vue/devtools-kit": "^8.0.5" - } - }, - "@vue/devtools-kit": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-8.0.5.tgz", - "integrity": "sha512-q2VV6x1U3KJMTQPUlRMyWEKVbcHuxhqJdSr6Jtjz5uAThAIrfJ6WVZdGZm5cuO63ZnSUz0RCsVwiUUb0mDV0Yg==", - "dev": true, - "requires": { - "@vue/devtools-shared": "^8.0.5", - "birpc": "^2.6.1", - "hookable": "^5.5.3", - "mitt": "^3.0.1", - "perfect-debounce": "^2.0.0", - "speakingurl": "^14.0.1", - "superjson": "^2.2.2" - } - }, - "@vue/devtools-shared": { - "version": "8.0.5", - "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-8.0.5.tgz", - "integrity": "sha512-bRLn6/spxpmgLk+iwOrR29KrYnJjG9DGpHGkDFG82UM21ZpJ39ztUT9OXX3g+usW7/b2z+h46I9ZiYyB07XMXg==", - "dev": true, - "requires": { - "rfdc": "^1.4.1" - } - }, - "@vue/reactivity": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", - "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", - "dev": true, - "requires": { - "@vue/shared": "3.5.30" - } - }, - "@vue/runtime-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", - "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", - "dev": true, - "requires": { - "@vue/reactivity": "3.5.30", - "@vue/shared": "3.5.30" - } - }, - "@vue/runtime-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", - "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", - "dev": true, - "requires": { - "@vue/reactivity": "3.5.30", - "@vue/runtime-core": "3.5.30", - "@vue/shared": "3.5.30", - "csstype": "^3.2.3" - } - }, - "@vue/server-renderer": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", - "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", - "dev": true, - "requires": { - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30" - } - }, - "@vue/shared": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", - "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", - "dev": true - }, - "@vueuse/core": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.1.tgz", - "integrity": "sha512-3vwDzV+GDUNpdegRY6kzpLm4Igptq+GA0QkJ3W61Iv27YWwW/ufSlOfgQIpN6FZRMG0mkaz4gglJRtq5SeJyIQ==", - "dev": true, - "requires": { - "@types/web-bluetooth": "^0.0.21", - "@vueuse/metadata": "14.2.1", - "@vueuse/shared": "14.2.1" - } - }, - "@vueuse/integrations": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-14.2.1.tgz", - "integrity": "sha512-2LIUpBi/67PoXJGqSDQUF0pgQWpNHh7beiA+KG2AbybcNm+pTGWT6oPGlBgUoDWmYwfeQqM/uzOHqcILpKL7nA==", - "dev": true, - "requires": { - "@vueuse/core": "14.2.1", - "@vueuse/shared": "14.2.1" - } - }, - "@vueuse/metadata": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.2.1.tgz", - "integrity": "sha512-1ButlVtj5Sb/HDtIy1HFr1VqCP4G6Ypqt5MAo0lCgjokrk2mvQKsK2uuy0vqu/Ks+sHfuHo0B9Y9jn9xKdjZsw==", - "dev": true - }, - "@vueuse/shared": { - "version": "14.2.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.2.1.tgz", - "integrity": "sha512-shTJncjV9JTI4oVNyF1FQonetYAiTBd+Qj7cY89SWbXSkx7gyhrgtEdF2ZAVWS1S3SHlaROO6F2IesJxQEkZBw==", - "dev": true, - "requires": {} - }, - "acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "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": {} - }, - "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==", - "dev": true, - "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" - } - }, - "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" - } - }, - "append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", - "dev": true, - "requires": { - "default-require-extensions": "^3.0.0" - } - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true - }, - "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-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "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 - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "birpc": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", - "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", - "dev": true - }, - "bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "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.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "requires": { - "fill-range": "^7.1.1" - } - }, - "browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "browserslist": { - "version": "4.23.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", - "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001640", - "electron-to-chromium": "^1.4.820", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.1.0" - } - }, - "cache-point": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/cache-point/-/cache-point-3.0.1.tgz", - "integrity": "sha512-itTIMLEKbh6Dw5DruXbxAgcyLnh/oPGVLBfTPqBOftASxHe8bAeXy7JkO4F0LvHqht7XqP5O/09h5UcHS2w0FA==", - "dev": true, - "requires": { - "array-back": "^6.2.2" - } - }, - "caching-transform": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", - "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", - "dev": true, - "requires": { - "hasha": "^5.0.0", - "make-dir": "^3.0.0", - "package-hash": "^4.0.0", - "write-file-atomic": "^3.0.0" - } - }, - "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": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001643", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001643.tgz", - "integrity": "sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==", - "dev": true - }, - "catharsis": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/catharsis/-/catharsis-0.9.0.tgz", - "integrity": "sha512-prMTQVpcns/tzFgFVkVp6ak6RykZyWb3gu8ckUpd6YkTlacOd3DXGJjIpD4Q6zJirizvaiAjSSHlOsA+6sNh2A==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "ccount": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", - "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", - "dev": true - }, - "chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chalk-template": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", - "dev": true, - "requires": { - "chalk": "^4.1.2" - } - }, - "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 - }, - "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 - }, - "chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "requires": { - "readdirp": "^4.0.1" - } - }, - "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 - }, - "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, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "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 - }, - "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 - }, - "command-line-args": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-6.0.1.tgz", - "integrity": "sha512-Jr3eByUjqyK0qd8W0SGFW1nZwqCaNCtbXjRo2cRJC1OYxWl3MZ5t1US3jq+cO4sPavqgw4l9BMGX0CBe+trepg==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "find-replace": "^5.0.2", - "lodash.camelcase": "^4.3.0", - "typical": "^7.2.0" - } - }, - "command-line-usage": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.3.tgz", - "integrity": "sha512-PqMLy5+YGwhMh1wS04mVG44oqDsgyLRSKJBdOo1bnYhMKBW65gZF1dRp2OZRhiTjgUHljy99qkO7bsctLaw35Q==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "chalk-template": "^0.4.0", - "table-layout": "^4.1.0", - "typical": "^7.1.1" - } - }, - "common-sequence": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/common-sequence/-/common-sequence-3.0.0.tgz", - "integrity": "sha512-g/CgSYk93y+a1IKm50tKl7kaT/OjjTYVQlEbUlt/49ZLV1mcKpUU7iyDiqTAeLdb4QDtQfq3ako8y8v//fzrWQ==", - "dev": true - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", - "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 - }, - "config-master": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/config-master/-/config-master-3.1.0.tgz", - "integrity": "sha512-n7LBL1zBzYdTpF1mx5DNcZnZn05CWIdsdvtPL4MosvqbBUK3Rq6VWEtGUuF3Y0s9/CIhMejezqlSkP6TnCJ/9g==", - "dev": true, - "requires": { - "walk-back": "^2.0.1" - }, - "dependencies": { - "walk-back": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-2.0.1.tgz", - "integrity": "sha512-Nb6GvBR8UWX1D+Le+xUq0+Q1kFmRBIWVrfLnQAOmcpEzA9oAxwJ9gIr36t9TWYfzvWRvuMtjHiVsJYEkXWaTAQ==", - "dev": true - } - } - }, - "content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==" - }, - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "copy-anything": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", - "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", - "dev": true, - "requires": { - "is-what": "^5.2.0" - } - }, - "cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true - }, - "current-module-paths": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/current-module-paths/-/current-module-paths-1.1.3.tgz", - "integrity": "sha512-7AH+ZTRKikdK4s1RmY0l6067UD/NZc7p3zZVZxvmnH80G31kr0y0W0E6ibYM4IS01MEm8DiC5FnTcgcgkbFHoA==", - "dev": true - }, - "debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "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 - }, - "default-require-extensions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", - "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", - "dev": true, - "requires": { - "strip-bom": "^4.0.0" - } - }, - "dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true - }, - "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, - "requires": { - "dequal": "^2.0.0" - } - }, - "diff": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", - "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", - "dev": true - }, - "dmd": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/dmd/-/dmd-7.1.1.tgz", - "integrity": "sha512-Ap2HP6iuOek7eShReDLr9jluNJm9RMZESlt29H/Xs1qrVMkcS9X6m5h1mBC56WMxNiSo0wvjGICmZlYUSFjwZQ==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "cache-point": "^3.0.0", - "common-sequence": "^3.0.0", - "file-set": "^5.2.2", - "handlebars": "^4.7.8", - "marked": "^4.3.0", - "walk-back": "^5.1.1" - }, - "dependencies": { - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true - } - } - }, - "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" - } - }, - "eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "electron-to-chromium": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.0.tgz", - "integrity": "sha512-Vb3xHHYnLseK8vlMJQKJYXJ++t4u1/qJ3vykuVrVjvdiOEhYyT1AuP4x03G8EnPmYvYOhe9T+dADTmthjRQMkA==", - "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 - }, - "entities": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", - "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", - "dev": true - }, - "es6-error": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true - }, - "esbuild": { - "version": "0.27.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.4.tgz", - "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", - "dev": true, - "requires": { - "@esbuild/aix-ppc64": "0.27.4", - "@esbuild/android-arm": "0.27.4", - "@esbuild/android-arm64": "0.27.4", - "@esbuild/android-x64": "0.27.4", - "@esbuild/darwin-arm64": "0.27.4", - "@esbuild/darwin-x64": "0.27.4", - "@esbuild/freebsd-arm64": "0.27.4", - "@esbuild/freebsd-x64": "0.27.4", - "@esbuild/linux-arm": "0.27.4", - "@esbuild/linux-arm64": "0.27.4", - "@esbuild/linux-ia32": "0.27.4", - "@esbuild/linux-loong64": "0.27.4", - "@esbuild/linux-mips64el": "0.27.4", - "@esbuild/linux-ppc64": "0.27.4", - "@esbuild/linux-riscv64": "0.27.4", - "@esbuild/linux-s390x": "0.27.4", - "@esbuild/linux-x64": "0.27.4", - "@esbuild/netbsd-arm64": "0.27.4", - "@esbuild/netbsd-x64": "0.27.4", - "@esbuild/openbsd-arm64": "0.27.4", - "@esbuild/openbsd-x64": "0.27.4", - "@esbuild/openharmony-arm64": "0.27.4", - "@esbuild/sunos-x64": "0.27.4", - "@esbuild/win32-arm64": "0.27.4", - "@esbuild/win32-ia32": "0.27.4", - "@esbuild/win32-x64": "0.27.4" - } - }, - "escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "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.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "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.1", - "@humanwhocodes/config-array": "^0.13.0", - "@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" - } - }, - "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" - } - }, - "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 - }, - "esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "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": "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 - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "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==", - "dev": true - }, - "fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "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.8" - }, - "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==", - "dev": true - }, - "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 - }, - "fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "requires": {} - }, - "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" - } - }, - "file-set": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/file-set/-/file-set-5.3.0.tgz", - "integrity": "sha512-FKCxdjLX0J6zqTWdT0RXIxNF/n7MyXXnsSUp0syLEOCKdexvPZ02lNNv2a+gpK9E3hzUYF3+eFZe32ci7goNUg==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "fast-glob": "^3.3.2" - } - }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-replace": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-5.0.2.tgz", - "integrity": "sha512-Y45BAiE3mz2QsrN2fb5QEtO4qb44NcS7en/0y9PEVsg351HsLeVclP8QPMH79Le9sH3rs5RSwJu99W0WPZO43Q==", - "dev": true, - "requires": {} - }, - "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": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true - }, - "flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "requires": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "focus-trap": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-8.0.0.tgz", - "integrity": "sha512-Aa84FOGHs99vVwufDMdq2qgOwXPC2e9U66GcqBhn1/jEHPDhJaP8PYhkIbqG9lhfL5Kddk/567lj46LLHYCRUw==", - "dev": true, - "requires": { - "tabbable": "^6.4.0" - } - }, - "foreground-child": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", - "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^3.0.2" - } - }, - "fromentries": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", - "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", - "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 - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "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 - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "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" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - } - }, - "minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.2" - } - }, - "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 - } - } - }, - "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" - } - }, - "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" - } - }, - "graceful-fs": { - "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 - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "handlebars": { - "version": "4.7.9", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz", - "integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4", - "wordwrap": "^1.0.0" - } - }, - "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 - }, - "hasha": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", - "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", - "dev": true, - "requires": { - "is-stream": "^2.0.0", - "type-fest": "^0.8.0" - }, - "dependencies": { - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - } - } - }, - "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, - "requires": { - "@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" - } - }, - "hast-util-whitespace": { - "version": "3.0.0", - "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, - "requires": { - "@types/hast": "^3.0.0" - } - }, - "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 - }, - "hookable": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", - "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", - "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 - }, - "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 - }, - "ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true - }, - "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" - } - }, - "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 - }, - "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-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-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": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true - }, - "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-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true - }, - "is-what": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", - "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "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-hook": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", - "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", - "dev": true, - "requires": { - "append-transform": "^2.0.0" - } - }, - "istanbul-lib-instrument": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", - "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", - "dev": true, - "requires": { - "@babel/core": "^7.23.9", - "@babel/parser": "^7.23.9", - "@istanbuljs/schema": "^0.1.3", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^7.5.4" - } - }, - "istanbul-lib-processinfo": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-3.0.0.tgz", - "integrity": "sha512-P7nLXRRlo7Sqinty6lNa7+4o9jBUYGpqtejqCOZKfgXlRoxY/QArflcB86YO500Ahj4pDJEG34JjMRbQgePLnQ==", - "dev": true, - "requires": { - "archy": "^1.0.0", - "cross-spawn": "^7.0.3", - "istanbul-lib-coverage": "^3.2.0", - "p-map": "^3.0.0", - "rimraf": "^6.1.3", - "uuid": "^8.3.2" - }, - "dependencies": { - "balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true - }, - "brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "requires": { - "balanced-match": "^4.0.2" - } - }, - "glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "requires": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - } - }, - "lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true - }, - "minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "requires": { - "brace-expansion": "^5.0.2" - } - }, - "path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "requires": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - } - }, - "rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "requires": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - } - } - } - }, - "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" - }, - "dependencies": { - "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" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "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, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "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" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "js2xmlparser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-4.0.2.tgz", - "integrity": "sha512-6n4D8gLlLf1n5mNLQPRfViYzu9RATblzPEtm1SthMX1Pjao0r9YI9nw7ZIfRxQMERS87mcswrg+r/OYrPRX6jA==", - "dev": true, - "requires": { - "xmlcreate": "^2.0.4" - } - }, - "jsdoc": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.5.tgz", - "integrity": "sha512-P4C6MWP9yIlMiK8nwoZvxN84vb6MsnXcHuy7XzVOvQoCizWX5JFCBsWIIWKXBltpoRZXddUOVQmCTOZt9yDj9g==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.15", - "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^14.1.1", - "bluebird": "^3.7.2", - "catharsis": "^0.9.0", - "escape-string-regexp": "^2.0.0", - "js2xmlparser": "^4.0.2", - "klaw": "^3.0.0", - "markdown-it": "^14.1.0", - "markdown-it-anchor": "^8.6.7", - "marked": "^4.0.10", - "mkdirp": "^1.0.4", - "requizzle": "^0.2.3", - "strip-json-comments": "^3.1.0", - "underscore": "~1.13.2" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - }, - "marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true - } - } - }, - "jsdoc-api": { - "version": "9.3.5", - "resolved": "https://registry.npmjs.org/jsdoc-api/-/jsdoc-api-9.3.5.tgz", - "integrity": "sha512-TQwh1jA8xtCkIbVwm/XA3vDRAa5JjydyKx1cC413Sh3WohDFxcMdwKSvn4LOsq2xWyAmOU/VnSChTQf6EF0R8g==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "cache-point": "^3.0.1", - "current-module-paths": "^1.1.2", - "file-set": "^5.3.0", - "jsdoc": "^4.0.4", - "object-to-spawn-args": "^2.0.1", - "walk-back": "^5.1.1" - } - }, - "jsdoc-parse": { - "version": "6.2.5", - "resolved": "https://registry.npmjs.org/jsdoc-parse/-/jsdoc-parse-6.2.5.tgz", - "integrity": "sha512-8JaSNjPLr2IuEY4Das1KM6Z4oLHZYUnjRrr27hKSa78Cj0i5Lur3DzNnCkz+DfrKBDoljGMoWOiBVQbtUZJBPw==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "find-replace": "^5.0.1", - "sort-array": "^5.0.0" - } - }, - "jsdoc-to-markdown": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/jsdoc-to-markdown/-/jsdoc-to-markdown-9.1.3.tgz", - "integrity": "sha512-i9wi+6WHX0WKziv0ar88T8h7OmxA0LWdQaV23nY6uQyKvdUPzVt0o6YAaOceFuKRF5Rvlju5w/KnZBfdpDAlnw==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "command-line-args": "^6.0.1", - "command-line-usage": "^7.0.3", - "config-master": "^3.1.0", - "dmd": "^7.1.1", - "jsdoc-api": "^9.3.5", - "jsdoc-parse": "^6.2.5", - "walk-back": "^5.1.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "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-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 - }, - "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 - }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "klaw": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz", - "integrity": "sha512-0Fo5oir+O9jnXu5EefYbVK+mHMBeEVEy2cmctR1O1NECcCkPRreJKrS6Qt/j3KC2C148Dfo9i3pCmCMsdqGr0g==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.9" - } - }, - "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" - } - }, - "linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "dev": true, - "requires": { - "uc.micro": "^2.0.0" - } - }, - "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.23", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", - "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", - "dev": true - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true - }, - "lodash.flattendeep": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", - "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", - "dev": true - }, - "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 - }, - "log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - } - }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "requires": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "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 - }, - "markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "dependencies": { - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - } - } - }, - "markdown-it-anchor": { - "version": "8.6.7", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", - "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", - "dev": true, - "requires": {} - }, - "mdast-util-to-hast": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", - "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", - "dev": true, - "requires": { - "@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" - } - }, - "mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true - }, - "media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==" - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "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, - "requires": { - "micromark-util-symbol": "^2.0.0", - "micromark-util-types": "^2.0.0" - } - }, - "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 - }, - "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, - "requires": { - "micromark-util-character": "^2.0.0", - "micromark-util-encode": "^2.0.0", - "micromark-util-symbol": "^2.0.0" - } - }, - "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 - }, - "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 - }, - "micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "requires": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "dependencies": { - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - } - } - }, - "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==" - }, - "mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "requires": { - "mime-db": "^1.54.0" - } - }, - "minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true - }, - "minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true - }, - "minisearch": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", - "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", - "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 - }, - "mocha": { - "version": "11.7.5", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.5.tgz", - "integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==", - "dev": true, - "requires": { - "browser-stdout": "^1.3.1", - "chokidar": "^4.0.1", - "debug": "^4.3.5", - "diff": "^7.0.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^10.4.5", - "he": "^1.2.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^9.0.5", - "ms": "^2.1.3", - "picocolors": "^1.1.1", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^9.2.0", - "yargs": "^17.7.2", - "yargs-parser": "^21.1.1", - "yargs-unparser": "^2.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.2" - } - }, - "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 - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.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==", - "dev": true - }, - "nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node-preload": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", - "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", - "dev": true, - "requires": { - "process-on-spawn": "^1.0.0" - } - }, - "node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", - "dev": true - }, - "nyc": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-18.0.0.tgz", - "integrity": "sha512-G5UyHinFkB1BxqGTrmZdB6uIYH0+v7ZnVssuflUDi+J+RhKWyAhRT1RCehBSI6jLFLuUUgFDyLt49mUtdO1XeQ==", - "dev": true, - "requires": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^3.3.0", - "get-package-type": "^0.1.0", - "glob": "^13.0.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^6.0.2", - "istanbul-lib-processinfo": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^6.1.3", - "signal-exit": "^3.0.2", - "spawn-wrap": "^3.0.0", - "test-exclude": "^8.0.0", - "yargs": "^15.0.2" - }, - "dependencies": { - "balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true - }, - "brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "requires": { - "balanced-match": "^4.0.2" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "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 - } - } - }, - "glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "requires": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true - }, - "minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "requires": { - "brace-expansion": "^5.0.2" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "requires": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - } - }, - "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 - }, - "rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "requires": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - } - } - }, - "object-to-spawn-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object-to-spawn-args/-/object-to-spawn-args-2.0.1.tgz", - "integrity": "sha512-6FuKFQ39cOID+BMZ3QaphcC8Y4cw6LXBLyIgPU+OhIYwviJamPAn+4mITapnSBQrejB+NNp+FMskhD8Cq+Ys3w==", - "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" - } - }, - "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 - }, - "oniguruma-to-es": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.4.tgz", - "integrity": "sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==", - "dev": true, - "requires": { - "oniguruma-parser": "^0.12.1", - "regex": "^6.0.1", - "regex-recursion": "^6.0.2" - } - }, - "optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - } - }, - "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": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "package-hash": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", - "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.15", - "hasha": "^5.0.0", - "lodash.flattendeep": "^4.4.0", - "release-zalgo": "^1.0.0" - } - }, - "package-json-from-dist": { - "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 - }, - "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" - } - }, - "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-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 - } - } - }, - "perfect-debounce": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz", - "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==", - "dev": true - }, - "picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true - }, - "picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - } - } - }, - "postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, - "requires": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - } - }, - "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 - }, - "process-on-spawn": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", - "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", - "dev": true, - "requires": { - "fromentries": "^1.2.0" - } - }, - "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 - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true - }, - "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 - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "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 - }, - "regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", - "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", - "dev": true, - "requires": { - "regex-utilities": "^2.3.0" - } - }, - "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, - "requires": { - "regex-utilities": "^2.3.0" - } - }, - "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 - }, - "release-zalgo": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", - "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", - "dev": true, - "requires": { - "es6-error": "^4.0.1" - } - }, - "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 - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "requizzle": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/requizzle/-/requizzle-0.2.4.tgz", - "integrity": "sha512-JRrFk1D4OQ4SqovXOgdav+K8EAhSB/LJZqCz8tbX0KObcdeM15Ss59ozWMBWmmINMagCwmqn4ZNryUGpBsl6Jw==", - "dev": true, - "requires": { - "lodash": "^4.17.21" - } - }, - "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 - }, - "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" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "requires": { - "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" - } - } - } - }, - "rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "requires": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "@types/estree": "1.0.8", - "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-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "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 - }, - "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 - }, - "shiki": { - "version": "3.22.0", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.22.0.tgz", - "integrity": "sha512-LBnhsoYEe0Eou4e1VgJACes+O6S6QC0w71fCSp5Oya79inkwkm15gQ1UF6VtQ8j/taMDh79hAB49WUk8ALQW3g==", - "dev": true, - "requires": { - "@shikijs/core": "3.22.0", - "@shikijs/engine-javascript": "3.22.0", - "@shikijs/engine-oniguruma": "3.22.0", - "@shikijs/langs": "3.22.0", - "@shikijs/themes": "3.22.0", - "@shikijs/types": "3.22.0", - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "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 - }, - "sinon": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.3.tgz", - "integrity": "sha512-0x8TQFr8EjADhSME01u1ZK31yv2+bd6Z5NrBCHVM+n4qL1wFqbxftmeyi3bwlr49FbbzRfrqSFOpyHCOh/YmYA==", - "dev": true, - "requires": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^15.1.1", - "@sinonjs/samsam": "^9.0.3", - "diff": "^8.0.3", - "supports-color": "^7.2.0" - }, - "dependencies": { - "diff": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz", - "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==", - "dev": true - } - } - }, - "sort-array": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/sort-array/-/sort-array-5.1.1.tgz", - "integrity": "sha512-EltS7AIsNlAFIM9cayrgKrM6XP94ATWwXP4LCL4IQbvbYhELSt2hZTrixg+AaQwnWFs/JGJgqU3rxMcNNWxGAA==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "typical": "^7.1.1" - } - }, - "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.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true - }, - "space-separated-tokens": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", - "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", - "dev": true - }, - "spawn-wrap": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-3.0.0.tgz", - "integrity": "sha512-z+s5vv4KzFPJVddGab0xX2n7kQPGMdNUX5l9T8EJqsXdKTWpcxmAqWHpsgHEXoC1taGBCc7b79bi62M5kdbrxQ==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.6", - "foreground-child": "^2.0.0", - "is-windows": "^1.0.2", - "make-dir": "^3.0.0", - "rimraf": "^6.1.3", - "signal-exit": "^3.0.2", - "which": "^2.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true - }, - "brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "requires": { - "balanced-match": "^4.0.2" - } - }, - "glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "requires": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - } - }, - "lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true - }, - "minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "requires": { - "brace-expansion": "^5.0.2" - } - }, - "path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "requires": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - } - }, - "rimraf": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.1.3.tgz", - "integrity": "sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==", - "dev": true, - "requires": { - "glob": "^13.0.3", - "package-json-from-dist": "^1.0.1" - } - } - } - }, - "speakingurl": { - "version": "14.0.1", - "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", - "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "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" - } - }, - "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, - "requires": { - "character-entities-html4": "^2.0.0", - "character-entities-legacy": "^3.0.0" - } - }, - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "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 - }, - "superjson": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", - "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", - "dev": true, - "requires": { - "copy-anything": "^4" - } - }, - "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" - } - }, - "tabbable": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", - "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", - "dev": true - }, - "table-layout": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-4.1.1.tgz", - "integrity": "sha512-iK5/YhZxq5GO5z8wb0bY1317uDF3Zjpha0QFFLA8/trAoiLbQD0HUbMesEaxyzUgDxi2QlcbM8IvqOlEjgoXBA==", - "dev": true, - "requires": { - "array-back": "^6.2.2", - "wordwrapjs": "^5.1.0" - } - }, - "test-exclude": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", - "integrity": "sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^13.0.6", - "minimatch": "^10.2.2" - }, - "dependencies": { - "balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true - }, - "brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", - "dev": true, - "requires": { - "balanced-match": "^4.0.2" - } - }, - "glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", - "dev": true, - "requires": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - } - }, - "lru-cache": { - "version": "11.2.7", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", - "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", - "dev": true - }, - "minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "requires": { - "brace-expansion": "^5.0.2" - } - }, - "path-scurry": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", - "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", - "dev": true, - "requires": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - } - } - } - }, - "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 - }, - "tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "requires": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - } - }, - "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" - } - }, - "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 - }, - "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": "2.1.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", - "requires": { - "content-type": "^2.0.0", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - } - }, - "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" - } - }, - "typical": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.3.0.tgz", - "integrity": "sha512-ya4mg/30vm+DOWfBg4YK3j2WD6TWtRkCbasOJr40CseYENzCUby/7rIvXA99JGsQHeNxLbnXdyLLxKSv3tauFw==", - "dev": true - }, - "uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true - }, - "uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "optional": true - }, - "underscore": { - "version": "1.13.7", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", - "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", - "dev": true - }, - "unist-util-is": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", - "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", - "dev": true, - "requires": { - "@types/unist": "^3.0.0" - } - }, - "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, - "requires": { - "@types/unist": "^3.0.0" - } - }, - "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, - "requires": { - "@types/unist": "^3.0.0" - } - }, - "unist-util-visit": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", - "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", - "dev": true, - "requires": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0", - "unist-util-visit-parents": "^6.0.0" - } - }, - "unist-util-visit-parents": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", - "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", - "dev": true, - "requires": { - "@types/unist": "^3.0.0", - "unist-util-is": "^6.0.0" - } - }, - "update-browserslist-db": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", - "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, - "requires": { - "escalade": "^3.1.2", - "picocolors": "^1.0.1" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - }, - "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, - "requires": { - "@types/unist": "^3.0.0", - "vfile-message": "^4.0.0" - } - }, - "vfile-message": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", - "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", - "dev": true, - "requires": { - "@types/unist": "^3.0.0", - "unist-util-stringify-position": "^4.0.0" - } - }, - "vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, - "requires": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "fsevents": "~2.3.3", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - } - }, - "vitepress": { - "version": "2.0.0-alpha.17", - "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-2.0.0-alpha.17.tgz", - "integrity": "sha512-Z3VPUpwk/bHYqt1uMVOOK1/4xFiWQov1GNc2FvMdz6kvje4JRXEOngVI9C+bi5jeedMSHiA4dwKkff1NCvbZ9Q==", - "dev": true, - "requires": { - "@docsearch/css": "^4.5.3", - "@docsearch/js": "^4.5.3", - "@docsearch/sidepanel-js": "^4.5.3", - "@iconify-json/simple-icons": "^1.2.69", - "@shikijs/core": "^3.22.0", - "@shikijs/transformers": "^3.22.0", - "@shikijs/types": "^3.22.0", - "@types/markdown-it": "^14.1.2", - "@vitejs/plugin-vue": "^6.0.4", - "@vue/devtools-api": "^8.0.5", - "@vue/shared": "^3.5.27", - "@vueuse/core": "^14.2.0", - "@vueuse/integrations": "^14.2.0", - "focus-trap": "^8.0.0", - "mark.js": "8.11.1", - "minisearch": "^7.2.0", - "shiki": "^3.22.0", - "vite": "^7.3.1", - "vue": "^3.5.27" - } - }, - "vue": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", - "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", - "dev": true, - "requires": { - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-sfc": "3.5.30", - "@vue/runtime-dom": "3.5.30", - "@vue/server-renderer": "3.5.30", - "@vue/shared": "3.5.30" - } - }, - "walk-back": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/walk-back/-/walk-back-5.1.1.tgz", - "integrity": "sha512-e/FRLDVdZQWFrAzU6Hdvpm7D7m2ina833gIKLptQykRK49mmCYHLHq7UqjPDbxbKLZkTkW1rFqbengdE3sLfdw==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", - "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true - }, - "word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "wordwrapjs": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.1.tgz", - "integrity": "sha512-0yweIbkINJodk27gX9LBGMzyQdBDan3s/dEAiwBOj+Mf0PPyWL6/rikalkv8EeD0E8jm4o5RXEOrFTP3NXbhJg==", - "dev": true - }, - "workerpool": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.2.tgz", - "integrity": "sha512-Xz4Nm9c+LiBHhDR5bDLnNzmj6+5F+cyEAWPMkbs2awq/dYazR/efelZzUAjB/y3kNHL+uzkHvxVVpaOfGCPV7A==", - "dev": true - }, - "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": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrap-ansi-cjs": { - "version": "npm:wrap-ansi@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": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "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" - } - }, - "xmlcreate": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-2.0.4.tgz", - "integrity": "sha512-nquOebG4sngPmGPICTS5EnxqhKbCmz5Ox5hsszI2T6U5qdrJizBc+0ilYSEjTSzU0yZcmvppztXe/5Al5fUwdg==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "requires": { - "cliui": "^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" - } - }, - "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 - }, - "yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "requires": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "dependencies": { - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - }, - "decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true - } - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true - }, - "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 - } } } diff --git a/package.json b/package.json index 79aeec4d..7a884de1 100644 --- a/package.json +++ b/package.json @@ -31,13 +31,13 @@ "type-is": "2.1.0" }, "devDependencies": { + "@biomejs/biome": "2.5.0", "chai": "6.2.2", - "eslint": "8.57.1", "jsdoc-to-markdown": "^9.1.3", - "mocha": "11.7.5", + "mocha": "^11.7.6", "nyc": "18.0.0", - "sinon": "21.0.3", - "vitepress": "^2.0.0-alpha.15" + "sinon": "^22.0.0", + "vitepress": "^2.0.0-alpha.17" }, "license": "MIT", "engines": { @@ -49,8 +49,10 @@ "test-debug": "NODE_ENV=test ./node_modules/.bin/mocha --inspect --debug-brk 'test/**/*_test.js'", "test:watch": "NODE_ENV=test ./node_modules/.bin/mocha --watch 'test/**/*_test.js'", "test:coverage": "NODE_ENV=test nyc --reporter=html --reporter=lcov --reporter=text ./node_modules/.bin/mocha 'test/**/*_test.js'", - "lint": "npx eslint .", - "lint:fix": "npx eslint . --fix", + "lint": "npx @biomejs/biome lint .", + "lint:fix": "npx @biomejs/biome lint --write .", + "format": "npx @biomejs/biome format .", + "format:fix": "npx @biomejs/biome format --write .", "docs:dev": "vitepress dev docs", "docs:build": "npm run docs:setup && npm run docs:api && vitepress build docs", "docs:preview": "vitepress preview docs", diff --git a/test/compliance/client-authentication_test.js b/test/compliance/client-authentication_test.js index 72624ec5..6fe39dbc 100644 --- a/test/compliance/client-authentication_test.js +++ b/test/compliance/client-authentication_test.js @@ -32,11 +32,11 @@ const auth = new OAuth2Server({ model: createModel(db) }); -const user = db.saveUser({ id: 1, username: 'test', password: 'test'}); +const user = db.saveUser({ id: 1, username: 'test', password: 'test' }); const client = db.saveClient({ id: 'a', secret: 'b', grants: ['password'] }); const scope = 'read write'; -function createDefaultRequest () { +function createDefaultRequest() { return createRequest({ body: { grant_type: 'password', @@ -45,10 +45,10 @@ function createDefaultRequest () { scope }, headers: { - 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + authorization: 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), 'content-type': 'application/x-www-form-urlencoded' }, - method: 'POST', + method: 'POST' }); } @@ -60,11 +60,12 @@ describe('Client Authentication Compliance', function () { delete request.headers.authorization; - await auth.token(request, response, {}) + await auth + .token(request, response, {}) .then((token) => { throw new Error('Should not be here'); - }). - catch(err => { + }) + .catch((err) => { err.name.should.equal('invalid_client'); }); }); @@ -84,11 +85,12 @@ describe('Client Authentication Compliance', function () { request.headers.authorization = 'Basic ' + Buffer.from('a:c').toString('base64'); - await auth.token(request, response, {}) + await auth + .token(request, response, {}) .then((token) => { throw new Error('Should not be here'); - }). - catch(err => { + }) + .catch((err) => { err.name.should.equal('invalid_client'); }); }); @@ -116,11 +118,12 @@ describe('Client Authentication Compliance', function () { request.body.client_id = 'a'; request.body.client_secret = 'c'; - await auth.token(request, response, {}) + await auth + .token(request, response, {}) .then((token) => { throw new Error('Should not be here'); }) - .catch(err => { + .catch((err) => { err.name.should.equal('invalid_client'); }); }); diff --git a/test/compliance/client-credential-workflow_test.js b/test/compliance/client-credential-workflow_test.js index 6c63c255..4d1b747e 100644 --- a/test/compliance/client-credential-workflow_test.js +++ b/test/compliance/client-credential-workflow_test.js @@ -77,16 +77,19 @@ describe('ClientCredentials Workflow Compliance (4.4)', function () { scope: enabledScope }, headers: { - 'authorization': 'Basic ' + Buffer.from(clientDoc.id + ':' + clientDoc.secret).toString('base64'), + authorization: 'Basic ' + Buffer.from(clientDoc.id + ':' + clientDoc.secret).toString('base64'), 'content-type': 'application/x-www-form-urlencoded' }, - method: 'POST', + method: 'POST' }); const token = await oAuth2Server.token(request, response); response.status.should.equal(200); - response.headers.should.deep.equal( { 'cache-control': 'no-store', pragma: 'no-cache' }); + response.headers.should.deep.equal({ + 'cache-control': 'no-store', + pragma: 'no-cache' + }); response.body.token_type.should.equal('Bearer'); response.body.access_token.should.equal(token.accessToken); response.body.expires_in.should.be.a('number'); @@ -119,11 +122,11 @@ describe('ClientCredentials Workflow Compliance (4.4)', function () { const [accessToken] = [...db.accessTokens.entries()][0]; const response = new Response(); const request = createRequest({ - query: {}, + query: {}, headers: { - 'authorization': `Bearer ${accessToken}` + authorization: `Bearer ${accessToken}` }, - method: 'GET', + method: 'GET' }); const token = await oAuth2Server.authenticate(request, response); diff --git a/test/compliance/password-grant-type_test.js b/test/compliance/password-grant-type_test.js index d82193af..bdde8be5 100644 --- a/test/compliance/password-grant-type_test.js +++ b/test/compliance/password-grant-type_test.js @@ -70,11 +70,11 @@ const auth = new OAuth2Server({ model: createModel(db) }); -const user = db.saveUser({ id: 1, username: 'test', password: 'test'}); +const user = db.saveUser({ id: 1, username: 'test', password: 'test' }); const client = db.saveClient({ id: 'a', secret: 'b', grants: ['password'] }); const scope = 'read write'; -function createDefaultRequest () { +function createDefaultRequest() { return createRequest({ body: { grant_type: 'password', @@ -83,16 +83,16 @@ function createDefaultRequest () { scope }, headers: { - 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + authorization: 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), 'content-type': 'application/x-www-form-urlencoded' }, - method: 'POST', + method: 'POST' }); } describe('PasswordGrantType Compliance', function () { describe('Authenticate', function () { - it ('Succesfull authorization', async function () { + it('Succesfull authorization', async function () { const request = createDefaultRequest(); const response = new Response({}); @@ -113,7 +113,7 @@ describe('PasswordGrantType Compliance', function () { db.refreshTokens.has(token.refreshToken).should.equal(true); }); - it ('Succesfull authorization and authentication', async function () { + it('Succesfull authorization and authentication', async function () { const tokenRequest = createDefaultRequest(); const tokenResponse = new Response({}); @@ -122,72 +122,65 @@ describe('PasswordGrantType Compliance', function () { const authenticationRequest = createRequest({ body: {}, headers: { - 'Authorization': `Bearer ${token.accessToken}` + Authorization: `Bearer ${token.accessToken}` }, method: 'GET', query: {} }); const authenticationResponse = new Response({}); - const authenticated = await auth.authenticate( - authenticationRequest, - authenticationResponse, - {}); + const authenticated = await auth.authenticate(authenticationRequest, authenticationResponse, {}); authenticated.scope.should.eql(['read', 'write']); authenticated.user.should.be.an('object'); authenticated.client.should.be.an('object'); }); - it ('Username missing', async function () { + it('Username missing', async function () { const request = createDefaultRequest(); const response = new Response({}); delete request.body.username; - await auth.token(request, response, {}) - .catch(err => { - err.name.should.equal('invalid_request'); - }); + await auth.token(request, response, {}).catch((err) => { + err.name.should.equal('invalid_request'); + }); }); - it ('Password missing', async function () { + it('Password missing', async function () { const request = createDefaultRequest(); const response = new Response({}); delete request.body.password; - await auth.token(request, response, {}) - .catch(err => { - err.name.should.equal('invalid_request'); - }); + await auth.token(request, response, {}).catch((err) => { + err.name.should.equal('invalid_request'); + }); }); - it ('Wrong username', async function () { + it('Wrong username', async function () { const request = createDefaultRequest(); const response = new Response({}); request.body.username = 'wrong'; - await auth.token(request, response, {}) - .catch(err => { - err.name.should.equal('invalid_grant'); - }); + await auth.token(request, response, {}).catch((err) => { + err.name.should.equal('invalid_grant'); + }); }); - it ('Wrong password', async function () { + it('Wrong password', async function () { const request = createDefaultRequest(); const response = new Response({}); request.body.password = 'wrong'; - await auth.token(request, response, {}) - .catch(err => { - err.name.should.equal('invalid_grant'); - }); + await auth.token(request, response, {}).catch((err) => { + err.name.should.equal('invalid_grant'); + }); }); - it ('Client not found', async function () { + it('Client not found', async function () { const request = createDefaultRequest(); const response = new Response({}); @@ -196,13 +189,12 @@ describe('PasswordGrantType Compliance', function () { request.headers.authorization = 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64'); - await auth.token(request, response, {}) - .catch(err => { - err.name.should.equal('invalid_client'); - }); + await auth.token(request, response, {}).catch((err) => { + err.name.should.equal('invalid_client'); + }); }); - it ('Client secret not required', async function () { + it('Client secret not required', async function () { const request = createDefaultRequest(); const response = new Response({}); @@ -217,18 +209,19 @@ describe('PasswordGrantType Compliance', function () { token.accessToken.should.be.a('string'); }); - it ('Client secret required', async function () { + it('Client secret required', async function () { const request = createDefaultRequest(); const response = new Response({}); delete request.body.client_secret; - await auth.token(request, response, { - requireClientAuthentication: { - password: false - } - }) - .catch(err => { + await auth + .token(request, response, { + requireClientAuthentication: { + password: false + } + }) + .catch((err) => { err.name.should.equal('invalid_client'); }); }); diff --git a/test/compliance/pkce_test.js b/test/compliance/pkce_test.js index fa46b8fd..4569ce6c 100644 --- a/test/compliance/pkce_test.js +++ b/test/compliance/pkce_test.js @@ -52,7 +52,7 @@ require('chai').should(); * Compute the S256 code_challenge for a given verifier, * using the same logic the server uses internally. */ -function computeS256Challenge (verifier) { +function computeS256Challenge(verifier) { const hash = createHash({ data: verifier }); return base64URLEncode(hash); } @@ -63,7 +63,11 @@ describe('PKCE Compliance (RFC 7636)', function () { // --------------------------------------------------------------- let db, oAuth2Server; - const userDoc = { id: 'pkce-user-1', username: 'pkceuser', password: 'pkcepass' }; + const userDoc = { + id: 'pkce-user-1', + username: 'pkceuser', + password: 'pkcepass' + }; const clientDoc = { id: 'pkce-client', secret: 'pkce-secret', @@ -79,7 +83,7 @@ describe('PKCE Compliance (RFC 7636)', function () { * @param {string} method Optional code_challenge_method to use (default "S256"). For testing the "plain" method, set this to "plain" and ensure the verifier is the same as the challenge. * @return {object} The authorization code document that was seeded into the DB. */ - function seedAuthorizationCode (verifier, codeValue, method = 'S256') { + function seedAuthorizationCode(verifier, codeValue, method = 'S256') { codeValue = codeValue || 'auth-code-' + Math.random().toString(36).slice(2); const codeChallenge = computeS256Challenge(verifier); const codeDoc = { @@ -103,7 +107,7 @@ describe('PKCE Compliance (RFC 7636)', function () { * @param {string} codeVerifier The code_verifier to include in the request. * @returns {Request} The constructed request object. */ - function tokenRequest (code, codeVerifier) { + function tokenRequest(code, codeVerifier) { return createRequest({ body: { grant_type: 'authorization_code', @@ -112,7 +116,7 @@ describe('PKCE Compliance (RFC 7636)', function () { code_verifier: codeVerifier }, headers: { - 'authorization': 'Basic ' + Buffer.from(clientDoc.id + ':' + clientDoc.secret).toString('base64'), + authorization: 'Basic ' + Buffer.from(clientDoc.id + ':' + clientDoc.secret).toString('base64'), 'content-type': 'application/x-www-form-urlencoded' }, method: 'POST' @@ -205,8 +209,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Server issued a token for a 1-character code_verifier ("z"). ' + - 'RFC 7636 §4.1 ABNF requires 43..128 unreserved characters; accepting shorter ' + - 'values breaks the entropy guarantee of Appendix B.' + 'RFC 7636 §4.1 ABNF requires 43..128 unreserved characters; accepting shorter ' + + 'values breaks the entropy guarantee of Appendix B.' ); } }); @@ -231,8 +235,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Server issued a token for a 42-character code_verifier. ' + - 'RFC 7636 §4.1 ABNF minimum is 43 characters; server-side enforcement ' + - 'is needed to preserve the entropy guarantee of Appendix B.' + 'RFC 7636 §4.1 ABNF minimum is 43 characters; server-side enforcement ' + + 'is needed to preserve the entropy guarantee of Appendix B.' ); } }); @@ -257,8 +261,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Server issued a token for a 129-character code_verifier. ' + - 'RFC 7636 §4.1 ABNF maximum is 128 characters; server-side enforcement ' + - 'is needed to preserve the entropy guarantee of Appendix B.' + 'RFC 7636 §4.1 ABNF maximum is 128 characters; server-side enforcement ' + + 'is needed to preserve the entropy guarantee of Appendix B.' ); } }); @@ -283,7 +287,7 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Server issued a token for a code_verifier containing ' + - 'forbidden characters (space). RFC 7636 §4.1 restricts to unreserved characters.' + 'forbidden characters (space). RFC 7636 §4.1 restricts to unreserved characters.' ); } }); @@ -337,8 +341,7 @@ describe('PKCE Compliance (RFC 7636)', function () { if (codeStillExists) { throw new Error( - 'Authorization code was NOT revoked after a failed ' + - 'code_verifier attempt. An attacker can keep guessing.' + 'Authorization code was NOT revoked after a failed ' + 'code_verifier attempt. An attacker can keep guessing.' ); } }); @@ -373,8 +376,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( `Brute-forced code_verifier in ${tries} tries ` + - `(guess="${successfulGuess}"). The authorization code was not ` + - 'consumed after failed attempts, allowing online guessing.' + `(guess="${successfulGuess}"). The authorization code was not ` + + 'consumed after failed attempts, allowing online guessing.' ); } }); @@ -417,8 +420,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Authorization code was still valid after a prior ' + - 'failed PKCE attempt. The code should have been revoked on the first ' + - 'failed verification to prevent further guessing.' + 'failed PKCE attempt. The code should have been revoked on the first ' + + 'failed verification to prevent further guessing.' ); } }); @@ -499,9 +502,9 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Server issued a token using "plain" PKCE method. ' + - 'While RFC 7636 §4.3 requires server support for "plain", the OAuth 2.0 ' + - 'Security BCP and OAuth 2.1 deprecate it because code_challenge === code_verifier ' + - 'offers zero cryptographic protection.' + 'While RFC 7636 §4.3 requires server support for "plain", the OAuth 2.0 ' + + 'Security BCP and OAuth 2.1 deprecate it because code_challenge === code_verifier ' + + 'offers zero cryptographic protection.' ); } }); @@ -564,8 +567,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Server with enablePlainPKCE=false still issued ' + - 'a token using "plain" PKCE method. The option should cause the server to ' + - 'reject any plain code_challenge_method.' + 'a token using "plain" PKCE method. The option should cause the server to ' + + 'reject any plain code_challenge_method.' ); } @@ -616,8 +619,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Attacker redeemed an authorization code by using ' + - 'the intercepted code_challenge as code_verifier (plain method). ' + - 'This defeats PKCE entirely for public clients.' + 'the intercepted code_challenge as code_verifier (plain method). ' + + 'This defeats PKCE entirely for public clients.' ); } }); @@ -665,8 +668,8 @@ describe('PKCE Compliance (RFC 7636)', function () { if (tokenIssued) { throw new Error( 'Attacker redeemed an authorization code by using ' + - 'the intercepted code_challenge as code_verifier (custom method). ' + - 'This defeats PKCE entirely for public clients.' + 'the intercepted code_challenge as code_verifier (custom method). ' + + 'This defeats PKCE entirely for public clients.' ); } }); diff --git a/test/compliance/refresh-token-grant-type_test.js b/test/compliance/refresh-token-grant-type_test.js index fd3d40da..456f0a54 100644 --- a/test/compliance/refresh-token-grant-type_test.js +++ b/test/compliance/refresh-token-grant-type_test.js @@ -14,7 +14,6 @@ * resource owner. */ - /** * Response * @see https://datatracker.ietf.org/doc/html/rfc6749#section-5.1 @@ -72,11 +71,15 @@ const auth = new OAuth2Server({ model: createModel(db) }); -const user = db.saveUser({ id: 1, username: 'test', password: 'test'}); -const client = db.saveClient({ id: 'a', secret: 'b', grants: ['password', 'refresh_token'] }); +const user = db.saveUser({ id: 1, username: 'test', password: 'test' }); +const client = db.saveClient({ + id: 'a', + secret: 'b', + grants: ['password', 'refresh_token'] +}); const scope = 'read write'; -function createLoginRequest () { +function createLoginRequest() { return createRequest({ body: { grant_type: 'password', @@ -85,14 +88,14 @@ function createLoginRequest () { scope }, headers: { - 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + authorization: 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), 'content-type': 'application/x-www-form-urlencoded' }, - method: 'POST', + method: 'POST' }); } -function createRefreshRequest (refresh_token) { +function createRefreshRequest(refresh_token) { return createRequest({ method: 'POST', body: { @@ -101,7 +104,7 @@ function createRefreshRequest (refresh_token) { scope }, headers: { - 'authorization': 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), + authorization: 'Basic ' + Buffer.from(client.id + ':' + client.secret).toString('base64'), 'content-type': 'application/x-www-form-urlencoded' } }); @@ -140,10 +143,12 @@ describe('RefreshTokenGrantType Compliance', function () { const request = createRefreshRequest('invalid'); const response = new Response({}); - await auth.token(request, response, {}) + await auth + .token(request, response, {}) .then(() => { throw Error('Should not reach this'); - }).catch(err => { + }) + .catch((err) => { err.name.should.equal('invalid_grant'); }); }); @@ -159,9 +164,10 @@ describe('RefreshTokenGrantType Compliance', function () { refreshRequest.body.scope = 'invalid'; - await auth.token(refreshRequest, refreshResponse, {}) + await auth + .token(refreshRequest, refreshResponse, {}) .then(should.fail) - .catch(err => { + .catch((err) => { err.name.should.equal('invalid_scope'); }); }); @@ -179,9 +185,10 @@ describe('RefreshTokenGrantType Compliance', function () { refreshRequest.scope = 'read write'; - await auth.token(refreshRequest, refreshResponse, {}) + await auth + .token(refreshRequest, refreshResponse, {}) .then(should.fail) - .catch(err => { + .catch((err) => { err.name.should.equal('invalid_scope'); }); }); @@ -199,9 +206,10 @@ describe('RefreshTokenGrantType Compliance', function () { refreshRequest.scope = 'read write'; - await auth.token(refreshRequest, refreshResponse, {}) + await auth + .token(refreshRequest, refreshResponse, {}) .then(should.fail) - .catch(err => { + .catch((err) => { err.name.should.equal('invalid_scope'); }); }); diff --git a/test/helpers/db.js b/test/helpers/db.js index 147d1741..fbd9a36b 100644 --- a/test/helpers/db.js +++ b/test/helpers/db.js @@ -1,35 +1,35 @@ class DB { - constructor () { + constructor() { this.users = new Map(); this.clients = []; this.accessTokens = new Map(); - this.refreshTokens= new Map(); + this.refreshTokens = new Map(); } - saveUser (user) { + saveUser(user) { this.users.set(user.id, user); return user; } - findUser (username, password) { - return Array.from(this.users.values()).find(user => { + findUser(username, password) { + return Array.from(this.users.values()).find((user) => { return user.username === username && user.password === password; }); } - findUserById (id) { + findUserById(id) { return this.users.get(id); } - saveClient (client) { + saveClient(client) { this.clients.push(client); return client; } - findClient (clientId, clientSecret) { - return this.clients.find(client => { + findClient(clientId, clientSecret) { + return this.clients.find((client) => { if (clientSecret) { return client.id === clientId && client.secret === clientSecret; } else { @@ -38,31 +38,31 @@ class DB { }); } - findClientById (id) { - return this.clients.find(client => client.id === id); + findClientById(id) { + return this.clients.find((client) => client.id === id); } - saveAccessToken (accessToken, meta) { + saveAccessToken(accessToken, meta) { this.accessTokens.set(accessToken, meta); } - findAccessToken (accessToken) { + findAccessToken(accessToken) { return this.accessTokens.get(accessToken); } - deleteAccessToken (accessToken) { + deleteAccessToken(accessToken) { this.accessTokens.delete(accessToken); } - saveRefreshToken (refreshToken, meta) { + saveRefreshToken(refreshToken, meta) { this.refreshTokens.set(refreshToken, meta); } - findRefreshToken (refreshToken) { + findRefreshToken(refreshToken) { return this.refreshTokens.get(refreshToken); } - deleteRefreshToken (refreshToken) { + deleteRefreshToken(refreshToken) { this.refreshTokens.delete(refreshToken); } } diff --git a/test/helpers/model.js b/test/helpers/model.js index 12507bbf..dcf0addc 100644 --- a/test/helpers/model.js +++ b/test/helpers/model.js @@ -1,16 +1,16 @@ const Model = require('../../lib/model'); const scopes = ['read', 'write']; -function createModel (db) { - async function getUser (username, password) { +function createModel(db) { + async function getUser(username, password) { return db.findUser(username, password); } - async function getClient (clientId, clientSecret) { + async function getClient(clientId, clientSecret) { return db.findClient(clientId, clientSecret); } - async function saveToken (token, client, user) { + async function saveToken(token, client, user) { if (token.scope && !Array.isArray(token.scope)) { throw new Error('Scope should internally be an array'); } @@ -36,7 +36,7 @@ function createModel (db) { return token; } - async function getAccessToken (accessToken) { + async function getAccessToken(accessToken) { const meta = db.findAccessToken(accessToken); if (!meta) { @@ -54,7 +54,7 @@ function createModel (db) { }; } - async function getRefreshToken (refreshToken) { + async function getRefreshToken(refreshToken) { const meta = db.findRefreshToken(refreshToken); if (!meta) { @@ -72,20 +72,20 @@ function createModel (db) { }; } - async function revokeToken (token) { + async function revokeToken(token) { db.deleteRefreshToken(token.refreshToken); return true; } - async function verifyScope (token, scope) { + async function verifyScope(token, scope) { if (!Array.isArray(scope)) { throw new Error('Scope should internally be an array'); } - return scope.every(s => scopes.includes(s)); + return scope.every((s) => scopes.includes(s)); } - return Model.from({ + return Model.from({ getUser, getClient, saveToken, diff --git a/test/integration/grant-types/abstract-grant-type_test.js b/test/integration/grant-types/abstract-grant-type_test.js index 202c7084..df0f588a 100644 --- a/test/integration/grant-types/abstract-grant-type_test.js +++ b/test/integration/grant-types/abstract-grant-type_test.js @@ -15,9 +15,9 @@ const should = require('chai').should(); * Test `AbstractGrantType` integration. */ -describe('AbstractGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.accessTokenLifetime` is missing', function() { +describe('AbstractGrantType integration', function () { + describe('constructor()', function () { + it('should throw an error if `options.accessTokenLifetime` is missing', function () { try { new AbstractGrantType(); @@ -28,7 +28,7 @@ describe('AbstractGrantType integration', function() { } }); - it('should throw an error if `options.model` is missing', function() { + it('should throw an error if `options.model` is missing', function () { try { new AbstractGrantType({ accessTokenLifetime: 123 }); @@ -39,106 +39,157 @@ describe('AbstractGrantType integration', function() { } }); - it('should set the `accessTokenLifetime`', function() { - const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {} }); + it('should set the `accessTokenLifetime`', function () { + const grantType = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {} + }); grantType.accessTokenLifetime.should.equal(123); }); - it('should set the `model`', function() { - const model = Model.from({ async generateAccessToken () {} }); - const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: model }); + it('should set the `model`', function () { + const model = Model.from({ async generateAccessToken() {} }); + const grantType = new AbstractGrantType({ + accessTokenLifetime: 123, + model: model + }); grantType.model.should.equal(model); }); - it('should set the `refreshTokenLifetime`', function() { - const grantType = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + it('should set the `refreshTokenLifetime`', function () { + const grantType = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); grantType.refreshTokenLifetime.should.equal(456); }); }); - describe('generateAccessToken()', function() { - it('should return an access token', async function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + describe('generateAccessToken()', function () { + it('should return an access token', async function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); const accessToken = await handler.generateAccessToken(); accessToken.should.be.a.sha256(); }); - it('should support promises', async function() { + it('should support promises', async function () { const model = Model.from({ - generateAccessToken: async function() { + generateAccessToken: async function () { return 'long-hash-foo-bar'; } }); - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 456 + }); const accessToken = await handler.generateAccessToken(); accessToken.should.equal('long-hash-foo-bar'); }); - it('should support non-promises', async function() { + it('should support non-promises', async function () { const model = Model.from({ - generateAccessToken: function() { + generateAccessToken: function () { return 'long-hash-foo-bar'; } }); - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 456 + }); const accessToken = await handler.generateAccessToken(); accessToken.should.equal('long-hash-foo-bar'); }); }); - describe('generateRefreshToken()', function() { - it('should return a refresh token', async function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + describe('generateRefreshToken()', function () { + it('should return a refresh token', async function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); const refreshToken = await handler.generateRefreshToken(); refreshToken.should.be.a.sha256(); }); - it('should support promises', async function() { + it('should support promises', async function () { const model = Model.from({ - generateRefreshToken: async function() { + generateRefreshToken: async function () { return 'long-hash-foo-bar'; } }); - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 456 + }); const refreshToken = await handler.generateRefreshToken(); refreshToken.should.equal('long-hash-foo-bar'); }); - it('should support non-promises', async function() { + it('should support non-promises', async function () { const model = Model.from({ - generateRefreshToken: function() { + generateRefreshToken: function () { return 'long-hash-foo-bar'; } }); - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 456 + }); const refreshToken = await handler.generateRefreshToken(); refreshToken.should.equal('long-hash-foo-bar'); }); }); - describe('getAccessTokenExpiresAt()', function() { - it('should return a date', function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + describe('getAccessTokenExpiresAt()', function () { + it('should return a date', function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); handler.getAccessTokenExpiresAt().should.be.an.instanceOf(Date); }); }); - describe('getRefreshTokenExpiresAt()', function() { - it('should return a refresh token', function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + describe('getRefreshTokenExpiresAt()', function () { + it('should return a refresh token', function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); handler.getRefreshTokenExpiresAt().should.be.an.instanceOf(Date); }); }); - describe('getScope()', function() { - it('should throw an error if `scope` is invalid', function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - const request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + describe('getScope()', function () { + it('should throw an error if `scope` is invalid', function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); + const request = new Request({ + body: { scope: 'øå€£‰' }, + headers: {}, + method: {}, + query: {} + }); try { handler.getScope(request); @@ -150,16 +201,34 @@ describe('AbstractGrantType integration', function() { } }); - it('should allow the `scope` to be `undefined`', function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + it('should allow the `scope` to be `undefined`', function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); should.not.exist(handler.getScope(request)); }); - it('should return the scope', function() { - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); - const request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); + it('should return the scope', function () { + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); + const request = new Request({ + body: { scope: 'foo' }, + headers: {}, + method: {}, + query: {} + }); handler.getScope(request).should.eql(['foo']); }); @@ -170,7 +239,11 @@ describe('AbstractGrantType integration', function() { const scope = ['some,scope,this,that']; const user = { id: 123 }; const client = { id: 456 }; - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model: {}, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model: {}, + refreshTokenLifetime: 456 + }); const validated = await handler.validateScope(user, client, scope); validated.should.eql(scope); }); @@ -181,7 +254,7 @@ describe('AbstractGrantType integration', function() { const client = { id: 456 }; const model = Model.from({ - async validateScope (_user, _client, _scope) { + async validateScope(_user, _client, _scope) { // make sure the model received the correct args _user.should.deep.equal(user); _client.should.deep.equal(_client); @@ -190,7 +263,11 @@ describe('AbstractGrantType integration', function() { return scope; } }); - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456 + }); const validated = await handler.validateScope(user, client, scope); validated.should.eql(scope); }); @@ -203,7 +280,7 @@ describe('AbstractGrantType integration', function() { for (const type of returnTypes) { const model = Model.from({ - async validateScope (_user, _client, _scope) { + async validateScope(_user, _client, _scope) { // make sure the model received the correct args _user.should.deep.equal(user); _client.should.deep.equal(_client); @@ -212,7 +289,11 @@ describe('AbstractGrantType integration', function() { return type; } }); - const handler = new AbstractGrantType({ accessTokenLifetime: 123, model, refreshTokenLifetime: 456 }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 123, + model, + refreshTokenLifetime: 456 + }); try { await handler.validateScope(user, client, scope); diff --git a/test/integration/grant-types/authorization-code-grant-type_test.js b/test/integration/grant-types/authorization-code-grant-type_test.js index c3ec4c09..d91b6265 100644 --- a/test/integration/grant-types/authorization-code-grant-type_test.js +++ b/test/integration/grant-types/authorization-code-grant-type_test.js @@ -17,9 +17,9 @@ const should = require('chai').should(); * Test `AuthorizationCodeGrantType` integration. */ -describe('AuthorizationCodeGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { +describe('AuthorizationCodeGrantType integration', function () { + describe('constructor()', function () { + it('should throw an error if `model` is missing', function () { try { new AuthorizationCodeGrantType(); @@ -30,7 +30,7 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if the model does not implement `getAuthorizationCode()`', function() { + it('should throw an error if the model does not implement `getAuthorizationCode()`', function () { try { new AuthorizationCodeGrantType({ model: {} }); @@ -41,10 +41,10 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if the model does not implement `revokeAuthorizationCode()`', function() { + it('should throw an error if the model does not implement `revokeAuthorizationCode()`', function () { try { const model = Model.from({ - getAuthorizationCode: function() {} + getAuthorizationCode: function () {} }); new AuthorizationCodeGrantType({ model: model }); @@ -56,11 +56,11 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if the model does not implement `saveToken()`', function() { + it('should throw an error if the model does not implement `saveToken()`', function () { try { const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {} + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () {} }); new AuthorizationCodeGrantType({ model: model }); @@ -73,14 +73,17 @@ describe('AuthorizationCodeGrantType integration', function() { }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing', async function () { const model = Model.from({ getAuthorizationCode: () => should.fail(), revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); try { await grantType.handle(); @@ -90,18 +93,30 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `client` is invalid (not in code)', async function() { + it('should throw an error if `client` is invalid (not in code)', async function () { const client = { id: 1234 }; const model = Model.from({ - getAuthorizationCode: function(code) { + getAuthorizationCode: function (code) { code.should.equal(123456789); - return { authorizationCode: 12345, expiresAt: new Date(new Date() * 2), user: {} }; + return { + authorizationCode: 12345, + expiresAt: new Date(new Date() * 2), + user: {} + }; }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 123456789 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 123456789 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.handle(request, client); @@ -112,25 +127,32 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `client` is missing', function() { + it('should throw an error if `client` is missing', function () { const model = Model.from({ getAuthorizationCode: () => should.fail(), revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { grantType.handle(request, null); - } - catch (e) { + } catch (e) { e.should.be.an.instanceOf(InvalidArgumentError); e.message.should.equal('Missing parameter: `client`'); } }); - it('should return a token', async function() { + it('should return a token', async function () { const client = { id: 'foobar' }; const scope = ['fooscope']; const user = { name: 'foouser' }; @@ -178,11 +200,19 @@ describe('AuthorizationCodeGrantType integration', function() { _token.accessTokenExpiresAt.should.be.instanceOf(Date); _token.refreshTokenExpiresAt.should.be.instanceOf(Date); return _token; - }, + } }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 'code-1234' }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 'code-1234' }, + headers: {}, + method: {}, + query: {} + }); const token = await grantType.handle(request, client); token.accessToken.should.equal('long-access-token-hash'); @@ -192,43 +222,85 @@ describe('AuthorizationCodeGrantType integration', function() { token.refreshTokenExpiresAt.should.be.instanceOf(Date); }); - it('should support promises', function() { + it('should support promises', function () { const client = { id: 'foobar' }; const model = Model.from({ - getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} + getAuthorizationCode: function () { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() * 2), + user: {} + }; + }, + revokeAuthorizationCode: function () { + return true; + }, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const client = { id: 'foobar' }; const model = Model.from({ - getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} + getAuthorizationCode: function () { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() * 2), + user: {} + }; + }, + revokeAuthorizationCode: function () { + return true; + }, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); }); - describe('getAuthorizationCode()', function() { - it('should throw an error if the request body does not contain `code`', async function() { + describe('getAuthorizationCode()', function () { + it('should throw an error if the request body does not contain `code`', async function () { const client = {}; const model = Model.from({ getAuthorizationCode: () => should.fail(), revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -238,15 +310,23 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `code` is invalid', async function() { + it('should throw an error if `code` is invalid', async function () { const client = {}; const model = Model.from({ getAuthorizationCode: () => should.fail(), revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 'øå€£‰' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -257,15 +337,23 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `authorizationCode` is missing', async function() { + it('should throw an error if `authorizationCode` is missing', async function () { const client = {}; const model = Model.from({ - getAuthorizationCode: async function() {}, + getAuthorizationCode: async function () {}, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -276,15 +364,25 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `authorizationCode.client` is missing', async function() { + it('should throw an error if `authorizationCode.client` is missing', async function () { const client = {}; const model = Model.from({ - getAuthorizationCode: async function() { return { authorizationCode: 12345 }; }, + getAuthorizationCode: async function () { + return { authorizationCode: 12345 }; + }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -295,17 +393,25 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `authorizationCode.expiresAt` is missing', async function() { + it('should throw an error if `authorizationCode.expiresAt` is missing', async function () { const client = {}; const model = Model.from({ - getAuthorizationCode: async function() { + getAuthorizationCode: async function () { return { authorizationCode: 12345, client: {}, user: {} }; }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -316,17 +422,29 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `authorizationCode.user` is missing', async function() { + it('should throw an error if `authorizationCode.user` is missing', async function () { const client = {}; const model = Model.from({ - getAuthorizationCode: async function() { - return { authorizationCode: 12345, client: {}, expiresAt: new Date() }; + getAuthorizationCode: async function () { + return { + authorizationCode: 12345, + client: {}, + expiresAt: new Date() + }; }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -337,17 +455,30 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if the client id does not match', async function() { + it('should throw an error if the client id does not match', async function () { const client = { id: 123 }; const model = Model.from({ - getAuthorizationCode: async function() { - return { authorizationCode: 12345, expiresAt: new Date(), client: { id: 456 }, user: {} }; + getAuthorizationCode: async function () { + return { + authorizationCode: 12345, + expiresAt: new Date(), + client: { id: 456 }, + user: {} + }; }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -358,18 +489,31 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if the auth code is expired', async function() { + it('should throw an error if the auth code is expired', async function () { const client = { id: 123 }; const date = new Date(new Date() / 2); const model = Model.from({ - getAuthorizationCode: async function() { - return { authorizationCode: 12345, client: { id: 123 }, expiresAt: date, user: {} }; + getAuthorizationCode: async function () { + return { + authorizationCode: 12345, + client: { id: 123 }, + expiresAt: date, + user: {} + }; }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -380,16 +524,32 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if the `redirectUri` is invalid (format)', async function() { - const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), redirectUri: 'foobar', user: {} }; + it('should throw an error if the `redirectUri` is invalid (format)', async function () { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() * 2), + redirectUri: 'foobar', + user: {} + }; const client = { id: 'foobar' }; const model = Model.from({ - getAuthorizationCode: async function() { return authorizationCode; }, + getAuthorizationCode: async function () { + return authorizationCode; + }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getAuthorizationCode(request, client); @@ -400,67 +560,122 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should return an auth code', async function() { + it('should return an auth code', async function () { const authorizationCode = { authorizationCode: 1234567, client: { id: 'foobar' }, - expiresAt: new Date(new Date() * 2), user: {} + expiresAt: new Date(new Date() * 2), + user: {} }; const client = { id: 'foobar' }; const model = Model.from({ - getAuthorizationCode: async function(_code) { + getAuthorizationCode: async function (_code) { _code.should.equal(12345); return authorizationCode; }, revokeAuthorizationCode: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} + }); const code = await grantType.getAuthorizationCode(request, client); code.should.deep.equal(authorizationCode); }); - it('should support promises', function() { - const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; + it('should support promises', function () { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() * 2), + user: {} + }; const client = { id: 'foobar' }; const model = Model.from({ - getAuthorizationCode: async function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} + getAuthorizationCode: async function () { + return authorizationCode; + }, + revokeAuthorizationCode: function () {}, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { - const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; + it('should support non-promises', function () { + const authorizationCode = { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() * 2), + user: {} + }; const client = { id: 'foobar' }; const model = Model.from({ - getAuthorizationCode: function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} + getAuthorizationCode: function () { + return authorizationCode; + }, + revokeAuthorizationCode: function () {}, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); grantType.getAuthorizationCode(request, client).should.be.an.instanceOf(Promise); }); }); - describe('validateRedirectUri()', function() { - it('should throw an error if `redirectUri` is missing', function() { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; + describe('validateRedirectUri()', function () { + it('should throw an error if `redirectUri` is missing', function () { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + redirectUri: 'http://foo.bar', + user: {} + }; const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return authorizationCode; }, - saveToken: function() {} + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () { + return authorizationCode; + }, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); try { grantType.validateRedirectUri(request, authorizationCode); @@ -472,15 +687,31 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should throw an error if `redirectUri` is invalid', function() { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; + it('should throw an error if `redirectUri` is invalid', function () { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + redirectUri: 'http://foo.bar', + user: {} + }; const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () { + return true; + }, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345, redirect_uri: 'http://bar.foo' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345, redirect_uri: 'http://bar.foo' }, headers: {}, method: {}, query: {} }); try { grantType.validateRedirectUri(request, authorizationCode); @@ -492,51 +723,83 @@ describe('AuthorizationCodeGrantType integration', function() { } }); it('returns undefined and does not throw if `redirectUri` is valid', async function () { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), redirectUri: 'http://foo.bar', user: {} }; + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + redirectUri: 'http://foo.bar', + user: {} + }; const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() { return true; }, - saveToken: function() {} + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () { + return true; + }, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345, redirect_uri: 'http://foo.bar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345, redirect_uri: 'http://foo.bar' }, headers: {}, method: {}, query: {} }); const value = grantType.validateRedirectUri(request, authorizationCode); const isUndefined = value === undefined; isUndefined.should.equal(true); }); }); - describe('revokeAuthorizationCode()', function() { - it('should revoke the auth code', async function() { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + describe('revokeAuthorizationCode()', function () { + it('should revoke the auth code', async function () { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + user: {} + }; const model = Model.from({ getAuthorizationCode: () => should.fail(), - revokeAuthorizationCode: async function(_code) { + revokeAuthorizationCode: async function (_code) { _code.should.equal(authorizationCode); return true; }, saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); const data = await grantType.revokeAuthorizationCode(authorizationCode); data.should.deep.equal(authorizationCode); }); - it('should throw an error when the auth code is invalid', async function() { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + it('should throw an error when the auth code is invalid', async function () { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + user: {} + }; const returnTypes = [false, null, undefined, 0, '']; for (const type of returnTypes) { const model = Model.from({ getAuthorizationCode: () => should.fail(), - revokeAuthorizationCode: async function(_code) { + revokeAuthorizationCode: async function (_code) { _code.should.equal(authorizationCode); return type; }, saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); try { await grantType.revokeAuthorizationCode(authorizationCode); @@ -548,36 +811,56 @@ describe('AuthorizationCodeGrantType integration', function() { } }); - it('should support promises', function() { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + it('should support promises', function () { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + user: {} + }; const model = Model.from({ getAuthorizationCode: () => should.fail(), - revokeAuthorizationCode: async function() { return true; }, + revokeAuthorizationCode: async function () { + return true; + }, saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { - const authorizationCode = { authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() / 2), user: {} }; + it('should support non-promises', function () { + const authorizationCode = { + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() / 2), + user: {} + }; const model = Model.from({ getAuthorizationCode: () => should.fail(), - revokeAuthorizationCode: function() { return authorizationCode; }, + revokeAuthorizationCode: function () { + return authorizationCode; + }, saveToken: () => should.fail() }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); grantType.revokeAuthorizationCode(authorizationCode).should.be.an.instanceOf(Promise); }); }); - describe('saveToken()', function() { - it('should save the token', async function() { + describe('saveToken()', function () { + it('should save the token', async function () { const token = { foo: 'bar' }; const model = Model.from({ getAuthorizationCode: () => should.fail(), revokeAuthorizationCode: () => should.fail(), - saveToken: function(_token, _client= 'fallback', _user= 'fallback') { + saveToken: function (_token, _client = 'fallback', _user = 'fallback') { _token.accessToken.should.be.a.sha256(); _token.accessTokenExpiresAt.should.be.instanceOf(Date); _token.refreshTokenExpiresAt.should.be.instanceOf(Date); @@ -588,38 +871,51 @@ describe('AuthorizationCodeGrantType integration', function() { _client.should.equal('fallback'); return token; }, - validateScope: function(_user= 'fallback', _client= 'fallback', _scope = ['fallback']) { + validateScope: function (_user = 'fallback', _client = 'fallback', _scope = ['fallback']) { _user.should.equal('fallback'); _client.should.equal('fallback'); _scope.should.eql(['fallback']); return ['foo']; } }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); const data = await grantType.saveToken(); data.should.equal(token); }); - it('should support promises', function() { + it('should support promises', function () { const token = {}; const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: async function() { return token; } + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () {}, + saveToken: async function () { + return token; + } + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const token = {}; const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, - saveToken: function() { return token; } + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () {}, + saveToken: function () { + return token; + } + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/grant-types/client-credentials-grant-type_test.js b/test/integration/grant-types/client-credentials-grant-type_test.js index 813a2081..0f17b78e 100644 --- a/test/integration/grant-types/client-credentials-grant-type_test.js +++ b/test/integration/grant-types/client-credentials-grant-type_test.js @@ -15,9 +15,9 @@ const should = require('chai').should(); * Test `ClientCredentialsGrantType` integration. */ -describe('ClientCredentialsGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { +describe('ClientCredentialsGrantType integration', function () { + describe('constructor()', function () { + it('should throw an error if `model` is missing', function () { try { new ClientCredentialsGrantType(); @@ -28,7 +28,7 @@ describe('ClientCredentialsGrantType integration', function() { } }); - it('should throw an error if the model does not implement `getUserFromClient()`', function() { + it('should throw an error if the model does not implement `getUserFromClient()`', function () { try { new ClientCredentialsGrantType({ model: {} }); @@ -39,10 +39,10 @@ describe('ClientCredentialsGrantType integration', function() { } }); - it('should throw an error if the model does not implement `saveToken()`', function() { + it('should throw an error if the model does not implement `saveToken()`', function () { try { const model = Model.from({ - getUserFromClient: function() {} + getUserFromClient: function () {} }); new ClientCredentialsGrantType({ model: model }); @@ -55,13 +55,16 @@ describe('ClientCredentialsGrantType integration', function() { }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing', async function () { const model = Model.from({ - getUserFromClient: function() {}, - saveToken: function() {} + getUserFromClient: function () {}, + saveToken: function () {} + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); try { await grantType.handle(); @@ -73,13 +76,21 @@ describe('ClientCredentialsGrantType integration', function() { } }); - it('should throw an error if `client` is missing', async function() { + it('should throw an error if `client` is missing', async function () { const model = Model.from({ - getUserFromClient: function() {}, - saveToken: function() {} + getUserFromClient: function () {}, + saveToken: function () {} + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { await grantType.handle(request); @@ -91,18 +102,18 @@ describe('ClientCredentialsGrantType integration', function() { } }); - it('should return a token', async function() { + it('should return a token', async function () { const token = {}; const client = { foo: 'bar' }; const user = { name: 'foo' }; const scope = ['fooscope']; const model = Model.from({ - getUserFromClient: async function(_client) { + getUserFromClient: async function (_client) { _client.should.deep.equal(client); return { ...user }; }, - saveToken: async function(_token, _client, _user) { + saveToken: async function (_token, _client, _user) { _client.should.deep.equal(client); _user.should.deep.equal(user); _token.accessToken.should.equal('long-access-token-hash'); @@ -123,127 +134,216 @@ describe('ClientCredentialsGrantType integration', function() { return 'long-access-token-hash'; } }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: { scope: scope.join(' ') }, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: { scope: scope.join(' ') }, + headers: {}, + method: {}, + query: {} + }); const data = await grantType.handle(request, client); data.should.equal(token); }); - it('should support promises', function() { + it('should support promises', function () { const token = {}; const model = Model.from({ - getUserFromClient: async function() { return {}; }, - saveToken: async function() { return token; } + getUserFromClient: async function () { + return {}; + }, + saveToken: async function () { + return token; + } + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.handle(request, {}).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const token = {}; const model = Model.from({ - getUserFromClient: function() { return {}; }, - saveToken: function() { return token; } + getUserFromClient: function () { + return {}; + }, + saveToken: function () { + return token; + } + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); grantType.handle(request, {}).should.be.an.instanceOf(Promise); }); }); - describe('getUserFromClient()', function() { - it('should throw an error if `user` is missing', function() { + describe('getUserFromClient()', function () { + it('should throw an error if `user` is missing', function () { const model = Model.from({ - getUserFromClient: function() {}, + getUserFromClient: function () {}, saveToken: () => should.fail() }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); - return grantType.getUserFromClient(request, {}) + return grantType + .getUserFromClient(request, {}) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: user credentials are invalid'); }); }); - it('should return a user', function() { + it('should return a user', function () { const user = { email: 'foo@bar.com' }; const model = Model.from({ - getUserFromClient: function() { return user; }, + getUserFromClient: function () { + return user; + }, saveToken: () => should.fail() }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); - return grantType.getUserFromClient(request, {}) - .then(function(data) { + return grantType + .getUserFromClient(request, {}) + .then(function (data) { data.should.equal(user); }) .catch(should.fail); }); - it('should support promises', function() { + it('should support promises', function () { const user = { email: 'foo@bar.com' }; const model = Model.from({ - getUserFromClient: async function() { return user; }, + getUserFromClient: async function () { + return user; + }, saveToken: () => should.fail() }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const user = { email: 'foo@bar.com' }; const model = Model.from({ - getUserFromClient: function() {return user; }, + getUserFromClient: function () { + return user; + }, saveToken: () => should.fail() }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); grantType.getUserFromClient(request, {}).should.be.an.instanceOf(Promise); }); }); - describe('saveToken()', function() { - it('should save the token', async function() { + describe('saveToken()', function () { + it('should save the token', async function () { const token = {}; const model = Model.from({ getUserFromClient: () => should.fail(), - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; } + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + } + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model: model }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); const data = await grantType.saveToken(token); data.should.equal(token); }); - it('should support promises', function() { + it('should support promises', function () { const token = {}; const model = Model.from({ - getUserFromClient:() => should.fail(), - saveToken: async function() { return token; } + getUserFromClient: () => should.fail(), + saveToken: async function () { + return token; + } + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model: model }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const token = {}; const model = Model.from({ getUserFromClient: () => should.fail(), - saveToken: function() { return token; } + saveToken: function () { + return token; + } + }); + const grantType = new ClientCredentialsGrantType({ + accessTokenLifetime: 123, + model: model }); - const grantType = new ClientCredentialsGrantType({ accessTokenLifetime: 123, model: model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/grant-types/password-grant-type_test.js b/test/integration/grant-types/password-grant-type_test.js index 25da266b..024156b3 100644 --- a/test/integration/grant-types/password-grant-type_test.js +++ b/test/integration/grant-types/password-grant-type_test.js @@ -16,9 +16,9 @@ const should = require('chai').should(); * Test `PasswordGrantType` integration. */ -describe('PasswordGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { +describe('PasswordGrantType integration', function () { + describe('constructor()', function () { + it('should throw an error if `model` is missing', function () { try { new PasswordGrantType(); @@ -29,7 +29,7 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if the model does not implement `getUser()`', function() { + it('should throw an error if the model does not implement `getUser()`', function () { try { new PasswordGrantType({ model: {} }); @@ -40,10 +40,10 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if the model does not implement `saveToken()`', function() { + it('should throw an error if the model does not implement `saveToken()`', function () { try { const model = Model.from({ - getUser: function() {} + getUser: function () {} }); new PasswordGrantType({ model }); @@ -56,13 +56,16 @@ describe('PasswordGrantType integration', function() { }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing', async function () { const model = Model.from({ getUser: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); try { await grantType.handle(); @@ -74,12 +77,15 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if `client` is missing', async function() { + it('should throw an error if `client` is missing', async function () { const model = Model.from({ getUser: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); try { await grantType.handle({}); @@ -91,7 +97,7 @@ describe('PasswordGrantType integration', function() { } }); - it('should return a token', async function() { + it('should return a token', async function () { const client = { id: 'foobar' }; const scope = ['baz']; const token = {}; @@ -102,12 +108,12 @@ describe('PasswordGrantType integration', function() { }; const model = Model.from({ - getUser: async function(username, password) { + getUser: async function (username, password) { username.should.equal('foo'); password.should.equal('bar'); return user; }, - validateScope: async function(_user, _client, _scope) { + validateScope: async function (_user, _client, _scope) { _client.should.equal(client); _user.should.equal(user); _scope.should.eql(scope); @@ -125,7 +131,7 @@ describe('PasswordGrantType integration', function() { _scope.should.eql(scope); return 'long-refresh-token-hash'; }, - saveToken: async function(_token, _client, _user) { + saveToken: async function (_token, _client, _user) { _client.should.equal(client); _user.should.equal(user); _token.accessToken.should.equal('long-access-token-hash'); @@ -136,51 +142,91 @@ describe('PasswordGrantType integration', function() { } }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar', scope: 'baz' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar', scope: 'baz' }, + headers: {}, + method: {}, + query: {} + }); const data = await grantType.handle(request, client); data.should.equal(token); }); - it('should support promises', async function() { + it('should support promises', async function () { const client = { id: 'foobar' }; const token = {}; const model = Model.from({ - getUser: async function() { return {}; }, - saveToken: async function() { return token; } + getUser: async function () { + return {}; + }, + saveToken: async function () { + return token; + } + }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); const result = await grantType.handle(request, client); result.should.deep.equal({}); }); - it('should support non-promises', async function() { + it('should support non-promises', async function () { const client = { id: 'foobar' }; const token = {}; const model = Model.from({ - getUser: function() { return {}; }, - saveToken: function() { return token; } + getUser: function () { + return {}; + }, + saveToken: function () { + return token; + } + }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); const result = await grantType.handle(request, client); result.should.deep.equal({}); }); }); - describe('getUser()', function() { - it('should throw an error if the request body does not contain `username`', async function() { + describe('getUser()', function () { + it('should throw an error if the request body does not contain `username`', async function () { const model = Model.from({ getUser: () => should.fail(), saveToken: () => should.fail() }); const client = { id: 'foobar' }; - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getUser(request, client); @@ -192,14 +238,22 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if the request body does not contain `password`', async function() { + it('should throw an error if the request body does not contain `password`', async function () { const model = Model.from({ getUser: () => should.fail(), saveToken: () => should.fail() }); const client = { id: 'foobar' }; - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getUser(request, client); @@ -211,14 +265,22 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if `username` is invalid', async function() { + it('should throw an error if `username` is invalid', async function () { const model = Model.from({ getUser: () => should.fail(), saveToken: () => should.fail() }); const client = { id: 'foobar' }; - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: '\r\n', password: 'foobar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: '\r\n', password: 'foobar' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getUser(request, client); @@ -230,14 +292,22 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if `password` is invalid', async function() { + it('should throw an error if `password` is invalid', async function () { const model = Model.from({ getUser: () => should.fail(), saveToken: () => should.fail() }); const client = { id: 'foobar' }; - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foobar', password: '\r\n' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foobar', password: '\r\n' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getUser(request, client); @@ -249,14 +319,22 @@ describe('PasswordGrantType integration', function() { } }); - it('should throw an error if `user` is missing', async function() { + it('should throw an error if `user` is missing', async function () { const model = Model.from({ getUser: async () => undefined, saveToken: () => should.fail() }); const client = { id: 'foobar' }; - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getUser(request, client); @@ -267,57 +345,85 @@ describe('PasswordGrantType integration', function() { } }); - it('should return a user', async function() { + it('should return a user', async function () { const user = { email: 'foo@bar.com' }; const client = { id: 'foobar' }; const model = Model.from({ - getUser: function(username, password) { + getUser: function (username, password) { username.should.equal('foo'); password.should.equal('bar'); return user; }, saveToken: () => should.fail() }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} + }); const data = await grantType.getUser(request, client); data.should.equal(user); }); - it('should support promises', function() { + it('should support promises', function () { const user = { email: 'foo@bar.com' }; const client = { id: 'foobar' }; const model = Model.from({ - getUser: async function() { return user; }, + getUser: async function () { + return user; + }, saveToken: () => should.fail() }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} + }); grantType.getUser(request, client).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const user = { email: 'foo@bar.com' }; const client = { id: 'foobar' }; const model = Model.from({ - getUser: function() { return user; }, + getUser: function () { + return user; + }, saveToken: () => should.fail() }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} + }); grantType.getUser(request, client).should.be.an.instanceOf(Promise); }); }); - describe('saveToken()', function() { - it('should save the token', async function() { + describe('saveToken()', function () { + it('should save the token', async function () { const token = {}; const model = Model.from({ getUser: () => should.fail(), - saveToken: async function(_token, _client = 'fallback', _user = 'fallback') { + saveToken: async function (_token, _client = 'fallback', _user = 'fallback') { _token.accessToken.should.be.a.sha256(); _token.accessTokenExpiresAt.should.be.instanceOf(Date); _token.refreshTokenExpiresAt.should.be.instanceOf(Date); @@ -327,35 +433,48 @@ describe('PasswordGrantType integration', function() { _user.should.equal('fallback'); return token; }, - validateScope: async function(_scope = ['fallback']) { + validateScope: async function (_scope = ['fallback']) { _scope.should.eql(['fallback']); return ['foo']; } }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model + }); const data = await grantType.saveToken(); data.should.equal(token); }); - it('should support promises', function() { + it('should support promises', function () { const token = {}; const model = Model.from({ getUser: () => should.fail(), - saveToken: async function() { return token; } + saveToken: async function () { + return token; + } + }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const token = {}; const model = Model.from({ getUser: () => should.fail(), - saveToken: function() { return token; } + saveToken: function () { + return token; + } + }); + const grantType = new PasswordGrantType({ + accessTokenLifetime: 123, + model }); - const grantType = new PasswordGrantType({ accessTokenLifetime: 123, model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/grant-types/refresh-token-grant-type_test.js b/test/integration/grant-types/refresh-token-grant-type_test.js index 98a2f852..af3e6b63 100644 --- a/test/integration/grant-types/refresh-token-grant-type_test.js +++ b/test/integration/grant-types/refresh-token-grant-type_test.js @@ -18,9 +18,9 @@ const should = require('chai').should(); * Test `RefreshTokenGrantType` integration. */ -describe('RefreshTokenGrantType integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { +describe('RefreshTokenGrantType integration', function () { + describe('constructor()', function () { + it('should throw an error if `model` is missing', function () { try { new RefreshTokenGrantType(); @@ -31,7 +31,7 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if the model does not implement `getRefreshToken()`', function() { + it('should throw an error if the model does not implement `getRefreshToken()`', function () { try { new RefreshTokenGrantType({ model: {} }); @@ -42,7 +42,7 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if the model does not implement `revokeToken()`', function() { + it('should throw an error if the model does not implement `revokeToken()`', function () { try { const model = Model.from({ getRefreshToken: () => should.fail() @@ -57,7 +57,7 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if the model does not implement `saveToken()`', function() { + it('should throw an error if the model does not implement `saveToken()`', function () { try { const model = Model.from({ getRefreshToken: () => should.fail(), @@ -74,14 +74,17 @@ describe('RefreshTokenGrantType integration', function() { }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing', async function () { const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); try { await grantType.handle(); @@ -93,14 +96,22 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `client` is missing', async function() { + it('should throw an error if `client` is missing', async function () { const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); try { await grantType.handle(request); @@ -112,21 +123,21 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should return a token', async function() { + it('should return a token', async function () { const client = { id: 123 }; const token = { accessToken: 'foo', client: { id: 123 }, user: { name: 'foo' }, scope: ['read', 'write'], - refreshTokenExpiresAt: new Date( new Date() * 2) + refreshTokenExpiresAt: new Date(new Date() * 2) }; const model = Model.from({ - getRefreshToken: async function(_refreshToken) { + getRefreshToken: async function (_refreshToken) { _refreshToken.should.equal('foobar_refresh'); return token; }, - revokeToken: async function(_token) { + revokeToken: async function (_token) { _token.should.deep.equal(token); return true; }, @@ -142,7 +153,7 @@ describe('RefreshTokenGrantType integration', function() { _scope.should.eql(['read', 'write']); return 'new-refresh-token'; }, - saveToken: async function(_token, _client, _user) { + saveToken: async function (_token, _client, _user) { _user.should.deep.equal({ name: 'foo' }); _client.should.deep.equal({ id: 123 }); _token.accessToken.should.equal('new-access-token'); @@ -153,39 +164,85 @@ describe('RefreshTokenGrantType integration', function() { } }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar_refresh' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar_refresh' }, + headers: {}, + method: {}, + query: {} + }); const data = await grantType.handle(request, client); data.should.equal(token); }); - it('should support promises', function() { + it('should support promises', function () { const client = { id: 123 }; const model = Model.from({ - getRefreshToken: async function() { return { accessToken: 'foo', client: { id: 123 }, user: {} }; }, - revokeToken: async function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, - saveToken: async function() { return { accessToken: 'foo', client: {}, user: {} }; } + getRefreshToken: async function () { + return { accessToken: 'foo', client: { id: 123 }, user: {} }; + }, + revokeToken: async function () { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }; + }, + saveToken: async function () { + return { accessToken: 'foo', client: {}, user: {} }; + } + }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const client = { id: 123 }; const model = Model.from({ - getRefreshToken: async function() { return { accessToken: 'foo', client: { id: 123 }, user: {} }; }, - revokeToken: async function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; }, - saveToken: async function() { return { accessToken: 'foo', client: {}, user: {} }; } + getRefreshToken: async function () { + return { accessToken: 'foo', client: { id: 123 }, user: {} }; + }, + revokeToken: async function () { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }; + }, + saveToken: async function () { + return { accessToken: 'foo', client: {}, user: {} }; + } + }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.handle(request, client).should.be.an.instanceOf(Promise); }); - it('should throw an error if extra `scope` is requested', async function() { + it('should throw an error if extra `scope` is requested', async function () { const client = { id: 123 }; const token = { accessToken: 'foo', @@ -194,14 +251,22 @@ describe('RefreshTokenGrantType integration', function() { refreshTokenExpiresAt: new Date(new Date() * 2) }; const model = { - getRefreshToken: async function() { + getRefreshToken: async function () { return token; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }; - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar', scope: 'read' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar', scope: 'read' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.handle(request, client); @@ -214,16 +279,24 @@ describe('RefreshTokenGrantType integration', function() { }); }); - describe('getRefreshToken()', function() { - it('should throw an error if the `refreshToken` parameter is missing from the request body', async function() { + describe('getRefreshToken()', function () { + it('should throw an error if the `refreshToken` parameter is missing from the request body', async function () { const client = {}; const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -235,15 +308,23 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refreshToken` is not found', async function() { + it('should throw an error if `refreshToken` is not found', async function () { const client = { id: 123 }; const model = Model.from({ - getRefreshToken: async function() {} , + getRefreshToken: async function () {}, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: '12345' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: '12345' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -255,15 +336,25 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refreshToken.client` is missing', async function() { + it('should throw an error if `refreshToken.client` is missing', async function () { const client = {}; const model = Model.from({ - getRefreshToken: async function() { return {}; }, + getRefreshToken: async function () { + return {}; + }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -275,17 +366,25 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refreshToken.user` is missing', async function() { + it('should throw an error if `refreshToken.user` is missing', async function () { const client = {}; const model = Model.from({ - getRefreshToken: async function() { + getRefreshToken: async function () { return { accessToken: 'foo', client: {} }; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -297,17 +396,25 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if the client id does not match', async function() { + it('should throw an error if the client id does not match', async function () { const client = { id: 123 }; const model = Model.from({ - getRefreshToken: async function() { + getRefreshToken: async function () { return { accessToken: 'foo', client: { id: 456 }, user: {} }; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -319,17 +426,25 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refresh_token` contains invalid characters', async function() { + it('should throw an error if `refresh_token` contains invalid characters', async function () { const client = {}; const model = Model.from({ - getRefreshToken: async function() { + getRefreshToken: async function () { return { client: { id: 456 }, user: {} }; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 'øå€£‰' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 'øå€£‰' }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -341,17 +456,25 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refresh_token` is missing', async function() { + it('should throw an error if `refresh_token` is missing', async function () { const client = {}; const model = Model.from({ - getRefreshToken: async function() { + getRefreshToken: async function () { return { accessToken: 'foo', client: { id: 456 }, user: {} }; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -363,18 +486,31 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refresh_token` is expired', async function() { + it('should throw an error if `refresh_token` is expired', async function () { const client = { id: 123 }; const date = new Date(new Date() / 2); const model = Model.from({ - getRefreshToken: async function() { - return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: date, user: {} }; + getRefreshToken: async function () { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: date, + user: {} + }; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -386,17 +522,30 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should throw an error if `refreshTokenExpiresAt` is not a date value', async function() { + it('should throw an error if `refreshTokenExpiresAt` is not a date value', async function () { const client = { id: 123 }; const model = Model.from({ - getRefreshToken: async function() { - return { accessToken: 'foo', client: { id: 123 }, refreshTokenExpiresAt: 'stringvalue', user: {} }; + getRefreshToken: async function () { + return { + accessToken: 'foo', + client: { id: 123 }, + refreshTokenExpiresAt: 'stringvalue', + user: {} + }; }, revokeToken: () => should.fail(), saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); - const request = new Request({ body: { refresh_token: 12345 }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); + const request = new Request({ + body: { refresh_token: 12345 }, + headers: {}, + method: {}, + query: {} + }); try { await grantType.getRefreshToken(request, client); @@ -408,19 +557,23 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should return a token', async function() { + it('should return a token', async function () { const client = { id: 123 }; - const token = { accessToken: 'foo', client: { id: 123 }, user: { name: 'foobar' } }; + const token = { + accessToken: 'foo', + client: { id: 123 }, + user: { name: 'foobar' } + }; const model = Model.from({ - getRefreshToken: async function(_refreshToken) { + getRefreshToken: async function (_refreshToken) { _refreshToken.should.equal('foobar_refresh'); return token; }, - revokeToken: async function(_token) { + revokeToken: async function (_token) { _token.should.deep.equal(token); return true; }, - saveToken: async function(_token, _client, _user) { + saveToken: async function (_token, _client, _user) { _user.should.deep.equal(token.user); _client.should.deep.equal(client); _token.accessToken.should.be.a.sha256(); @@ -430,50 +583,81 @@ describe('RefreshTokenGrantType integration', function() { return token; } }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar_refresh' }, headers: {}, method: {}, query: {} }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar_refresh' }, + headers: {}, + method: {}, + query: {} + }); const data = await grantType.getRefreshToken(request, client); data.should.equal(token); }); - it('should support promises', function() { + it('should support promises', function () { const client = { id: 123 }; const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; const model = Model.from({ - getRefreshToken: async function() { return token; }, - revokeToken: async function() {}, - saveToken: async function() {} + getRefreshToken: async function () { + return token; + }, + revokeToken: async function () {}, + saveToken: async function () {} + }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const client = { id: 123 }; const token = { accessToken: 'foo', client: { id: 123 }, user: {} }; const model = Model.from({ - getRefreshToken: async function() { return token; }, - revokeToken: async function() {}, - saveToken: async function() {} + getRefreshToken: async function () { + return token; + }, + revokeToken: async function () {}, + saveToken: async function () {} + }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); + const request = new Request({ + body: { refresh_token: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); - const request = new Request({ body: { refresh_token: 'foobar' }, headers: {}, method: {}, query: {} }); grantType.getRefreshToken(request, client).should.be.an.instanceOf(Promise); }); }); - describe('revokeToken()', function() { - it('should throw an error if the `token` is invalid', async function() { + describe('revokeToken()', function () { + it('should throw an error if the `token` is invalid', async function () { const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: async () => {}, saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 120, model }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model + }); try { await grantType.revokeToken({}); @@ -484,56 +668,84 @@ describe('RefreshTokenGrantType integration', function() { } }); - it('should revoke the token', async function() { - const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + it('should revoke the token', async function () { + const token = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }; const model = Model.from({ getRefreshToken: () => should.fail(), - revokeToken: async function(_token) { + revokeToken: async function (_token) { _token.should.deep.equal(token); return token; }, saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); const data = await grantType.revokeToken(token); data.should.equal(token); }); - it('should support promises', function() { - const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + it('should support promises', function () { + const token = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }; const model = Model.from({ getRefreshToken: () => should.fail(), - revokeToken: async function() { return token; }, + revokeToken: async function () { + return token; + }, saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); grantType.revokeToken(token).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { - const token = { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; + it('should support non-promises', function () { + const token = { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }; const model = Model.from({ getRefreshToken: () => should.fail(), - revokeToken: function() { return token; }, + revokeToken: function () { + return token; + }, saveToken: () => should.fail() }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); grantType.revokeToken(token).should.be.an.instanceOf(Promise); }); }); - describe('saveToken()', function() { - it('should save the token', async function() { + describe('saveToken()', function () { + it('should save the token', async function () { const user = { name: 'foo' }; const client = { id: 123465 }; const scope = ['foo', 'bar']; const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: () => should.fail(), - saveToken: async function(_token, _client, _user) { + saveToken: async function (_token, _client, _user) { _user.should.deep.equal(user); _client.should.deep.equal(client); _token.scope.should.deep.eql(scope); @@ -544,7 +756,10 @@ describe('RefreshTokenGrantType integration', function() { return { ..._token }; } }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model + }); const data = await grantType.saveToken(user, client, scope); data.accessToken.should.be.a.sha256(); @@ -554,26 +769,36 @@ describe('RefreshTokenGrantType integration', function() { data.scope.should.deep.equal(scope); }); - it('should support promises', function() { + it('should support promises', function () { const token = {}; const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: () => should.fail(), - saveToken: async function() { return token; } + saveToken: async function () { + return token; + } + }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const token = {}; const model = Model.from({ getRefreshToken: () => should.fail(), revokeToken: () => should.fail(), - saveToken: function() { return token; } + saveToken: function () { + return token; + } + }); + const grantType = new RefreshTokenGrantType({ + accessTokenLifetime: 123, + model }); - const grantType = new RefreshTokenGrantType({ accessTokenLifetime: 123, model }); grantType.saveToken(token).should.be.an.instanceOf(Promise); }); diff --git a/test/integration/handlers/authenticate-handler_test.js b/test/integration/handlers/authenticate-handler_test.js index c1524f47..98cb29aa 100644 --- a/test/integration/handlers/authenticate-handler_test.js +++ b/test/integration/handlers/authenticate-handler_test.js @@ -21,9 +21,9 @@ const should = require('chai').should(); * Test `AuthenticateHandler` integration. */ -describe('AuthenticateHandler integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.model` is missing', function() { +describe('AuthenticateHandler integration', function () { + describe('constructor()', function () { + it('should throw an error if `options.model` is missing', function () { try { new AuthenticateHandler(); @@ -34,7 +34,7 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if the model does not implement `getAccessToken()`', function() { + it('should throw an error if the model does not implement `getAccessToken()`', function () { try { new AuthenticateHandler({ model: {} }); @@ -45,9 +45,12 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if `scope` was given and `addAcceptedScopesHeader()` is missing', function() { + it('should throw an error if `scope` was given and `addAcceptedScopesHeader()` is missing', function () { try { - new AuthenticateHandler({ model: { getAccessToken: function() {} }, scope: ['foobar'] }); + new AuthenticateHandler({ + model: { getAccessToken: function () {} }, + scope: ['foobar'] + }); should.fail(); } catch (e) { @@ -56,9 +59,13 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if `scope` was given and `addAuthorizedScopesHeader()` is missing', function() { + it('should throw an error if `scope` was given and `addAuthorizedScopesHeader()` is missing', function () { try { - new AuthenticateHandler({ addAcceptedScopesHeader: true, model: { getAccessToken: function() {} }, scope: ['foobar'] }); + new AuthenticateHandler({ + addAcceptedScopesHeader: true, + model: { getAccessToken: function () {} }, + scope: ['foobar'] + }); should.fail(); } catch (e) { @@ -67,9 +74,14 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if `scope` was given and the model does not implement `verifyScope()`', function() { + it('should throw an error if `scope` was given and the model does not implement `verifyScope()`', function () { try { - new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: { getAccessToken: function() {} }, scope: ['foobar'] }); + new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: { getAccessToken: function () {} }, + scope: ['foobar'] + }); should.fail(); } catch (e) { @@ -78,17 +90,17 @@ describe('AuthenticateHandler integration', function() { } }); - it('should set the `model`', function() { - const model = Model.from({ getAccessToken: function() {} }); + it('should set the `model`', function () { + const model = Model.from({ getAccessToken: function () {} }); const grantType = new AuthenticateHandler({ model: model }); grantType.model.should.equal(model); }); - it('should set the `scope`', function() { + it('should set the `scope`', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} }); const grantType = new AuthenticateHandler({ addAcceptedScopesHeader: true, @@ -101,12 +113,14 @@ describe('AuthenticateHandler integration', function() { }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing or not a Request instance', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing or not a Request instance', async function () { class Request {} // intentionally fake const values = [undefined, null, {}, [], new Date(), new Request()]; for (const request of values) { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); try { await handler.handle(request); @@ -119,13 +133,20 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if `response` is missing or not a Response instance', async function() { + it('should throw an error if `response` is missing or not a Response instance', async function () { class Response {} // intentionally fake const values = [undefined, null, {}, [], new Date(), new Response()]; - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); for (const response of values) { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); try { await handler.handle(request, response); @@ -137,14 +158,19 @@ describe('AuthenticateHandler integration', function() { } }); - it('should set the `WWW-Authenticate` header if an unauthorized request error is thrown', async function() { + it('should set the `WWW-Authenticate` header if an unauthorized request error is thrown', async function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { throw new UnauthorizedRequestError(); } }); const handler = new AuthenticateHandler({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); try { @@ -155,158 +181,202 @@ describe('AuthenticateHandler integration', function() { } }); - it('should set the `WWW-Authenticate` header if an InvalidRequestError is thrown', function() { + it('should set the `WWW-Authenticate` header if an InvalidRequestError is thrown', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { throw new InvalidRequestError(); } }); const handler = new AuthenticateHandler({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function() { + .catch(function () { response.get('WWW-Authenticate').should.equal('Bearer realm="Service",error="invalid_request"'); }); }); - it('should set the `WWW-Authenticate` header if an InvalidTokenError is thrown', function() { + it('should set the `WWW-Authenticate` header if an InvalidTokenError is thrown', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { throw new InvalidTokenError(); } }); const handler = new AuthenticateHandler({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function() { + .catch(function () { response.get('WWW-Authenticate').should.equal('Bearer realm="Service",error="invalid_token"'); }); }); - it('should set the `WWW-Authenticate` header if an InsufficientScopeError is thrown', function() { + it('should set the `WWW-Authenticate` header if an InsufficientScopeError is thrown', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { throw new InsufficientScopeError(); } }); const handler = new AuthenticateHandler({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function() { + .catch(function () { response.get('WWW-Authenticate').should.equal('Bearer realm="Service",error="insufficient_scope"'); }); }); - it('should throw the error if an oauth error is thrown', function() { + it('should throw the error if an oauth error is thrown', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { throw new AccessDeniedError('Cannot request this access token'); } }); const handler = new AuthenticateHandler({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(AccessDeniedError); e.message.should.equal('Cannot request this access token'); }); }); - it('should throw a server error if a non-oauth error is thrown', function() { + it('should throw a server error if a non-oauth error is thrown', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { throw new Error('Unhandled exception'); } }); const handler = new AuthenticateHandler({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(ServerError); e.message.should.equal('Unhandled exception'); }); }); - it('should return an access token', function() { + it('should return an access token', function () { const accessToken = { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return accessToken; }, - verifyScope: function() { + verifyScope: function () { return true; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: ['foo'] + }); const request = new Request({ body: {}, - headers: { 'Authorization': 'Bearer foo' }, + headers: { Authorization: 'Bearer foo' }, method: {}, query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) - .then(function(data) { + return handler + .handle(request, response) + .then(function (data) { data.should.equal(accessToken); }) .catch(should.fail); }); - it('should return an access token (deprecated)', function() { + it('should return an access token (deprecated)', function () { const accessToken = { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return accessToken; }, - verifyScope: function() { + verifyScope: function () { return true; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: 'foo' + }); const request = new Request({ body: {}, - headers: { 'Authorization': 'Bearer foo' }, + headers: { Authorization: 'Bearer foo' }, method: {}, query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) - .then(function(data) { + return handler + .handle(request, response) + .then(function (data) { data.should.equal(accessToken); }) .catch(should.fail); }); }); - describe('getTokenFromRequest()', function() { - it('should throw an error if more than one authentication method is used', async function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('getTokenFromRequest()', function () { + it('should throw an error if more than one authentication method is used', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: {}, - headers: { 'Authorization': 'Bearer foo' }, + headers: { Authorization: 'Bearer foo' }, method: {}, query: { access_token: 'foo' } }); @@ -321,9 +391,16 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if `accessToken` is missing', async function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + it('should throw an error if `accessToken` is missing', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); try { await handler.getTokenFromRequest(request); @@ -336,13 +413,15 @@ describe('AuthenticateHandler integration', function() { }); }); - describe('getTokenFromRequestHeader()', function() { - it('should throw an error if the token is malformed', async function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('getTokenFromRequestHeader()', function () { + it('should throw an error if the token is malformed', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: {}, headers: { - 'Authorization': 'foobar' + Authorization: 'foobar' }, method: {}, query: {} @@ -358,12 +437,14 @@ describe('AuthenticateHandler integration', function() { } }); - it('should return the bearer token', function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + it('should return the bearer token', function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: {}, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: {} @@ -375,9 +456,11 @@ describe('AuthenticateHandler integration', function() { }); }); - describe('getTokenFromRequestQuery()', function() { - it('should throw an error if the query contains a token', async function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('getTokenFromRequestQuery()', function () { + it('should throw an error if the query contains a token', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); try { await handler.getTokenFromRequestQuery(); @@ -389,16 +472,21 @@ describe('AuthenticateHandler integration', function() { } }); - it('should return the bearer token if `allowBearerTokensInQueryString` is true', function() { - const handler = new AuthenticateHandler({ allowBearerTokensInQueryString: true, model: { getAccessToken: function() {} } }); + it('should return the bearer token if `allowBearerTokensInQueryString` is true', function () { + const handler = new AuthenticateHandler({ + allowBearerTokensInQueryString: true, + model: { getAccessToken: function () {} } + }); handler.getTokenFromRequestQuery({ query: { access_token: 'foo' } }).should.equal('foo'); }); }); - describe('getTokenFromRequestBody()', function() { - it('should throw an error if the method is `GET`', async function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('getTokenFromRequestBody()', function () { + it('should throw an error if the method is `GET`', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: { access_token: 'foo' }, headers: {}, @@ -416,8 +504,10 @@ describe('AuthenticateHandler integration', function() { } }); - it('should throw an error if the media type is not `application/x-www-form-urlencoded`', async function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + it('should throw an error if the media type is not `application/x-www-form-urlencoded`', async function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: { access_token: 'foo' }, headers: {}, @@ -435,11 +525,16 @@ describe('AuthenticateHandler integration', function() { } }); - it('should return the bearer token', function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + it('should return the bearer token', function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: { access_token: 'foo' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, method: {}, query: {} }); @@ -448,56 +543,59 @@ describe('AuthenticateHandler integration', function() { }); }); - describe('getAccessToken()', function() { - it('should throw an error if `accessToken` is missing', function() { + describe('getAccessToken()', function () { + it('should throw an error if `accessToken` is missing', function () { const model = Model.from({ - getAccessToken: function() {} + getAccessToken: function () {} }); const handler = new AuthenticateHandler({ model: model }); - return handler.getAccessToken('foo') + return handler + .getAccessToken('foo') .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidTokenError); e.message.should.equal('Invalid token: access token is invalid'); }); }); - it('should throw an error if `accessToken.user` is missing', function() { + it('should throw an error if `accessToken.user` is missing', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return {}; } }); const handler = new AuthenticateHandler({ model: model }); - return handler.getAccessToken('foo') + return handler + .getAccessToken('foo') .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(ServerError); e.message.should.equal('Server error: `getAccessToken()` did not return a `user` object'); }); }); - it('should return an access token', function() { + it('should return an access token', function () { const accessToken = { user: {} }; const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return accessToken; } }); const handler = new AuthenticateHandler({ model: model }); - return handler.getAccessToken('foo') - .then(function(data) { + return handler + .getAccessToken('foo') + .then(function (data) { data.should.equal(accessToken); }) .catch(should.fail); }); - it('should support promises', function() { + it('should support promises', function () { const model = Model.from({ - getAccessToken: async function() { + getAccessToken: async function () { return { user: {} }; } }); @@ -506,9 +604,9 @@ describe('AuthenticateHandler integration', function() { handler.getAccessToken('foo').should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return { user: {} }; } }); @@ -518,10 +616,12 @@ describe('AuthenticateHandler integration', function() { }); }); - describe('validateAccessToken()', function() { - it('should throw an error if `accessToken` is expired', async function() { + describe('validateAccessToken()', function () { + it('should throw an error if `accessToken` is expired', async function () { const accessToken = { accessTokenExpiresAt: new Date(new Date() / 2) }; - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); try { await handler.validateAccessToken(accessToken); @@ -533,108 +633,146 @@ describe('AuthenticateHandler integration', function() { } }); - it('should return an access token', function() { + it('should return an access token', function () { const accessToken = { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); handler.validateAccessToken(accessToken).should.equal(accessToken); }); }); - describe('verifyScope()', function() { - it('should throw an error if `scope` is insufficient (deprecated)', function() { + describe('verifyScope()', function () { + it('should throw an error if `scope` is insufficient (deprecated)', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() { + getAccessToken: function () {}, + verifyScope: function () { return false; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: 'foo' + }); - return handler.verifyScope(['foo']) + return handler + .verifyScope(['foo']) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InsufficientScopeError); e.message.should.equal('Insufficient scope: authorized scope is insufficient'); }); }); - it('should throw an error if `scope` is insufficient', function() { + it('should throw an error if `scope` is insufficient', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() { + getAccessToken: function () {}, + verifyScope: function () { return false; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: ['foo'] + }); - return handler.verifyScope(['foo']) + return handler + .verifyScope(['foo']) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InsufficientScopeError); e.message.should.equal('Insufficient scope: authorized scope is insufficient'); }); }); - it('should support promises (deprecated)', function() { + it('should support promises (deprecated)', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() { + getAccessToken: function () {}, + verifyScope: function () { return true; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: 'foo' + }); handler.verifyScope(['foo']).should.be.an.instanceOf(Promise); }); - it('should support promises', function() { + it('should support promises', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() { + getAccessToken: function () {}, + verifyScope: function () { return true; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: ['foo'] + }); handler.verifyScope(['foo']).should.be.an.instanceOf(Promise); }); - it('should support non-promises (deprecated)', function() { + it('should support non-promises (deprecated)', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() { + getAccessToken: function () {}, + verifyScope: function () { return true; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'foo' }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: 'foo' + }); handler.verifyScope(['foo']).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() { + getAccessToken: function () {}, + verifyScope: function () { return true; } }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: ['foo'] }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: ['foo'] + }); handler.verifyScope(['foo']).should.be.an.instanceOf(Promise); }); }); - describe('updateResponse()', function() { - it('should not set the `X-Accepted-OAuth-Scopes` header if `scope` is not specified', function() { + describe('updateResponse()', function () { + it('should not set the `X-Accepted-OAuth-Scopes` header if `scope` is not specified', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} + }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model: model }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model }); const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: ['foo', 'biz'] }); @@ -642,12 +780,17 @@ describe('AuthenticateHandler integration', function() { response.headers.should.not.have.property('x-accepted-oauth-scopes'); }); - it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified (deprecated)', function() { + it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified (deprecated)', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} + }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model: model, + scope: 'foo bar' }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model, scope: 'foo bar' }); const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: ['foo', 'biz'] }); @@ -655,12 +798,17 @@ describe('AuthenticateHandler integration', function() { response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar'); }); - it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', function() { + it('should set the `X-Accepted-OAuth-Scopes` header if `scope` is specified', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} + }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: false, + model: model, + scope: ['foo', 'bar'] }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: false, model: model, scope: ['foo', 'bar'] }); const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: ['foo', 'biz'] }); @@ -668,12 +816,16 @@ describe('AuthenticateHandler integration', function() { response.get('X-Accepted-OAuth-Scopes').should.equal('foo bar'); }); - it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', function() { + it('should not set the `X-Authorized-OAuth-Scopes` header if `scope` is not specified', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} + }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model: model }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model }); const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: ['foo', 'biz'] }); @@ -681,12 +833,17 @@ describe('AuthenticateHandler integration', function() { response.headers.should.not.have.property('x-oauth-scopes'); }); - it('should set the `X-Authorized-OAuth-Scopes` header (deprecated)', function() { + it('should set the `X-Authorized-OAuth-Scopes` header (deprecated)', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} + }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model: model, + scope: 'foo bar' }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model, scope: 'foo bar' }); const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: ['foo', 'biz'] }); @@ -694,12 +851,17 @@ describe('AuthenticateHandler integration', function() { response.get('X-OAuth-Scopes').should.equal('foo biz'); }); - it('should set the `X-Authorized-OAuth-Scopes` header', function() { + it('should set the `X-Authorized-OAuth-Scopes` header', function () { const model = Model.from({ - getAccessToken: function() {}, - verifyScope: function() {} + getAccessToken: function () {}, + verifyScope: function () {} + }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: false, + addAuthorizedScopesHeader: true, + model: model, + scope: ['foo', 'bar'] }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: false, addAuthorizedScopesHeader: true, model: model, scope: ['foo', 'bar'] }); const response = new Response({ body: {}, headers: {} }); handler.updateResponse(response, { scope: ['foo', 'biz'] }); diff --git a/test/integration/handlers/authorize-handler_test.js b/test/integration/handlers/authorize-handler_test.js index d9004cd3..91927601 100644 --- a/test/integration/handlers/authorize-handler_test.js +++ b/test/integration/handlers/authorize-handler_test.js @@ -34,9 +34,9 @@ const createModel = (model = {}) => { * Test `AuthorizeHandler` integration. */ -describe('AuthorizeHandler integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.authorizationCodeLifetime` is missing', function() { +describe('AuthorizeHandler integration', function () { + describe('constructor()', function () { + it('should throw an error if `options.authorizationCodeLifetime` is missing', function () { try { new AuthorizeHandler(); should.fail(); @@ -46,7 +46,7 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `options.model` is missing', function() { + it('should throw an error if `options.model` is missing', function () { try { new AuthorizeHandler({ authorizationCodeLifetime: 120 }); should.fail(); @@ -56,7 +56,7 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if the model does not implement `getClient()`', function() { + it('should throw an error if the model does not implement `getClient()`', function () { try { new AuthorizeHandler({ authorizationCodeLifetime: 120, model: {} }); should.fail(); @@ -66,9 +66,12 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if the model does not implement `saveAuthorizationCode()`', function() { + it('should throw an error if the model does not implement `saveAuthorizationCode()`', function () { try { - new AuthorizeHandler({ authorizationCodeLifetime: 120, model: { getClient: () => should.fail() } }); + new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: { getClient: () => should.fail() } + }); should.fail(); } catch (e) { e.should.be.an.instanceOf(InvalidArgumentError); @@ -76,7 +79,7 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if the model does not implement `getAccessToken()`', function() { + it('should throw an error if the model does not implement `getAccessToken()`', function () { const model = Model.from({ getClient: () => should.fail(), saveAuthorizationCode: () => should.fail() @@ -92,9 +95,12 @@ describe('AuthorizeHandler integration', function() { } }); - it('should set the `authorizationCodeLifetime`', function() { + it('should set the `authorizationCodeLifetime`', function () { const model = createModel(); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); handler.authorizationCodeLifetime.should.equal(120); }); @@ -104,7 +110,11 @@ describe('AuthorizeHandler integration', function() { const authenticateHandler = {}; // misses handle() method try { - new AuthorizeHandler({ authenticateHandler, authorizationCodeLifetime: 120, model }); + new AuthorizeHandler({ + authenticateHandler, + authorizationCodeLifetime: 120, + model + }); should.fail(); } catch (e) { e.should.be.an.instanceOf(InvalidArgumentError); @@ -112,9 +122,12 @@ describe('AuthorizeHandler integration', function() { } }); - it('should set the default `authenticateHandler`, if no custom one is passed', function() { + it('should set the default `authenticateHandler`, if no custom one is passed', function () { const model = createModel(); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); handler.authenticateHandler.should.be.an.instanceOf(AuthenticateHandler); }); @@ -122,26 +135,36 @@ describe('AuthorizeHandler integration', function() { const model = createModel(); class CustomAuthenticateHandler { - async handle () {} + async handle() {} } const authenticateHandler = new CustomAuthenticateHandler(); - const handler = new AuthorizeHandler({ authenticateHandler, authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authenticateHandler, + authorizationCodeLifetime: 120, + model + }); handler.authenticateHandler.should.be.an.instanceOf(CustomAuthenticateHandler); handler.authenticateHandler.should.not.be.an.instanceOf(AuthenticateHandler); }); - it('should set the `model`', function() { + it('should set the `model`', function () { const model = createModel(); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); handler.model.should.equal(model); }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing', async function () { const model = createModel(); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); try { await handler.handle(); @@ -152,10 +175,18 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `response` is missing', async function() { + it('should throw an error if `response` is missing', async function () { const model = createModel(); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); try { await handler.handle(request); @@ -166,27 +197,30 @@ describe('AuthorizeHandler integration', function() { } }); - it('should redirect to an error response if user denied access', async function() { + it('should redirect to an error response if user denied access', async function () { const client = { id: 'client-12345', grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; const model = createModel({ - getAccessToken: async function(_token) { + getAccessToken: async function (_token) { _token.should.equal('foobarbazmootoken'); return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function(clientId, clientSecret) { + getClient: async function (clientId, clientSecret) { clientId.should.equal(client.id); (clientSecret === null).should.equal(true); return { ...client }; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: client.id, @@ -194,7 +228,7 @@ describe('AuthorizeHandler integration', function() { }, method: {}, headers: { - 'Authorization': 'Bearer foobarbazmootoken' + Authorization: 'Bearer foobarbazmootoken' }, query: { state: 'foobar', @@ -211,38 +245,42 @@ describe('AuthorizeHandler integration', function() { e.message.should.equal('Access denied: user denied access to application'); response .get('location') - .should - .equal('http://example.com/cb?error=access_denied&error_description=Access%20denied%3A%20user%20denied%20access%20to%20application&state=foobar'); + .should.equal( + 'http://example.com/cb?error=access_denied&error_description=Access%20denied%3A%20user%20denied%20access%20to%20application&state=foobar' + ); } }); - it('should redirect to an error response if a non-oauth error is thrown', async function() { + it('should redirect to an error response if a non-oauth error is thrown', async function () { const model = createModel({ - getAccessToken: async function() { + getAccessToken: async function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { + getClient: async function () { return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; }, - saveAuthorizationCode: async function() { + saveAuthorizationCode: async function () { throw new CustomError('Unhandled exception'); } }); class CustomError extends Error {} - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -259,34 +297,41 @@ describe('AuthorizeHandler integration', function() { e.message.should.equal('Unhandled exception'); response .get('location') - .should - .equal('http://example.com/cb?error=server_error&error_description=Unhandled%20exception&state=foobar'); + .should.equal( + 'http://example.com/cb?error=server_error&error_description=Unhandled%20exception&state=foobar' + ); } }); - it('should redirect to an error response if an oauth error is thrown', async function() { + it('should redirect to an error response if an oauth error is thrown', async function () { const model = createModel({ - getAccessToken: async function() { + getAccessToken: async function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getClient: async function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: async function() { + saveAuthorizationCode: async function () { throw new AccessDeniedError('Cannot request this auth code'); } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -303,19 +348,20 @@ describe('AuthorizeHandler integration', function() { e.message.should.equal('Cannot request this auth code'); response .get('location') - .should - .equal('http://example.com/cb?error=access_denied&error_description=Cannot%20request%20this%20auth%20code&state=foobar'); + .should.equal( + 'http://example.com/cb?error=access_denied&error_description=Cannot%20request%20this%20auth%20code&state=foobar' + ); } }); - it('should redirect to a successful response with `code` and `state` if successful', async function() { + it('should redirect to a successful response with `code` and `state` if successful', async function () { const client = { id: 'client-12343434', grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; const model = createModel({ - getAccessToken: async function(_token) { + getAccessToken: async function (_token) { _token.should.equal('foobarbaztokenmoo'); return { client, @@ -323,26 +369,29 @@ describe('AuthorizeHandler integration', function() { accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function(clientId, clientSecret) { + getClient: async function (clientId, clientSecret) { clientId.should.equal(client.id); (clientSecret === null).should.equal(true); return { ...client }; }, - saveAuthorizationCode: async function() { + saveAuthorizationCode: async function () { return { authorizationCode: 'fooobar-long-authzcode-?', client }; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: client.id, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foobarbaztokenmoo' + Authorization: 'Bearer foobarbaztokenmoo' }, method: {}, query: { @@ -356,33 +405,38 @@ describe('AuthorizeHandler integration', function() { response.status.should.equal(302); response .get('location') - .should - .equal('http://example.com/cb?code=fooobar-long-authzcode-%3F&state=foobarbazstatemoo'); + .should.equal('http://example.com/cb?code=fooobar-long-authzcode-%3F&state=foobarbazstatemoo'); }); - it('should redirect to an error response if `scope` is invalid', async function() { + it('should redirect to an error response if `scope` is invalid', async function () { const model = createModel({ - getAccessToken: async function() { + getAccessToken: async function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getClient: async function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: async function() { + saveAuthorizationCode: async function () { return {}; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -399,35 +453,45 @@ describe('AuthorizeHandler integration', function() { e.should.be.an.instanceOf(InvalidScopeError); e.message.should.equal('Invalid parameter: `scope`'); response.status.should.equal(302); - response.get('location').should.equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20parameter%3A%20%60scope%60&state=foobar'); + response + .get('location') + .should.equal( + 'http://example.com/cb?error=invalid_scope&error_description=Invalid%20parameter%3A%20%60scope%60&state=foobar' + ); } }); - it('should redirect to a successful response if `model.validateScope` is not defined', async function() { - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + it('should redirect to a successful response if `model.validateScope` is not defined', async function () { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return { client: client, user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: function() { + getClient: function () { return client; }, - saveAuthorizationCode: function() { + saveAuthorizationCode: function () { return { authorizationCode: 'fooobar-long-authzcode-?', client }; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -444,39 +508,45 @@ describe('AuthorizeHandler integration', function() { response.status.should.equal(302); response .get('location') - .should - .equal('http://example.com/cb?code=fooobar-long-authzcode-%3F&state=foobarbazstatemoo'); + .should.equal('http://example.com/cb?code=fooobar-long-authzcode-%3F&state=foobarbazstatemoo'); }); - it('should redirect to an error response if `scope` is insufficient (validateScope)', async function() { - const client = { id: 12345, grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + it('should redirect to an error response if `scope` is insufficient (validateScope)', async function () { + const client = { + id: 12345, + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const model = Model.from({ - getAccessToken: async function() { + getAccessToken: async function () { return { client: client, user: { name: 'foouser' }, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { + getClient: async function () { return client; }, - saveAuthorizationCode: async function() { + saveAuthorizationCode: async function () { return { authorizationCode: 12345, client }; }, - validateScope: async function(_user, _client, _scope) { + validateScope: async function (_user, _client, _scope) { _scope.should.eql(['read']); return false; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -489,40 +559,47 @@ describe('AuthorizeHandler integration', function() { try { await handler.handle(request, response); should.fail(); - } catch(e) { + } catch (e) { e.should.be.an.instanceOf(InvalidScopeError); e.message.should.equal('Invalid scope: Requested scope is invalid'); response.status.should.equal(302); response .get('location') - .should - .equal('http://example.com/cb?error=invalid_scope&error_description=Invalid%20scope%3A%20Requested%20scope%20is%20invalid&state=foobar'); + .should.equal( + 'http://example.com/cb?error=invalid_scope&error_description=Invalid%20scope%3A%20Requested%20scope%20is%20invalid&state=foobar' + ); } }); - it('should redirect to an error response if `state` is missing', async function() { + it('should redirect to an error response if `state` is missing', async function () { const model = createModel({ - getAccessToken: async function() { + getAccessToken: async function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getClient: async function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: async function() { + saveAuthorizationCode: async function () { throw new AccessDeniedError('Cannot request this auth code'); } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: {} @@ -538,32 +615,39 @@ describe('AuthorizeHandler integration', function() { response.status.should.equal(302); response .get('location') - .should - .equal('http://example.com/cb?error=invalid_request&error_description=Missing%20parameter%3A%20%60state%60'); + .should.equal( + 'http://example.com/cb?error=invalid_request&error_description=Missing%20parameter%3A%20%60state%60' + ); } }); - it('should redirect to an error response if `response_type` is invalid', async function() { + it('should redirect to an error response if `response_type` is invalid', async function () { const model = Model.from({ - getAccessToken: async function() { + getAccessToken: async function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getClient: async function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, saveAuthorizationCode: () => should.fail() // should fail before call }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'test' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -581,37 +665,44 @@ describe('AuthorizeHandler integration', function() { response.status.should.equal(302); response .get('location') - .should - .equal('http://example.com/cb?error=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar'); + .should.equal( + 'http://example.com/cb?error=unsupported_response_type&error_description=Unsupported%20response%20type%3A%20%60response_type%60%20is%20not%20supported&state=foobar' + ); } }); - it('should return the `code` if successful', async function() { - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + it('should return the `code` if successful', async function () { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const model = Model.from({ - getAccessToken: async function() { + getAccessToken: async function () { return { client: client, user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { + getClient: async function () { return client; }, generateAuthorizationCode: async () => 'some-code', - saveAuthorizationCode: async function(code) { + saveAuthorizationCode: async function (code) { return { authorizationCode: code.authorizationCode, client: client }; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -680,14 +771,17 @@ describe('AuthorizeHandler integration', function() { } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); const request = new Request({ body: { client_id: client.id, response_type: 'code' }, headers: { - 'Authorization': `Bearer ${accessTokenDoc.accessToken}` + Authorization: `Bearer ${accessTokenDoc.accessToken}` }, method: {}, query: { state, scope: scope.join(' ') } @@ -701,10 +795,7 @@ describe('AuthorizeHandler integration', function() { data.expiresAt.should.be.instanceOf(Date); data.redirectUri.should.equal(client.redirectUris[0]); response.status.should.equal(302); - response - .get('location') - .should - .equal('http://example.com/cb?code=long-authz-code&state=fooobarstatebaz'); + response.get('location').should.equal('http://example.com/cb?code=long-authz-code&state=fooobarstatebaz'); }); it('should support a custom `authenticateHandler`', async function () { @@ -715,31 +806,38 @@ describe('AuthorizeHandler integration', function() { return { ...user }; } }; - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const model = Model.from({ - getAccessToken: async function() { + getAccessToken: async function () { return { client: client, user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: async function() { + getClient: async function () { return client; }, generateAuthorizationCode: async () => 'some-code', - saveAuthorizationCode: async function(code) { + saveAuthorizationCode: async function (code) { return { authorizationCode: code.authorizationCode, client: client }; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model, authenticateHandler }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model, + authenticateHandler + }); const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: { - 'Authorization': 'Bearer foo' + Authorization: 'Bearer foo' }, method: {}, query: { @@ -756,117 +854,151 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('generateAuthorizationCode()', function() { - it('should return an auth code', function() { + describe('generateAuthorizationCode()', function () { + it('should return an auth code', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - return handler.generateAuthorizationCode() - .then(function(data) { + return handler + .generateAuthorizationCode() + .then(function (data) { data.should.be.a.sha256(); }) .catch(should.fail); }); - it('should support promises', function() { + it('should support promises', function () { const model = Model.from({ - generateAuthorizationCode: async function() { + generateAuthorizationCode: async function () { return {}; }, - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const model = Model.from({ - generateAuthorizationCode: function() { + generateAuthorizationCode: function () { return {}; }, - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); handler.generateAuthorizationCode().should.be.an.instanceOf(Promise); }); }); - describe('getAuthorizationCodeLifetime()', function() { - it('should return a date', function() { + describe('getAuthorizationCodeLifetime()', function () { + it('should return a date', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); handler.getAuthorizationCodeLifetime().should.be.an.instanceOf(Date); }); }); - describe('validateRedirectUri()', function() { - it('should support empty method', function() { + describe('validateRedirectUri()', function () { + it('should support empty method', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); - handler.validateRedirectUri('http://example.com/a', { redirectUris: ['http://example.com/a'] }).should.be.an.instanceOf(Promise); + handler + .validateRedirectUri('http://example.com/a', { + redirectUris: ['http://example.com/a'] + }) + .should.be.an.instanceOf(Promise); }); - it('should support promises', function() { + it('should support promises', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {}, - validateRedirectUri: async function() { + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {}, + validateRedirectUri: async function () { return true; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); - handler.validateRedirectUri('http://example.com/a', { }).should.be.an.instanceOf(Promise); + handler.validateRedirectUri('http://example.com/a', {}).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {}, - validateRedirectUri: function() { + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {}, + validateRedirectUri: function () { return true; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); - handler.validateRedirectUri('http://example.com/a', { }).should.be.an.instanceOf(Promise); + handler.validateRedirectUri('http://example.com/a', {}).should.be.an.instanceOf(Promise); }); }); - describe('getClient()', function() { - it('should throw an error if `client_id` is missing', async function() { + describe('getClient()', function () { + it('should throw an error if `client_id` is missing', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); try { await handler.getClient(request); @@ -878,14 +1010,22 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `client_id` is invalid', async function() { + it('should throw an error if `client_id` is invalid', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { client_id: 'øå€£‰', response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 'øå€£‰', response_type: 'code' }, headers: {}, method: {}, query: {} }); try { await handler.getClient(request); @@ -897,14 +1037,26 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `client.redirectUri` is invalid', async function() { + it('should throw an error if `client.redirectUri` is invalid', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + redirect_uri: 'foobar' + }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'foobar' }, headers: {}, method: {}, query: {} }); try { await handler.getClient(request); @@ -916,106 +1068,166 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `client` is missing', function() { + it('should throw an error if `client` is missing', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: client credentials are invalid'); }); }); - it('should throw an error if `client.grants` is missing', function() { + it('should throw an error if `client.grants` is missing', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() { + getAccessToken: function () {}, + getClient: function () { return {}; }, - saveAuthorizationCode: function() {} + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: missing client `grants`'); }); }); - it('should throw an error if `client` is unauthorized', function() { + it('should throw an error if `client` is unauthorized', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() { + getAccessToken: function () {}, + getClient: function () { return { grants: [] }; }, - saveAuthorizationCode: function() {} + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(UnauthorizedClientError); e.message.should.equal('Unauthorized client: `grant_type` is invalid'); }); }); - it('should throw an error if `client.redirectUri` is missing', function() { + it('should throw an error if `client.redirectUri` is missing', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() { return { grants: ['authorization_code'] }; }, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () { + return { grants: ['authorization_code'] }; + }, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { client_id: 12345, response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 12345, response_type: 'code' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: missing client `redirectUri`'); }); }); - it('should throw an error if `client.redirectUri` is not equal to `redirectUri`', function() { + it('should throw an error if `client.redirectUri` is not equal to `redirectUri`', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['https://example.com'] }; + getAccessToken: function () {}, + getClient: function () { + return { + grants: ['authorization_code'], + redirectUris: ['https://example.com'] + }; + }, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { + client_id: 12345, + response_type: 'code', + redirect_uri: 'https://foobar.com' }, - saveAuthorizationCode: function() {} + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { client_id: 12345, response_type: 'code', redirect_uri: 'https://foobar.com' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: `redirect_uri` does not match client value'); }); }); - it('should support promises', function() { + it('should support promises', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: async function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getAccessToken: function () {}, + getClient: async function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: function() {} + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); const request = new Request({ body: { client_id: 12345 }, headers: {}, @@ -1026,15 +1238,21 @@ describe('AuthorizeHandler integration', function() { handler.getClient(request).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getAccessToken: function () {}, + getClient: function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: function() {} + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); const request = new Request({ body: { client_id: 12345 }, headers: {}, @@ -1045,21 +1263,33 @@ describe('AuthorizeHandler integration', function() { handler.getClient(request).should.be.an.instanceOf(Promise); }); - describe('with `client_id` in the request query', function() { - it('should return a client', function() { - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + describe('with `client_id` in the request query', function () { + it('should return a client', function () { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const model = Model.from({ - getAccessToken: function() {}, - getClient: function() { + getAccessToken: function () {}, + getClient: function () { return client; }, - saveAuthorizationCode: function() {} + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { response_type: 'code' }, + headers: {}, + method: {}, + query: { client_id: 12345 } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: { client_id: 12345 } }); - return handler.getClient(request) - .then(function(data) { + return handler + .getClient(request) + .then(function (data) { data.should.equal(client); }) .catch(should.fail); @@ -1067,15 +1297,23 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('getScope()', function() { - it('should throw an error if `scope` is invalid', async function() { + describe('getScope()', function () { + it('should throw an error if `scope` is invalid', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { scope: 'øå€£‰' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { scope: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { await handler.getScope(request); @@ -1087,44 +1325,69 @@ describe('AuthorizeHandler integration', function() { } }); - describe('with `scope` in the request body', function() { - it('should return the scope', function() { + describe('with `scope` in the request body', function () { + it('should return the scope', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { scope: 'foo' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { scope: 'foo' }, headers: {}, method: {}, query: {} }); handler.getScope(request).should.eql(['foo']); }); }); - describe('with `scope` in the request query', function() { - it('should return the scope', function() { + describe('with `scope` in the request query', function () { + it('should return the scope', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { scope: 'foo' } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: { scope: 'foo' } }); handler.getScope(request).should.eql(['foo']); }); }); }); - describe('getState()', function() { - it('should throw an error if `allowEmptyState` is false and `state` is missing', async function() { + describe('getState()', function () { + it('should throw an error if `allowEmptyState` is false and `state` is missing', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + allowEmptyState: false, + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ allowEmptyState: false, authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { await handler.getState(request); @@ -1138,24 +1401,41 @@ describe('AuthorizeHandler integration', function() { it('should allow missing `state` if `allowEmptyState` is valid', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + allowEmptyState: true, + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ allowEmptyState: true, authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); const state = handler.getState(request); should.equal(state, undefined); }); - it('should throw an error if `state` is invalid', async function() { + it('should throw an error if `state` is invalid', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { state: 'øå€£‰' } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'øå€£‰' } }); try { await handler.getState(request); @@ -1167,47 +1447,73 @@ describe('AuthorizeHandler integration', function() { } }); - describe('with `state` in the request body', function() { - it('should return the state', function() { + describe('with `state` in the request body', function () { + it('should return the state', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { state: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { state: 'foobar' }, headers: {}, method: {}, query: {} }); handler.getState(request).should.equal('foobar'); }); }); - describe('with `state` in the request query', function() { - it('should return the state', function() { + describe('with `state` in the request query', function () { + it('should return the state', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { state: 'foobar' } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: { state: 'foobar' } }); handler.getState(request).should.equal('foobar'); }); }); }); - describe('getUser()', function() { - it('should throw an error if `user` is missing', function() { - const authenticateHandler = { handle: function() {} }; + describe('getUser()', function () { + it('should throw an error if `user` is missing', function () { + const authenticateHandler = { handle: function () {} }; const model = Model.from({ - getClient: function() {}, - saveAuthorizationCode: function() {} + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authenticateHandler: authenticateHandler, + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); const response = new Response(); - return handler.getUser(request, response) + return handler + .getUser(request, response) .then(should.fail) .catch(function (e) { e.should.be.an.instanceOf(ServerError); @@ -1215,85 +1521,112 @@ describe('AuthorizeHandler integration', function() { }); }); - it('should return a user', function() { + it('should return a user', function () { const user = {}; const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return { user: user, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: function() {}, - saveAuthorizationCode: function() {} + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.getUser(request, response) - .then(function(data) { + return handler + .getUser(request, response) + .then(function (data) { data.should.equal(user); }) .catch(should.fail); }); }); - describe('saveAuthorizationCode()', function() { - it('should return an auth code', function() { + describe('saveAuthorizationCode()', function () { + it('should return an auth code', function () { const authorizationCode = {}; const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() { + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () { return authorizationCode; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); - return handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz') - .then(function(data) { + return handler + .saveAuthorizationCode('foo', 'bar', 'biz', 'baz') + .then(function (data) { data.should.equal(authorizationCode); }) .catch(should.fail); }); - it('should support promises when calling `model.saveAuthorizationCode()`', function() { + it('should support promises when calling `model.saveAuthorizationCode()`', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: async function() { + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: async function () { return {}; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); }); - it('should support non-promises when calling `model.saveAuthorizationCode()`', function() { + it('should support non-promises when calling `model.saveAuthorizationCode()`', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() { + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () { return {}; } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); handler.saveAuthorizationCode('foo', 'bar', 'biz', 'baz').should.be.an.instanceOf(Promise); }); }); - describe('getResponseType()', function() { - it('should throw an error if `response_type` is missing', async function() { + describe('getResponseType()', function () { + it('should throw an error if `response_type` is missing', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { await handler.getResponseType(request); @@ -1305,14 +1638,22 @@ describe('AuthorizeHandler integration', function() { } }); - it('should throw an error if `response_type` is not `code`', async function() { + it('should throw an error if `response_type` is not `code`', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { response_type: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { response_type: 'foobar' }, headers: {}, method: {}, query: {} }); try { await handler.getResponseType(request); @@ -1324,30 +1665,46 @@ describe('AuthorizeHandler integration', function() { } }); - describe('with `response_type` in the request body', function() { - it('should return a response type', function() { + describe('with `response_type` in the request body', function () { + it('should return a response type', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { response_type: 'code' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { response_type: 'code' }, headers: {}, method: {}, query: {} }); const ResponseType = handler.getResponseType(request); ResponseType.should.equal(CodeResponseType); }); }); - describe('with `response_type` in the request query', function() { - it('should return a response type', function() { + describe('with `response_type` in the request query', function () { + it('should return a response type', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: { response_type: 'code' } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: { response_type: 'code' } }); const ResponseType = handler.getResponseType(request); ResponseType.should.equal(CodeResponseType); @@ -1355,14 +1712,17 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('buildSuccessRedirectUri()', function() { - it('should return a redirect uri', function() { + describe('buildSuccessRedirectUri()', function () { + it('should return a redirect uri', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); const responseType = new CodeResponseType(12345); const redirectUri = handler.buildSuccessRedirectUri('http://example.com/cb', responseType); @@ -1370,42 +1730,53 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('buildErrorRedirectUri()', function() { - it('should set `error_description` if available', function() { + describe('buildErrorRedirectUri()', function () { + it('should set `error_description` if available', function () { const error = new InvalidClientError('foo bar'); const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); const redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=foo%20bar'); }); - it('should return a redirect uri', function() { + it('should return a redirect uri', function () { const error = new InvalidClientError(); const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); const redirectUri = handler.buildErrorRedirectUri('http://example.com/cb', error); - url.format(redirectUri).should.equal('http://example.com/cb?error=invalid_client&error_description=Bad%20Request'); + url + .format(redirectUri) + .should.equal('http://example.com/cb?error=invalid_client&error_description=Bad%20Request'); }); }); - describe('updateResponse()', function() { - it('should set the `location` header', function() { + describe('updateResponse()', function () { + it('should set the `location` header', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); const response = new Response({ body: {}, headers: {} }); const uri = url.parse('http://example.com/cb'); @@ -1415,21 +1786,26 @@ describe('AuthorizeHandler integration', function() { }); }); - describe('getCodeChallengeMethod()', function() { + describe('getCodeChallengeMethod()', function () { it('should throw if the code challenge method is not supported', async function () { const methods = ['plain', 'foo', ' ', '0', true, {}, []]; for (const method of methods) { const model = Model.from({ - getAccessToken: function () { - }, - getClient: function () { - }, - saveAuthorizationCode: function () { - } + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { code_challenge_method: method }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: { code_challenge_method: method }, headers: {}, method: {}, query: {} }); try { await handler.getCodeChallengeMethod(request); @@ -1438,8 +1814,7 @@ describe('AuthorizeHandler integration', function() { if (method === 'plain') { e.should.be.an.instanceOf(InvalidRequestError); e.message.should.equal('Invalid request: `code_challenge_method` "plain" is not allowed; use "S256"'); - } - else { + } else { e.should.be.an.instanceOf(InvalidRequestError); e.message.should.equal(`Invalid request: transform algorithm '${method}' not supported`); } @@ -1447,27 +1822,43 @@ describe('AuthorizeHandler integration', function() { } }); - it('should get code challenge method', function() { + it('should get code challenge method', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { code_challenge_method: 'S256' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {code_challenge_method: 'S256'}, headers: {}, method: {}, query: {} }); - const codeChallengeMethod = handler.getCodeChallengeMethod(request); + const codeChallengeMethod = handler.getCodeChallengeMethod(request); codeChallengeMethod.should.equal('S256'); }); it('should throw if the code challenge method is not supported', async function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { code_challenge_method: 'foo' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {code_challenge_method: 'foo'}, headers: {}, method: {}, query: {} }); try { await handler.getCodeChallengeMethod(request); @@ -1476,48 +1867,73 @@ describe('AuthorizeHandler integration', function() { } catch (e) { // defined in RFC 7636 - 4.4 e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal('Invalid request: transform algorithm \'foo\' not supported'); + e.message.should.equal("Invalid request: transform algorithm 'foo' not supported"); } }); - it('should get default code challenge method S256 if missing (default)', function() { + it('should get default code challenge method S256 if missing (default)', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - const codeChallengeMethod = handler.getCodeChallengeMethod(request); + const codeChallengeMethod = handler.getCodeChallengeMethod(request); codeChallengeMethod.should.equal('S256'); }); - it('should get default code challenge method plain if missing and plain PKCE is enabled', function() { + it('should get default code challenge method plain if missing and plain PKCE is enabled', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + enablePlainPKCE: true, + model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, enablePlainPKCE: true, model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); - const codeChallengeMethod = handler.getCodeChallengeMethod(request); + const codeChallengeMethod = handler.getCodeChallengeMethod(request); codeChallengeMethod.should.equal('plain'); }); }); - describe('getCodeChallenge()', function() { - it('should get code challenge', function() { + describe('getCodeChallenge()', function () { + it('should get code challenge', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model + }); + const request = new Request({ + body: { code_challenge: 'challenge' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model }); - const request = new Request({ body: {code_challenge: 'challenge'}, headers: {}, method: {}, query: {} }); - const codeChallengeMethod = handler.getCodeChallenge(request); + const codeChallengeMethod = handler.getCodeChallenge(request); codeChallengeMethod.should.equal('challenge'); }); }); diff --git a/test/integration/handlers/token-handler_test.js b/test/integration/handlers/token-handler_test.js index 7fc0a2b4..ba68e8d4 100644 --- a/test/integration/handlers/token-handler_test.js +++ b/test/integration/handlers/token-handler_test.js @@ -27,9 +27,9 @@ const stringUtil = require('../../../lib/utils/string-util'); * Test `TokenHandler` integration. */ -describe('TokenHandler integration', function() { - describe('constructor()', function() { - it('should throw an error if `options.accessTokenLifetime` is missing', function() { +describe('TokenHandler integration', function () { + describe('constructor()', function () { + it('should throw an error if `options.accessTokenLifetime` is missing', function () { try { new TokenHandler(); @@ -40,7 +40,7 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `options.model` is missing', function() { + it('should throw an error if `options.model` is missing', function () { try { new TokenHandler({ accessTokenLifetime: 120 }); @@ -51,7 +51,7 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `options.refreshTokenLifetime` is missing', function() { + it('should throw an error if `options.refreshTokenLifetime` is missing', function () { try { new TokenHandler({ accessTokenLifetime: 120, model: {} }); @@ -62,9 +62,13 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if the model does not implement `getClient()`', function() { + it('should throw an error if the model does not implement `getClient()`', function () { try { - new TokenHandler({ accessTokenLifetime: 120, model: {}, refreshTokenLifetime: 120 }); + new TokenHandler({ + accessTokenLifetime: 120, + model: {}, + refreshTokenLifetime: 120 + }); should.fail(); } catch (e) { @@ -73,88 +77,123 @@ describe('TokenHandler integration', function() { } }); - it('should set the `accessTokenLifetime`', function() { + it('should set the `accessTokenLifetime`', function () { const accessTokenLifetime = {}; const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: accessTokenLifetime, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: accessTokenLifetime, model: model, refreshTokenLifetime: 120 }); handler.accessTokenLifetime.should.equal(accessTokenLifetime); }); - it('should set the `alwaysIssueNewRefreshToken`', function() { + it('should set the `alwaysIssueNewRefreshToken`', function () { const alwaysIssueNewRefreshToken = true; const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 120, + alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); - const handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); }); - it('should set the `alwaysIssueNewRefreshToken` to false', function() { + it('should set the `alwaysIssueNewRefreshToken` to false', function () { const alwaysIssueNewRefreshToken = false; const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 120, + alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); - const handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120, alwaysIssueNewRefreshToken: alwaysIssueNewRefreshToken }); handler.alwaysIssueNewRefreshToken.should.equal(alwaysIssueNewRefreshToken); }); - it('should return the default `alwaysIssueNewRefreshToken` value', function() { + it('should return the default `alwaysIssueNewRefreshToken` value', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 123, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 123, model: model, refreshTokenLifetime: 120 }); handler.alwaysIssueNewRefreshToken.should.equal(true); }); - it('should set the `extendedGrantTypes`', function() { + it('should set the `extendedGrantTypes`', function () { const extendedGrantTypes = { foo: 'bar' }; const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + extendedGrantTypes: extendedGrantTypes, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, extendedGrantTypes: extendedGrantTypes, model: model, refreshTokenLifetime: 120 }); handler.grantTypes.should.deep.include(extendedGrantTypes); }); - it('should set the `model`', function() { + it('should set the `model`', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.model.should.equal(model); }); - it('should set the `refreshTokenLifetime`', function() { + it('should set the `refreshTokenLifetime`', function () { const refreshTokenLifetime = {}; const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: refreshTokenLifetime }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: refreshTokenLifetime }); handler.refreshTokenLifetime.should.equal(refreshTokenLifetime); }); }); - describe('handle()', function() { - it('should throw an error if `request` is missing', async function() { + describe('handle()', function () { + it('should throw an error if `request` is missing', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); try { await handler.handle(); @@ -166,13 +205,22 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `response` is missing', async function() { + it('should throw an error if `response` is missing', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { await handler.handle(request); @@ -184,66 +232,103 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if the method is not `POST`', function() { + it('should throw an error if the method is not `POST`', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: {}, + headers: {}, + method: 'GET', + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: {}, headers: {}, method: 'GET', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidRequestError); e.message.should.equal('Invalid request: method must be POST'); }); }); - it('should throw an error if the media type is not `application/x-www-form-urlencoded`', function() { + it('should throw an error if the media type is not `application/x-www-form-urlencoded`', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: {}, + headers: {}, + method: 'POST', + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: {}, headers: {}, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidRequestError); e.message.should.equal('Invalid request: content must be application/x-www-form-urlencoded'); }); }); - it('should throw the error if an oauth error is thrown', function() { + it('should throw the error if an oauth error is thrown', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: {}, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, + method: 'POST', + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: {}, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: cannot retrieve client credentials'); }); }); - it('should throw a server error if a non-oauth error is thrown', function() { + it('should throw a server error if a non-oauth error is thrown', function () { const model = Model.from({ - getClient: function() { + getClient: function () { throw new Error('Unhandled exception'); }, - getUser: function() {}, - saveToken: function() {} + getUser: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { client_id: 12345, @@ -252,30 +337,38 @@ describe('TokenHandler integration', function() { password: 'bar', username: 'foo' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(ServerError); e.message.should.equal('Unhandled exception'); e.inner.should.be.an.instanceOf(Error); }); }); - it('should update the response if an error is thrown', function() { + it('should update the response if an error is thrown', function () { const model = Model.from({ - getClient: function() { + getClient: function () { throw new Error('Unhandled exception'); }, - getUser: function() {}, - saveToken: function() {} + getUser: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { client_id: 12345, @@ -284,29 +377,54 @@ describe('TokenHandler integration', function() { password: 'bar', username: 'foo' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) + return handler + .handle(request, response) .then(should.fail) - .catch(function() { - response.body.should.eql({ error: 'server_error', error_description: 'Unhandled exception' }); + .catch(function () { + response.body.should.eql({ + error: 'server_error', + error_description: 'Unhandled exception' + }); response.status.should.equal(503); }); }); - it('should return a bearer token if successful', function() { - const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: ['foobar'], user: {} }; + it('should return a bearer token if successful', function () { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: ['foobar'], + user: {} + }; const model = Model.from({ - getClient: function() { return { grants: ['password'] }; }, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return ['baz']; } + getClient: function () { + return { grants: ['password'] }; + }, + getUser: function () { + return {}; + }, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['baz']; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { client_id: 12345, @@ -316,28 +434,51 @@ describe('TokenHandler integration', function() { grant_type: 'password', scope: 'baz' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) - .then(function(data) { + return handler + .handle(request, response) + .then(function (data) { data.should.eql(token); }) .catch(should.fail); }); - it('should not return custom attributes in a bearer token if the allowExtendedTokenAttributes is not set', function() { - const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: ['baz'], user: {}, foo: 'bar' }; + it('should not return custom attributes in a bearer token if the allowExtendedTokenAttributes is not set', function () { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: ['baz'], + user: {}, + foo: 'bar' + }; const model = Model.from({ - getClient: function() { return { grants: ['password'] }; }, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return ['baz']; } + getClient: function () { + return { grants: ['password'] }; + }, + getUser: function () { + return {}; + }, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['baz']; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { client_id: 12345, @@ -347,14 +488,18 @@ describe('TokenHandler integration', function() { grant_type: 'password', scope: 'baz' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) - .then(function() { + return handler + .handle(request, response) + .then(function () { should.exist(response.body.access_token); should.exist(response.body.refresh_token); should.exist(response.body.token_type); @@ -364,15 +509,35 @@ describe('TokenHandler integration', function() { .catch(should.fail); }); - it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', function() { - const token = { accessToken: 'foo', client: {}, refreshToken: 'bar', scope: ['baz'], user: {}, foo: 'bar' }; + it('should return custom attributes in a bearer token if the allowExtendedTokenAttributes is set', function () { + const token = { + accessToken: 'foo', + client: {}, + refreshToken: 'bar', + scope: ['baz'], + user: {}, + foo: 'bar' + }; const model = Model.from({ - getClient: function() { return { grants: ['password'] }; }, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return ['baz']; } + getClient: function () { + return { grants: ['password'] }; + }, + getUser: function () { + return {}; + }, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['baz']; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120, + allowExtendedTokenAttributes: true }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, allowExtendedTokenAttributes: true }); const request = new Request({ body: { client_id: 12345, @@ -382,14 +547,18 @@ describe('TokenHandler integration', function() { grant_type: 'password', scope: 'baz' }, - headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, method: 'POST', query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.handle(request, response) - .then(function() { + return handler + .handle(request, response) + .then(function () { should.exist(response.body.access_token); should.exist(response.body.refresh_token); should.exist(response.body.token_type); @@ -400,15 +569,23 @@ describe('TokenHandler integration', function() { }); }); - - describe('getClient()', function() { - it('should throw an error if `clientId` is invalid', async function() { + describe('getClient()', function () { + it('should throw an error if `clientId` is invalid', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 'øå€£‰', client_secret: 'foo' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 'øå€£‰', client_secret: 'foo' }, headers: {}, method: {}, query: {} }); try { await handler.getClient(request); @@ -420,13 +597,22 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `clientSecret` is invalid', async function() { + it('should throw an error if `clientSecret` is invalid', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 'foo', client_secret: 'øå€£‰' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 'foo', client_secret: 'øå€£‰' }, headers: {}, method: {}, query: {} }); try { await handler.getClient(request); @@ -438,71 +624,112 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `client` is missing', function() { + it('should throw an error if `client` is missing', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.message.should.equal('Invalid client: client is invalid'); }); }); - it('should throw an error if `client.grants` is missing', function() { + it('should throw an error if `client.grants` is missing', function () { const model = Model.from({ - getClient: function() { return {}; }, - saveToken: function() {} + getClient: function () { + return {}; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(ServerError); e.message.should.equal('Server error: missing client `grants`'); }); }); - it('should throw an error if `client.grants` is invalid', function() { + it('should throw an error if `client.grants` is invalid', function () { const model = Model.from({ - getClient: function() { return { grants: 'foobar' }; }, - saveToken: function() {} + getClient: function () { + return { grants: 'foobar' }; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) + return handler + .getClient(request) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(ServerError); e.message.should.equal('Server error: `grants` must be an array'); }); }); - it('should throw a 401 error if the client is invalid and the request contains an authorization header', function() { + it('should throw a 401 error if the client is invalid and the request contains an authorization header', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: {}, - headers: { 'authorization': util.format('Basic %s', Buffer.from('foo:bar').toString('base64')) }, + headers: { + authorization: util.format('Basic %s', Buffer.from('foo:bar').toString('base64')) + }, method: {}, query: {} }); const response = new Response({ body: {}, headers: {} }); - return handler.getClient(request, response) + return handler + .getClient(request, response) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidClientError); e.code.should.equal(401); e.message.should.equal('Invalid client: client is invalid'); @@ -511,29 +738,42 @@ describe('TokenHandler integration', function() { }); }); - it('should return a client', function() { + it('should return a client', function () { const client = { id: 12345, grants: [] }; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) - .then(function(data) { + return handler + .getClient(request) + .then(function (data) { data.should.equal(client); }) .catch(should.fail); }); - describe('with `password` grant type and `requireClientAuthentication` is false', function() { - - it('should return a client ', function() { + describe('with `password` grant type and `requireClientAuthentication` is false', function () { + it('should return a client ', function () { const client = { id: 12345, grants: [] }; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} }); const handler = new TokenHandler({ @@ -544,23 +784,30 @@ describe('TokenHandler integration', function() { password: false } }); - const request = new Request({ body: { client_id: 'blah', grant_type: 'password'}, headers: {}, method: {}, query: {} }); + const request = new Request({ + body: { client_id: 'blah', grant_type: 'password' }, + headers: {}, + method: {}, + query: {} + }); - return handler.getClient(request) - .then(function(data) { + return handler + .getClient(request) + .then(function (data) { data.should.equal(client); }) .catch(should.fail); }); }); - describe('with `password` grant type and `requireClientAuthentication` is false and Authorization header', function() { - - it('should return a client ', function() { + describe('with `password` grant type and `requireClientAuthentication` is false and Authorization header', function () { + it('should return a client ', function () { const client = { id: 12345, grants: [] }; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} }); const handler = new TokenHandler({ @@ -572,51 +819,85 @@ describe('TokenHandler integration', function() { } }); const request = new Request({ - body: { grant_type: 'password'}, - headers: { 'authorization': util.format('Basic %s', Buffer.from('blah:').toString('base64')) }, + body: { grant_type: 'password' }, + headers: { + authorization: util.format('Basic %s', Buffer.from('blah:').toString('base64')) + }, method: {}, query: {} }); - return handler.getClient(request) - .then(function(data) { + return handler + .getClient(request) + .then(function (data) { data.should.equal(client); }) .catch(should.fail); }); }); - it('should support promises', function() { + it('should support promises', function () { const model = Model.from({ - getClient: async function() { return { grants: [] }; }, - saveToken: function() {} + getClient: async function () { + return { grants: [] }; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); handler.getClient(request).should.be.an.instanceOf(Promise); }); - it('should support non-promises', function() { + it('should support non-promises', function () { const model = Model.from({ - getClient: function() { return { grants: [] }; }, - saveToken: function() {} + getClient: function () { + return { grants: [] }; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); handler.getClient(request).should.be.an.instanceOf(Promise); }); }); - describe('getClientCredentials()', function() { - it('should throw an error if `client_id` is missing', async function() { + describe('getClientCredentials()', function () { + it('should throw an error if `client_id` is missing', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_secret: 'foo' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_secret: 'foo' }, headers: {}, method: {}, query: {} }); try { await handler.getClientCredentials(request); @@ -628,13 +909,22 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `client_secret` is missing', async function() { + it('should throw an error if `client_secret` is missing', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 'foo' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 'foo' }, headers: {}, method: {}, query: {} }); try { await handler.getClientCredentials(request); @@ -646,31 +936,45 @@ describe('TokenHandler integration', function() { } }); - describe('with `client_id` and grant type is `password` and `requireClientAuthentication` is false', function() { - it('should return a client', function() { + describe('with `client_id` and grant type is `password` and `requireClientAuthentication` is false', function () { + it('should return a client', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120, + requireClientAuthentication: { password: false } + }); + const request = new Request({ + body: { client_id: 'foo', grant_type: 'password' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, requireClientAuthentication: { password: false} }); - const request = new Request({ body: { client_id: 'foo', grant_type: 'password' }, headers: {}, method: {}, query: {} }); const credentials = handler.getClientCredentials(request); credentials.should.eql({ clientId: 'foo' }); }); }); - describe('with `client_id` and `client_secret` in the request header as basic auth', function() { - it('should return a client', function() { + describe('with `client_id` and `client_secret` in the request header as basic auth', function () { + it('should return a client', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: {}, headers: { - 'authorization': util.format('Basic %s', Buffer.from('foo:bar').toString('base64')) + authorization: util.format('Basic %s', Buffer.from('foo:bar').toString('base64')) }, method: {}, query: {} @@ -681,14 +985,23 @@ describe('TokenHandler integration', function() { }); }); - describe('with `client_id` and `client_secret` in the request body', function() { - it('should return a client', function() { + describe('with `client_id` and `client_secret` in the request body', function () { + it('should return a client', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 'foo', client_secret: 'bar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 'foo', client_secret: 'bar' }, headers: {}, method: {}, query: {} }); const credentials = handler.getClientCredentials(request); credentials.should.eql({ clientId: 'foo', clientSecret: 'bar' }); @@ -696,14 +1009,23 @@ describe('TokenHandler integration', function() { }); }); - describe('handleGrantType()', function() { - it('should throw an error if `grant_type` is missing', async function() { + describe('handleGrantType()', function () { + it('should throw an error if `grant_type` is missing', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); try { await handler.handleGrantType(request); @@ -715,13 +1037,22 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `grant_type` is invalid', async function() { + it('should throw an error if `grant_type` is invalid', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { grant_type: '~foo~' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { grant_type: '~foo~' }, headers: {}, method: {}, query: {} }); try { await handler.handleGrantType(request); @@ -733,13 +1064,22 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `grant_type` is unsupported', async function() { + it('should throw an error if `grant_type` is unsupported', async function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { grant_type: 'foobar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { grant_type: 'foobar' }, headers: {}, method: {}, query: {} }); try { await handler.handleGrantType(request); @@ -751,14 +1091,23 @@ describe('TokenHandler integration', function() { } }); - it('should throw an error if `grant_type` is unauthorized', async function() { + it('should throw an error if `grant_type` is unauthorized', async function () { const client = { grants: ['client_credentials'] }; const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { grant_type: 'password' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { grant_type: 'password' }, headers: {}, method: {}, query: {} }); try { await handler.handleGrantType(request, client); @@ -770,36 +1119,70 @@ describe('TokenHandler integration', function() { } }); - it('should throw an invalid grant error if a non-oauth error is thrown', function() { + it('should throw an invalid grant error if a non-oauth error is thrown', function () { const client = { grants: ['password'] }; const model = Model.from({ - getClient: function(clientId, password) { return client; }, - getUser: function(uid, pwd) {}, - saveToken: function() {} + getClient: function (clientId, password) { + return client; + }, + getUser: function (uid, pwd) {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { grant_type: 'password', username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { grant_type: 'password', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - return handler.handleGrantType(request, client) + return handler + .handleGrantType(request, client) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: user credentials are invalid'); }); }); - describe('with grant_type `authorization_code`', function() { - it('should return a token', function() { + describe('with grant_type `authorization_code`', function () { + it('should return a token', function () { const client = { id: 'foobar', grants: ['authorization_code'] }; const token = {}; const model = Model.from({ - getAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() * 2), user: {} }; }, - getClient: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; }, - revokeAuthorizationCode: function() { return { authorizationCode: 12345, client: { id: 'foobar' }, expiresAt: new Date(new Date() / 2), user: {} }; } + getAuthorizationCode: function () { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() * 2), + user: {} + }; + }, + getClient: function () {}, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + }, + revokeAuthorizationCode: function () { + return { + authorizationCode: 12345, + client: { id: 'foobar' }, + expiresAt: new Date(new Date() / 2), + user: {} + }; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { code: 12345, @@ -810,16 +1193,17 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) - .then(function(data) { + return handler + .handleGrantType(request, client) + .then(function (data) { data.should.equal(token); }) .catch(should.fail); }); }); - describe('with PKCE', function() { - it('should return a token when code verifier is valid using S256 code challenge method', async function() { + describe('with PKCE', function () { + it('should return a token when code verifier is valid using S256 code challenge method', async function () { const methods = ['S256', undefined]; for (const method of methods) { @@ -838,8 +1222,7 @@ describe('TokenHandler integration', function() { getAuthorizationCode: function () { return authorizationCode; }, - getClient: function () { - }, + getClient: function () {}, saveToken: function () { return token; }, @@ -850,7 +1233,11 @@ describe('TokenHandler integration', function() { return authorizationCode; } }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); const request = new Request({ body: { code: 12345, @@ -867,7 +1254,7 @@ describe('TokenHandler integration', function() { } }); - it('should return a token when code verifier is valid using plain code challenge method', async function() { + it('should return a token when code verifier is valid using plain code challenge method', async function () { const methods = ['plain', undefined]; for (const method of methods) { @@ -886,8 +1273,7 @@ describe('TokenHandler integration', function() { getAuthorizationCode: function () { return authorizationCode; }, - getClient: function () { - }, + getClient: function () {}, saveToken: function () { return token; }, @@ -900,7 +1286,9 @@ describe('TokenHandler integration', function() { }); const handler = new TokenHandler({ enablePlainPKCE: true, - accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); const request = new Request({ body: { @@ -918,7 +1306,7 @@ describe('TokenHandler integration', function() { } }); - it('should throw an invalid grant error when code verifier is invalid', function() { + it('should throw an invalid grant error when code verifier is invalid', function () { const codeVerifier = stringUtil.base64URLEncode(crypto.randomBytes(32)); const authorizationCode = { authorizationCode: 12345, @@ -931,13 +1319,25 @@ describe('TokenHandler integration', function() { const client = { id: 'foobar', grants: ['authorization_code'] }; const token = {}; const model = Model.from({ - getAuthorizationCode: function() { return authorizationCode; }, - getClient: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; }, - revokeAuthorizationCode: function() { return authorizationCode; } + getAuthorizationCode: function () { + return authorizationCode; + }, + getClient: function () {}, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + }, + revokeAuthorizationCode: function () { + return authorizationCode; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { code: 12345, @@ -949,15 +1349,16 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) + return handler + .handleGrantType(request, client) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: code verifier is invalid'); }); }); - it('should throw an invalid grant error when code verifier is missing', function() { + it('should throw an invalid grant error when code verifier is missing', function () { const codeVerifier = stringUtil.base64URLEncode(crypto.randomBytes(32)); const authorizationCode = { authorizationCode: 12345, @@ -970,13 +1371,25 @@ describe('TokenHandler integration', function() { const client = { id: 'foobar', grants: ['authorization_code'] }; const token = {}; const model = Model.from({ - getAuthorizationCode: function() { return authorizationCode; }, - getClient: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; }, - revokeAuthorizationCode: function() { return authorizationCode; } + getAuthorizationCode: function () { + return authorizationCode; + }, + getClient: function () {}, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + }, + revokeAuthorizationCode: function () { + return authorizationCode; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { code: 12345, @@ -987,15 +1400,16 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) + return handler + .handleGrantType(request, client) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Missing parameter: `code_verifier`'); }); }); - it('should throw an invalid grant error when code verifier is present but code challenge is missing', function() { + it('should throw an invalid grant error when code verifier is present but code challenge is missing', function () { const authorizationCode = { authorizationCode: 12345, client: { id: 'foobar' }, @@ -1005,13 +1419,25 @@ describe('TokenHandler integration', function() { const client = { id: 'foobar', grants: ['authorization_code'] }; const token = {}; const model = Model.from({ - getAuthorizationCode: function() { return authorizationCode; }, - getClient: function() {}, - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; }, - revokeAuthorizationCode: function() { return authorizationCode; } + getAuthorizationCode: function () { + return authorizationCode; + }, + getClient: function () {}, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + }, + revokeAuthorizationCode: function () { + return authorizationCode; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { code: 12345, @@ -1023,26 +1449,37 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) + return handler + .handleGrantType(request, client) .then(should.fail) - .catch(function(e) { + .catch(function (e) { e.should.be.an.instanceOf(InvalidGrantError); e.message.should.equal('Invalid grant: code verifier is invalid'); }); }); }); - describe('with grant_type `client_credentials`', function() { - it('should return a token', function() { + describe('with grant_type `client_credentials`', function () { + it('should return a token', function () { const client = { grants: ['client_credentials'] }; const token = {}; const model = Model.from({ - getClient: function() {}, - getUserFromClient: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; } + getClient: function () {}, + getUserFromClient: function () { + return {}; + }, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { grant_type: 'client_credentials', @@ -1053,25 +1490,36 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) - .then(function(data) { + return handler + .handleGrantType(request, client) + .then(function (data) { data.should.equal(token); }) .catch(should.fail); }); }); - describe('with grant_type `password`', function() { - it('should return a token', function() { + describe('with grant_type `password`', function () { + it('should return a token', function () { const client = { grants: ['password'] }; const token = {}; const model = Model.from({ - getClient: function() {}, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return ['baz']; } + getClient: function () {}, + getUser: function () { + return {}; + }, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['baz']; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { client_id: 12345, @@ -1086,25 +1534,46 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) - .then(function(data) { + return handler + .handleGrantType(request, client) + .then(function (data) { data.should.equal(token); }) .catch(should.fail); }); }); - describe('with grant_type `refresh_token`', function() { - it('should return a token', function() { + describe('with grant_type `refresh_token`', function () { + it('should return a token', function () { const client = { grants: ['refresh_token'] }; const token = { accessToken: 'foo', client: {}, user: {} }; const model = Model.from({ - getClient: function() {}, - getRefreshToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() * 2), user: {} }; }, - saveToken: function() { return token; }, - revokeToken: function() { return { accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }; } + getClient: function () {}, + getRefreshToken: function () { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() * 2), + user: {} + }; + }, + saveToken: function () { + return token; + }, + revokeToken: function () { + return { + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const request = new Request({ body: { grant_type: 'refresh_token', @@ -1115,29 +1584,55 @@ describe('TokenHandler integration', function() { query: {} }); - return handler.handleGrantType(request, client) - .then(function(data) { + return handler + .handleGrantType(request, client) + .then(function (data) { data.should.equal(token); }) .catch(should.fail); }); }); - describe('with custom grant_type', function() { - it('should return a token', function() { - const client = { grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'] }; + describe('with custom grant_type', function () { + it('should return a token', function () { + const client = { + grants: ['urn:ietf:params:oauth:grant-type:saml2-bearer'] + }; const token = {}; const model = Model.from({ - getClient: function() {}, - getUser: function() { return {}; }, - saveToken: function() { return token; }, - validateScope: function() { return ['foo']; } + getClient: function () {}, + getUser: function () { + return {}; + }, + saveToken: function () { + return token; + }, + validateScope: function () { + return ['foo']; + } + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120, + extendedGrantTypes: { + 'urn:ietf:params:oauth:grant-type:saml2-bearer': PasswordGrantType + } + }); + const request = new Request({ + body: { + grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', + username: 'foo', + password: 'bar' + }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120, extendedGrantTypes: { 'urn:ietf:params:oauth:grant-type:saml2-bearer': PasswordGrantType } }); - const request = new Request({ body: { grant_type: 'urn:ietf:params:oauth:grant-type:saml2-bearer', username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); - return handler.handleGrantType(request, client) - .then(function(data) { + return handler + .handleGrantType(request, client) + .then(function (data) { data.should.equal(token); }) .catch(should.fail); @@ -1145,87 +1640,137 @@ describe('TokenHandler integration', function() { }); }); - describe('getAccessTokenLifetime()', function() { - it('should return the client access token lifetime', function() { + describe('getAccessTokenLifetime()', function () { + it('should return the client access token lifetime', function () { const client = { accessTokenLifetime: 60 }; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getAccessTokenLifetime(client).should.equal(60); }); - it('should return the default access token lifetime', function() { + it('should return the default access token lifetime', function () { const client = {}; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getAccessTokenLifetime(client).should.equal(120); }); }); - describe('getRefreshTokenLifetime()', function() { - it('should return the client access token lifetime', function() { + describe('getRefreshTokenLifetime()', function () { + it('should return the client access token lifetime', function () { const client = { refreshTokenLifetime: 60 }; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getRefreshTokenLifetime(client).should.equal(60); }); - it('should return the default access token lifetime', function() { + it('should return the default access token lifetime', function () { const client = {}; const model = Model.from({ - getClient: function() { return client; }, - saveToken: function() {} + getClient: function () { + return client; + }, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); handler.getRefreshTokenLifetime(client).should.equal(120); }); }); - describe('getTokenType()', function() { - it('should return a token type', function() { + describe('getTokenType()', function () { + it('should return a token type', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const tokenType = handler.getTokenType({ + accessToken: 'foo', + refreshToken: 'bar', + scope: ['foobar'] + }); + tokenType.should.deep.include({ + accessToken: 'foo', + accessTokenLifetime: undefined, + refreshToken: 'bar', + scope: ['foobar'] }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const tokenType = handler.getTokenType({ accessToken: 'foo', refreshToken: 'bar', scope: ['foobar'] }); - tokenType.should.deep.include({ accessToken: 'foo', accessTokenLifetime: undefined, refreshToken: 'bar', scope: ['foobar'] }); }); }); - describe('updateSuccessResponse()', function() { - it('should set the `body`', function() { + describe('updateSuccessResponse()', function () { + it('should set the `body`', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const tokenType = new BearerTokenType('foo', 'bar', 'biz'); const response = new Response({ body: {}, headers: {} }); handler.updateSuccessResponse(response, tokenType); - response.body.should.eql({ access_token: 'foo', expires_in: 'bar', refresh_token: 'biz', token_type: 'Bearer' }); + response.body.should.eql({ + access_token: 'foo', + expires_in: 'bar', + refresh_token: 'biz', + token_type: 'Bearer' + }); }); - it('should set the `Cache-Control` header', function() { + it('should set the `Cache-Control` header', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const tokenType = new BearerTokenType('foo', 'bar', 'biz'); const response = new Response({ body: {}, headers: {} }); @@ -1234,12 +1779,16 @@ describe('TokenHandler integration', function() { response.get('Cache-Control').should.equal('no-store'); }); - it('should set the `Pragma` header', function() { + it('should set the `Pragma` header', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const tokenType = new BearerTokenType('foo', 'bar', 'biz'); const response = new Response({ body: {}, headers: {} }); @@ -1249,14 +1798,18 @@ describe('TokenHandler integration', function() { }); }); - describe('updateErrorResponse()', function() { - it('should set the `body`', function() { + describe('updateErrorResponse()', function () { + it('should set the `body`', function () { const error = new AccessDeniedError('Cannot request a token'); const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const response = new Response({ body: {}, headers: {} }); handler.updateErrorResponse(response, error); @@ -1265,13 +1818,17 @@ describe('TokenHandler integration', function() { response.body.error_description.should.equal('Cannot request a token'); }); - it('should set the `status`', function() { + it('should set the `status`', function () { const error = new AccessDeniedError('Cannot request a token'); const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); const response = new Response({ body: {}, headers: {} }); handler.updateErrorResponse(response, error); diff --git a/test/integration/request_test.js b/test/integration/request_test.js index e0c98f13..76dbd6d4 100644 --- a/test/integration/request_test.js +++ b/test/integration/request_test.js @@ -12,9 +12,9 @@ const should = require('chai').should(); * Test `Request` integration. */ -describe('Request integration', function() { - describe('constructor()', function() { - it('should throw an error if `headers` is missing', function() { +describe('Request integration', function () { + describe('constructor()', function () { + it('should throw an error if `headers` is missing', function () { try { new Request({ body: {} }); @@ -25,7 +25,7 @@ describe('Request integration', function() { } }); - it('should throw an error if `method` is missing', function() { + it('should throw an error if `method` is missing', function () { try { new Request({ body: {}, headers: {} }); @@ -36,7 +36,7 @@ describe('Request integration', function() { } }); - it('should throw an error if `query` is missing', function() { + it('should throw an error if `query` is missing', function () { try { new Request({ body: {}, headers: {}, method: {} }); @@ -47,39 +47,64 @@ describe('Request integration', function() { } }); - it('should set the `body`', function() { - const request = new Request({ body: 'foo', headers: {}, method: {}, query: {} }); + it('should set the `body`', function () { + const request = new Request({ + body: 'foo', + headers: {}, + method: {}, + query: {} + }); request.body.should.equal('foo'); }); - it('should set the `headers`', function() { - const request = new Request({ body: {}, headers: { foo: 'bar', QuX: 'biz' }, method: {}, query: {} }); + it('should set the `headers`', function () { + const request = new Request({ + body: {}, + headers: { foo: 'bar', QuX: 'biz' }, + method: {}, + query: {} + }); request.headers.should.eql({ foo: 'bar', qux: 'biz' }); }); - it('should set the `method`', function() { - const request = new Request({ body: {}, headers: {}, method: 'biz', query: {} }); + it('should set the `method`', function () { + const request = new Request({ + body: {}, + headers: {}, + method: 'biz', + query: {} + }); request.method.should.equal('biz'); }); - it('should set the `query`', function() { - const request = new Request({ body: {}, headers: {}, method: {}, query: 'baz' }); + it('should set the `query`', function () { + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: 'baz' + }); request.query.should.equal('baz'); }); }); - describe('get()', function() { - it('should return `undefined` if the field does not exist', function() { - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + describe('get()', function () { + it('should return `undefined` if the field does not exist', function () { + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); (undefined === request.get('content-type')).should.be.true; }); - it('should return the value if the field exists', function() { + it('should return the value if the field exists', function () { const request = new Request({ body: {}, headers: { @@ -93,8 +118,8 @@ describe('Request integration', function() { }); }); - describe('is()', function() { - it('should accept an array of `types`', function() { + describe('is()', function () { + it('should accept an array of `types`', function () { const request = new Request({ body: {}, headers: { @@ -108,7 +133,7 @@ describe('Request integration', function() { request.is(['html', 'json']).should.equal('json'); }); - it('should accept multiple `types` as arguments', function() { + it('should accept multiple `types` as arguments', function () { const request = new Request({ body: {}, headers: { @@ -122,7 +147,7 @@ describe('Request integration', function() { request.is('html', 'json').should.equal('json'); }); - it('should return the first matching type', function() { + it('should return the first matching type', function () { const request = new Request({ body: {}, headers: { @@ -136,7 +161,7 @@ describe('Request integration', function() { request.is('html').should.equal('html'); }); - it('should return `false` if none of the `types` match', function() { + it('should return `false` if none of the `types` match', function () { const request = new Request({ body: {}, headers: { @@ -150,8 +175,13 @@ describe('Request integration', function() { request.is('json').should.be.false; }); - it('should return `false` if the request has no body', function() { - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); + it('should return `false` if the request has no body', function () { + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} + }); request.is('text/html').should.be.false; }); diff --git a/test/integration/response-types/code-response-type_test.js b/test/integration/response-types/code-response-type_test.js index 44bd53b0..d97c48e3 100644 --- a/test/integration/response-types/code-response-type_test.js +++ b/test/integration/response-types/code-response-type_test.js @@ -13,9 +13,9 @@ const url = require('url'); * Test `CodeResponseType` integration. */ -describe('CodeResponseType integration', function() { - describe('constructor()', function() { - it('should throw an error if `code` is missing', function() { +describe('CodeResponseType integration', function () { + describe('constructor()', function () { + it('should throw an error if `code` is missing', function () { try { new CodeResponseType(); @@ -26,15 +26,15 @@ describe('CodeResponseType integration', function() { } }); - it('should set the `code`', function() { + it('should set the `code`', function () { const responseType = new CodeResponseType('foo'); responseType.code.should.equal('foo'); }); }); - describe('buildRedirectUri()', function() { - it('should throw an error if the `redirectUri` is missing', function() { + describe('buildRedirectUri()', function () { + it('should throw an error if the `redirectUri` is missing', function () { const responseType = new CodeResponseType('foo'); try { @@ -47,14 +47,14 @@ describe('CodeResponseType integration', function() { } }); - it('should return the new redirect uri and set the `code` and `state` in the query', function() { + it('should return the new redirect uri and set the `code` and `state` in the query', function () { const responseType = new CodeResponseType('foo'); const redirectUri = responseType.buildRedirectUri('http://example.com/cb'); url.format(redirectUri).should.equal('http://example.com/cb?code=foo'); }); - it('should return the new redirect uri and append the `code` and `state` in the query', function() { + it('should return the new redirect uri and append the `code` and `state` in the query', function () { const responseType = new CodeResponseType('foo'); const redirectUri = responseType.buildRedirectUri('http://example.com/cb?foo=bar'); diff --git a/test/integration/response_test.js b/test/integration/response_test.js index d6c37e43..7b074b97 100644 --- a/test/integration/response_test.js +++ b/test/integration/response_test.js @@ -10,43 +10,49 @@ const Response = require('../../lib/response'); * Test `Response` integration. */ -describe('Response integration', function() { - describe('constructor()', function() { - it('should set the `body`', function() { +describe('Response integration', function () { + describe('constructor()', function () { + it('should set the `body`', function () { const response = new Response({ body: 'foo', headers: {} }); response.body.should.equal('foo'); }); - it('should set the `headers`', function() { - const response = new Response({ body: {}, headers: { foo: 'bar', QuX: 'biz' } }); + it('should set the `headers`', function () { + const response = new Response({ + body: {}, + headers: { foo: 'bar', QuX: 'biz' } + }); response.headers.should.eql({ foo: 'bar', qux: 'biz' }); }); - it('should set the `status` to 200', function() { + it('should set the `status` to 200', function () { const response = new Response({ body: {}, headers: {} }); response.status.should.equal(200); }); }); - describe('get()', function() { - it('should return `undefined` if the field does not exist', function() { + describe('get()', function () { + it('should return `undefined` if the field does not exist', function () { const response = new Response({ body: {}, headers: {} }); (undefined === response.get('content-type')).should.be.true; }); - it('should return the value if the field exists', function() { - const response = new Response({ body: {}, headers: { 'content-type': 'text/html; charset=utf-8' } }); + it('should return the value if the field exists', function () { + const response = new Response({ + body: {}, + headers: { 'content-type': 'text/html; charset=utf-8' } + }); response.get('Content-Type').should.equal('text/html; charset=utf-8'); }); }); - describe('redirect()', function() { - it('should set the location header to `url`', function() { + describe('redirect()', function () { + it('should set the location header to `url`', function () { const response = new Response({ body: {}, headers: {} }); response.redirect('http://example.com'); @@ -54,7 +60,7 @@ describe('Response integration', function() { response.get('Location').should.equal('http://example.com'); }); - it('should set the `status` to 302', function() { + it('should set the `status` to 302', function () { const response = new Response({ body: {}, headers: {} }); response.redirect('http://example.com'); @@ -63,8 +69,8 @@ describe('Response integration', function() { }); }); - describe('set()', function() { - it('should set the `field`', function() { + describe('set()', function () { + it('should set the `field`', function () { const response = new Response({ body: {}, headers: {} }); response.set('foo', 'bar'); diff --git a/test/integration/server_test.js b/test/integration/server_test.js index f16aecce..c9360086 100644 --- a/test/integration/server_test.js +++ b/test/integration/server_test.js @@ -15,10 +15,10 @@ const should = require('chai').should(); * Test `Server` integration. */ -describe('Server integration', function() { - describe('constructor()', function() { - it('should throw an error if `model` is missing', function() { - [null, undefined, {}].forEach(options => { +describe('Server integration', function () { + describe('constructor()', function () { + it('should throw an error if `model` is missing', function () { + [null, undefined, {}].forEach((options) => { try { new Server(options); @@ -30,7 +30,7 @@ describe('Server integration', function() { }); }); - it('should set the `model`', function() { + it('should set the `model`', function () { const model = Model.from({}); const server = new Server({ model: model }); @@ -38,10 +38,10 @@ describe('Server integration', function() { }); }); - describe('authenticate()', function() { - it('should set the default `options`', async function() { + describe('authenticate()', function () { + it('should set the default `options`', async function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) @@ -49,7 +49,12 @@ describe('Server integration', function() { } }); const server = new Server({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); try { @@ -62,9 +67,9 @@ describe('Server integration', function() { } }); - it('should return a promise', function() { + it('should return a promise', function () { const model = Model.from({ - getAccessToken: async function(token) { + getAccessToken: async function (token) { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) @@ -72,7 +77,12 @@ describe('Server integration', function() { } }); const server = new Server({ model: model }); - const request = new Request({ body: {}, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: {} }); + const request = new Request({ + body: {}, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: {} + }); const response = new Response({ body: {}, headers: {} }); const handler = server.authenticate(request, response); @@ -80,24 +90,36 @@ describe('Server integration', function() { }); }); - describe('authorize()', function() { - it('should set the default `options`', async function() { + describe('authorize()', function () { + it('should set the default `options`', async function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getClient: function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: function() { + saveAuthorizationCode: function () { return { authorizationCode: 123 }; } }); const server = new Server({ model: model }); - const request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code' + }, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: { state: 'foobar' } + }); const response = new Response({ body: {}, headers: {} }); try { @@ -109,23 +131,35 @@ describe('Server integration', function() { } }); - it('should return a promise', function() { + it('should return a promise', function () { const model = Model.from({ - getAccessToken: function() { + getAccessToken: function () { return { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }; }, - getClient: function() { - return { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + getClient: function () { + return { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; }, - saveAuthorizationCode: function() { + saveAuthorizationCode: function () { return { authorizationCode: 123 }; } }); const server = new Server({ model: model }); - const request = new Request({ body: { client_id: 1234, client_secret: 'secret', response_type: 'code' }, headers: { 'Authorization': 'Bearer foo' }, method: {}, query: { state: 'foobar' } }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + response_type: 'code' + }, + headers: { Authorization: 'Bearer foo' }, + method: {}, + query: { state: 'foobar' } + }); const response = new Response({ body: {}, headers: {} }); const handler = server.authorize(request, response); @@ -133,22 +167,39 @@ describe('Server integration', function() { }); }); - describe('token()', function() { - it('should set the default `options`', async function() { + describe('token()', function () { + it('should set the default `options`', async function () { const model = Model.from({ - getClient: function() { + getClient: function () { return { grants: ['password'] }; }, - getUser: function() { + getUser: function () { return {}; }, - saveToken: function() { + saveToken: function () { return { accessToken: 1234, client: {}, user: {} }; }, - validateScope: function() { return ['foo']; } + validateScope: function () { + return ['foo']; + } }); const server = new Server({ model: model }); - const request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass', scope: 'foo' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass', + scope: 'foo' + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, + method: 'POST', + query: {} + }); const response = new Response({ body: {}, headers: {} }); try { @@ -160,20 +211,34 @@ describe('Server integration', function() { } }); - it('should return a promise', function() { + it('should return a promise', function () { const model = Model.from({ - getClient: function() { + getClient: function () { return { grants: ['password'] }; }, - getUser: function() { + getUser: function () { return {}; }, - saveToken: function() { + saveToken: function () { return { accessToken: 1234, client: {}, user: {} }; } }); const server = new Server({ model: model }); - const request = new Request({ body: { client_id: 1234, client_secret: 'secret', grant_type: 'password', username: 'foo', password: 'pass' }, headers: { 'content-type': 'application/x-www-form-urlencoded', 'transfer-encoding': 'chunked' }, method: 'POST', query: {} }); + const request = new Request({ + body: { + client_id: 1234, + client_secret: 'secret', + grant_type: 'password', + username: 'foo', + password: 'pass' + }, + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'transfer-encoding': 'chunked' + }, + method: 'POST', + query: {} + }); const response = new Response({ body: {}, headers: {} }); const handler = server.token(request, response); diff --git a/test/integration/token-types/bearer-token-type_test.js b/test/integration/token-types/bearer-token-type_test.js index 47b1daa6..68d95879 100644 --- a/test/integration/token-types/bearer-token-type_test.js +++ b/test/integration/token-types/bearer-token-type_test.js @@ -12,9 +12,9 @@ const should = require('chai').should(); * Test `BearerTokenType` integration. */ -describe('BearerTokenType integration', function() { - describe('constructor()', function() { - it('should throw an error if `accessToken` is missing', function() { +describe('BearerTokenType integration', function () { + describe('constructor()', function () { + it('should throw an error if `accessToken` is missing', function () { try { new BearerTokenType(); @@ -25,27 +25,27 @@ describe('BearerTokenType integration', function() { } }); - it('should set the `accessToken`', function() { + it('should set the `accessToken`', function () { const responseType = new BearerTokenType('foo', 'bar'); responseType.accessToken.should.equal('foo'); }); - it('should set the `accessTokenLifetime`', function() { + it('should set the `accessTokenLifetime`', function () { const responseType = new BearerTokenType('foo', 'bar'); responseType.accessTokenLifetime.should.equal('bar'); }); - it('should set the `refreshToken`', function() { + it('should set the `refreshToken`', function () { const responseType = new BearerTokenType('foo', 'bar', 'biz'); responseType.refreshToken.should.equal('biz'); }); }); - describe('valueOf()', function() { - it('should return the value representation', function() { + describe('valueOf()', function () { + it('should return the value representation', function () { const responseType = new BearerTokenType('foo', 'bar'); const value = responseType.valueOf(); @@ -56,7 +56,7 @@ describe('BearerTokenType integration', function() { }); }); - it('should not include the `expires_in` if not given', function() { + it('should not include the `expires_in` if not given', function () { const responseType = new BearerTokenType('foo'); const value = responseType.valueOf(); @@ -66,7 +66,7 @@ describe('BearerTokenType integration', function() { }); }); - it('should set `refresh_token` if `refreshToken` is defined', function() { + it('should set `refresh_token` if `refreshToken` is defined', function () { const responseType = new BearerTokenType('foo', 'bar', 'biz'); const value = responseType.valueOf(); @@ -78,7 +78,7 @@ describe('BearerTokenType integration', function() { }); }); - it('should set `expires_in` if `accessTokenLifetime` is defined', function() { + it('should set `expires_in` if `accessTokenLifetime` is defined', function () { const responseType = new BearerTokenType('foo', 'bar', 'biz'); const value = responseType.valueOf(); diff --git a/test/integration/utils/token-util_test.js b/test/integration/utils/token-util_test.js index edf9c7e9..c3e119ea 100644 --- a/test/integration/utils/token-util_test.js +++ b/test/integration/utils/token-util_test.js @@ -10,9 +10,9 @@ const TokenUtil = require('../../../lib/utils/token-util'); * Test `TokenUtil` integration. */ -describe('TokenUtil integration', function() { - describe('generateRandomToken()', function() { - it('should return a sha-256 token', async function() { +describe('TokenUtil integration', function () { + describe('generateRandomToken()', function () { + it('should return a sha-256 token', async function () { const token = await TokenUtil.generateRandomToken(); token.should.be.a.sha256(); }); diff --git a/test/unit/errors/oauth-error_test.js b/test/unit/errors/oauth-error_test.js index 6d68a299..1939793d 100644 --- a/test/unit/errors/oauth-error_test.js +++ b/test/unit/errors/oauth-error_test.js @@ -12,18 +12,18 @@ const OAuthError = require('../../../lib/errors/oauth-error'); * Test `OAuthError`. */ -describe('OAuthError', function() { - describe('constructor()', function() { - it('should get `captureStackTrace`', function() { - - const errorFn = function () { throw new OAuthError('test', {name: 'test_error', foo: 'bar'}); }; +describe('OAuthError', function () { + describe('constructor()', function () { + it('should get `captureStackTrace`', function () { + const errorFn = function () { + throw new OAuthError('test', { name: 'test_error', foo: 'bar' }); + }; try { errorFn(); should.fail(); } catch (e) { - e.should.be.an.instanceOf(OAuthError); e.name.should.equal('test_error'); e.foo.should.equal('bar'); @@ -37,14 +37,15 @@ describe('OAuthError', function() { }); }); it('supports undefined properties', function () { - const errorFn = function () { throw new OAuthError('test'); }; + const errorFn = function () { + throw new OAuthError('test'); + }; try { errorFn(); should.fail(); } catch (e) { - e.should.be.an.instanceOf(OAuthError); e.name.should.equal('Error'); e.message.should.equal('test'); @@ -52,7 +53,7 @@ describe('OAuthError', function() { e.stack.should.not.be.null; e.stack.should.not.be.undefined; e.stack.should.include('oauth-error_test.js'); - e.stack.should.include('40'); //error lineNUmber + e.stack.should.include('41'); //error lineNUmber } }); }); diff --git a/test/unit/grant-types/abstract-grant-type_test.js b/test/unit/grant-types/abstract-grant-type_test.js index 236574ce..0a1eb0c7 100644 --- a/test/unit/grant-types/abstract-grant-type_test.js +++ b/test/unit/grant-types/abstract-grant-type_test.js @@ -13,16 +13,20 @@ const should = require('chai').should(); * Test `AbstractGrantType`. */ -describe('AbstractGrantType', function() { - describe('generateAccessToken()', function() { - it('should call `model.generateAccessToken()`', function() { +describe('AbstractGrantType', function () { + describe('generateAccessToken()', function () { + it('should call `model.generateAccessToken()`', function () { const model = Model.from({ generateAccessToken: sinon.stub().returns({ client: {}, expiresAt: new Date(), user: {} }) }); - const handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 120, + model: model + }); - return handler.generateAccessToken() - .then(function() { + return handler + .generateAccessToken() + .then(function () { model.generateAccessToken.callCount.should.equal(1); model.generateAccessToken.firstCall.thisValue.should.equal(model); }) @@ -30,15 +34,23 @@ describe('AbstractGrantType', function() { }); }); - describe('generateRefreshToken()', function() { - it('should call `model.generateRefreshToken()`', function() { + describe('generateRefreshToken()', function () { + it('should call `model.generateRefreshToken()`', function () { const model = Model.from({ - generateRefreshToken: sinon.stub().returns({ client: {}, expiresAt: new Date(new Date() / 2), user: {} }) + generateRefreshToken: sinon.stub().returns({ + client: {}, + expiresAt: new Date(new Date() / 2), + user: {} + }) + }); + const handler = new AbstractGrantType({ + accessTokenLifetime: 120, + model: model }); - const handler = new AbstractGrantType({ accessTokenLifetime: 120, model: model }); - return handler.generateRefreshToken() - .then(function() { + return handler + .generateRefreshToken() + .then(function () { model.generateRefreshToken.callCount.should.equal(1); model.generateRefreshToken.firstCall.thisValue.should.equal(model); }) diff --git a/test/unit/grant-types/authorization-code-grant-type_test.js b/test/unit/grant-types/authorization-code-grant-type_test.js index 5650f83b..089419a2 100644 --- a/test/unit/grant-types/authorization-code-grant-type_test.js +++ b/test/unit/grant-types/authorization-code-grant-type_test.js @@ -16,20 +16,34 @@ const crypto = require('crypto'); * Test `AuthorizationCodeGrantType`. */ -describe('AuthorizationCodeGrantType', function() { - describe('getAuthorizationCode()', function() { - it('should call `model.getAuthorizationCode()`', function() { +describe('AuthorizationCodeGrantType', function () { + describe('getAuthorizationCode()', function () { + it('should call `model.getAuthorizationCode()`', function () { const model = Model.from({ - getAuthorizationCode: sinon.stub().returns({ authorizationCode: 12345, client: {}, expiresAt: new Date(new Date() * 2), user: {} }), - revokeAuthorizationCode: function() {}, - saveToken: function() {} + getAuthorizationCode: sinon.stub().returns({ + authorizationCode: 12345, + client: {}, + expiresAt: new Date(new Date() * 2), + user: {} + }), + revokeAuthorizationCode: function () {}, + saveToken: function () {} + }); + const handler = new AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: { code: 12345 }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: { code: 12345 }, headers: {}, method: {}, query: {} }); const client = {}; - return handler.getAuthorizationCode(request, client) - .then(function() { + return handler + .getAuthorizationCode(request, client) + .then(function () { model.getAuthorizationCode.callCount.should.equal(1); model.getAuthorizationCode.firstCall.args.should.have.length(1); model.getAuthorizationCode.firstCall.args[0].should.equal(12345); @@ -39,18 +53,22 @@ describe('AuthorizationCodeGrantType', function() { }); }); - describe('revokeAuthorizationCode()', function() { - it('should call `model.revokeAuthorizationCode()`', function() { + describe('revokeAuthorizationCode()', function () { + it('should call `model.revokeAuthorizationCode()`', function () { const model = Model.from({ - getAuthorizationCode: function() {}, + getAuthorizationCode: function () {}, revokeAuthorizationCode: sinon.stub().returns(true), - saveToken: function() {} + saveToken: function () {} + }); + const handler = new AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model: model }); - const handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); const authorizationCode = {}; - return handler.revokeAuthorizationCode(authorizationCode) - .then(function() { + return handler + .revokeAuthorizationCode(authorizationCode) + .then(function () { model.revokeAuthorizationCode.callCount.should.equal(1); model.revokeAuthorizationCode.firstCall.args.should.have.length(1); model.revokeAuthorizationCode.firstCall.args[0].should.equal(authorizationCode); @@ -60,16 +78,19 @@ describe('AuthorizationCodeGrantType', function() { }); }); - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { + describe('saveToken()', function () { + it('should call `model.saveToken()`', function () { const client = {}; const user = {}; const model = Model.from({ - getAuthorizationCode: function() {}, - revokeAuthorizationCode: function() {}, + getAuthorizationCode: function () {}, + revokeAuthorizationCode: function () {}, saveToken: sinon.stub().returns(true) }); - const handler = new AuthorizationCodeGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new AuthorizationCodeGrantType({ + accessTokenLifetime: 120, + model: model + }); sinon.stub(handler, 'validateScope').returns(['foobiz']); sinon.stub(handler, 'generateAccessToken').returns(Promise.resolve('foo')); @@ -77,11 +98,19 @@ describe('AuthorizationCodeGrantType', function() { sinon.stub(handler, 'getAccessTokenExpiresAt').returns(Promise.resolve('biz')); sinon.stub(handler, 'getRefreshTokenExpiresAt').returns(Promise.resolve('baz')); - return handler.saveToken(user, client, 'foobar', ['foobiz']) - .then(function() { + return handler + .saveToken(user, client, 'foobar', ['foobiz']) + .then(function () { model.saveToken.callCount.should.equal(1); model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', authorizationCode: 'foobar', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: ['foobiz'] }); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + authorizationCode: 'foobar', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: ['foobiz'] + }); model.saveToken.firstCall.args[1].should.equal(client); model.saveToken.firstCall.args[2].should.equal(user); model.saveToken.firstCall.thisValue.should.equal(model); @@ -90,11 +119,11 @@ describe('AuthorizationCodeGrantType', function() { }); }); - describe('with PKCE', function() { + describe('with PKCE', function () { // xxx: the tests for `getAuthorizationCode` are removed, because PKCE is now validated // in the handle method to ensure token revocation is performed before PKCE validation. - it('should return an auth code when `code_verifier` is valid with S256 code challenge method', function() { + it('should return an auth code when `code_verifier` is valid with S256 code challenge method', function () { const codeVerifier = stringUtil.base64URLEncode(crypto.randomBytes(32)); const authorizationCode = { authorizationCode: 12345, @@ -106,21 +135,32 @@ describe('AuthorizationCodeGrantType', function() { }; const client = { id: 'foobar', isPublic: true }; const model = Model.from({ - getAuthorizationCode: function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} + getAuthorizationCode: function () { + return authorizationCode; + }, + revokeAuthorizationCode: function () {}, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345, code_verifier: codeVerifier }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345, code_verifier: codeVerifier }, headers: {}, method: {}, query: {} }); - return grantType.getAuthorizationCode(request, client) - .then(function(data) { + return grantType + .getAuthorizationCode(request, client) + .then(function (data) { data.should.equal(authorizationCode); }) .catch(should.fail); }); - it('should return an auth code when `code_verifier` is valid with plain code challenge method', function() { + it('should return an auth code when `code_verifier` is valid with plain code challenge method', function () { const codeVerifier = stringUtil.base64URLEncode(crypto.randomBytes(32)); const authorizationCode = { authorizationCode: 12345, @@ -132,15 +172,26 @@ describe('AuthorizationCodeGrantType', function() { }; const client = { id: 'foobar', isPublic: true }; const model = Model.from({ - getAuthorizationCode: function() { return authorizationCode; }, - revokeAuthorizationCode: function() {}, - saveToken: function() {} + getAuthorizationCode: function () { + return authorizationCode; + }, + revokeAuthorizationCode: function () {}, + saveToken: function () {} + }); + const grantType = new AuthorizationCodeGrantType({ + accessTokenLifetime: 123, + model: model + }); + const request = new Request({ + body: { code: 12345, code_verifier: codeVerifier }, + headers: {}, + method: {}, + query: {} }); - const grantType = new AuthorizationCodeGrantType({ accessTokenLifetime: 123, model: model }); - const request = new Request({ body: { code: 12345, code_verifier: codeVerifier }, headers: {}, method: {}, query: {} }); - return grantType.getAuthorizationCode(request, client) - .then(function(data) { + return grantType + .getAuthorizationCode(request, client) + .then(function (data) { data.should.equal(authorizationCode); }) .catch(should.fail); diff --git a/test/unit/grant-types/client-credentials-grant-type_test.js b/test/unit/grant-types/client-credentials-grant-type_test.js index 17d386cf..1939bfff 100644 --- a/test/unit/grant-types/client-credentials-grant-type_test.js +++ b/test/unit/grant-types/client-credentials-grant-type_test.js @@ -13,18 +13,22 @@ const should = require('chai').should(); * Test `ClientCredentialsGrantType`. */ -describe('ClientCredentialsGrantType', function() { - describe('getUserFromClient()', function() { - it('should call `model.getUserFromClient()`', function() { +describe('ClientCredentialsGrantType', function () { + describe('getUserFromClient()', function () { + it('should call `model.getUserFromClient()`', function () { const model = Model.from({ getUserFromClient: sinon.stub().returns(true), - saveToken: function() {} + saveToken: function () {} + }); + const handler = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model }); - const handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); const client = {}; - return handler.getUserFromClient(client) - .then(function() { + return handler + .getUserFromClient(client) + .then(function () { model.getUserFromClient.callCount.should.equal(1); model.getUserFromClient.firstCall.args.should.have.length(1); model.getUserFromClient.firstCall.args[0].should.equal(client); @@ -34,25 +38,33 @@ describe('ClientCredentialsGrantType', function() { }); }); - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { + describe('saveToken()', function () { + it('should call `model.saveToken()`', function () { const client = {}; const user = {}; const model = Model.from({ - getUserFromClient: function() {}, + getUserFromClient: function () {}, saveToken: sinon.stub().returns(true) }); - const handler = new ClientCredentialsGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new ClientCredentialsGrantType({ + accessTokenLifetime: 120, + model: model + }); sinon.stub(handler, 'validateScope').returns(['foobar']); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); - return handler.saveToken(user, client, ['foobar']) - .then(function() { + return handler + .saveToken(user, client, ['foobar']) + .then(function () { model.saveToken.callCount.should.equal(1); model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', accessTokenExpiresAt: 'biz', scope: ['foobar'] }); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + scope: ['foobar'] + }); model.saveToken.firstCall.args[1].should.equal(client); model.saveToken.firstCall.args[2].should.equal(user); model.saveToken.firstCall.thisValue.should.equal(model); diff --git a/test/unit/grant-types/password-grant-type_test.js b/test/unit/grant-types/password-grant-type_test.js index 398b2929..ad0f14c3 100644 --- a/test/unit/grant-types/password-grant-type_test.js +++ b/test/unit/grant-types/password-grant-type_test.js @@ -14,19 +14,28 @@ const should = require('chai').should(); * Test `PasswordGrantType`. */ -describe('PasswordGrantType', function() { - describe('getUser()', function() { - it('should call `model.getUser()`', function() { +describe('PasswordGrantType', function () { + describe('getUser()', function () { + it('should call `model.getUser()`', function () { const model = Model.from({ getUser: sinon.stub().returns(true), - saveToken: function() {} + saveToken: function () {} }); const client = { id: 'foobar' }; - const handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: { username: 'foo', password: 'bar' }, headers: {}, method: {}, query: {} }); + const handler = new PasswordGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: { username: 'foo', password: 'bar' }, + headers: {}, + method: {}, + query: {} + }); - return handler.getUser(request, client) - .then(function() { + return handler + .getUser(request, client) + .then(function () { model.getUser.callCount.should.equal(1); model.getUser.firstCall.args.should.have.length(3); model.getUser.firstCall.args[0].should.equal('foo'); @@ -37,15 +46,18 @@ describe('PasswordGrantType', function() { }); }); - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { + describe('saveToken()', function () { + it('should call `model.saveToken()`', function () { const client = {}; const user = {}; const model = Model.from({ - getUser: function() {}, + getUser: function () {}, saveToken: sinon.stub().returns(true) }); - const handler = new PasswordGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new PasswordGrantType({ + accessTokenLifetime: 120, + model: model + }); sinon.stub(handler, 'validateScope').returns(['foobar']); sinon.stub(handler, 'generateAccessToken').returns('foo'); @@ -53,11 +65,18 @@ describe('PasswordGrantType', function() { sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - return handler.saveToken(user, client, ['foobar']) - .then(function() { + return handler + .saveToken(user, client, ['foobar']) + .then(function () { model.saveToken.callCount.should.equal(1); model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: ['foobar'] }); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: ['foobar'] + }); model.saveToken.firstCall.args[1].should.equal(client); model.saveToken.firstCall.args[2].should.equal(user); model.saveToken.firstCall.thisValue.should.equal(model); diff --git a/test/unit/grant-types/refresh-token-grant-type_test.js b/test/unit/grant-types/refresh-token-grant-type_test.js index ed0c9e2a..2f5b0ad9 100644 --- a/test/unit/grant-types/refresh-token-grant-type_test.js +++ b/test/unit/grant-types/refresh-token-grant-type_test.js @@ -14,21 +14,39 @@ const should = require('chai').should(); * Test `RefreshTokenGrantType`. */ -describe('RefreshTokenGrantType', function() { - describe('handle()', function() { - it('should revoke the previous token', function() { +describe('RefreshTokenGrantType', function () { + describe('handle()', function () { + it('should revoke the previous token', function () { const token = { accessToken: 'foo', client: {}, user: {} }; const model = Model.from({ - getRefreshToken: function() { return token; }, - saveToken: function() { return { accessToken: 'bar', client: {}, user: {} }; }, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }) + getRefreshToken: function () { + return token; + }, + saveToken: function () { + return { accessToken: 'bar', client: {}, user: {} }; + }, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }) + }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: { refresh_token: 'bar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); const client = {}; - return handler.handle(request, client) - .then(function() { + return handler + .handle(request, client) + .then(function () { model.revokeToken.callCount.should.equal(1); model.revokeToken.firstCall.args.should.have.length(1); model.revokeToken.firstCall.args[0].should.equal(token); @@ -38,19 +56,28 @@ describe('RefreshTokenGrantType', function() { }); }); - describe('getRefreshToken()', function() { - it('should call `model.getRefreshToken()`', function() { + describe('getRefreshToken()', function () { + it('should call `model.getRefreshToken()`', function () { const model = Model.from({ getRefreshToken: sinon.stub().returns({ accessToken: 'foo', client: {}, user: {} }), - saveToken: function() {}, - revokeToken: function() {} + saveToken: function () {}, + revokeToken: function () {} + }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model + }); + const request = new Request({ + body: { refresh_token: 'bar' }, + headers: {}, + method: {}, + query: {} }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); - const request = new Request({ body: { refresh_token: 'bar' }, headers: {}, method: {}, query: {} }); const client = {}; - return handler.getRefreshToken(request, client) - .then(function() { + return handler + .getRefreshToken(request, client) + .then(function () { model.getRefreshToken.callCount.should.equal(1); model.getRefreshToken.firstCall.args.should.have.length(1); model.getRefreshToken.firstCall.args[0].should.equal('bar'); @@ -60,18 +87,27 @@ describe('RefreshTokenGrantType', function() { }); }); - describe('revokeToken()', function() { - it('should call `model.revokeToken()`', function() { + describe('revokeToken()', function () { + it('should call `model.revokeToken()`', function () { const model = Model.from({ - getRefreshToken: function() {}, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), - saveToken: function() {} + getRefreshToken: function () {}, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }), + saveToken: function () {} + }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); const token = {}; - return handler.revokeToken(token) - .then(function() { + return handler + .revokeToken(token) + .then(function () { model.revokeToken.callCount.should.equal(1); model.revokeToken.firstCall.args.should.have.length(1); model.revokeToken.firstCall.args[0].should.equal(token); @@ -80,33 +116,53 @@ describe('RefreshTokenGrantType', function() { .catch(should.fail); }); - it('should not call `model.revokeToken()`', function() { + it('should not call `model.revokeToken()`', function () { const model = Model.from({ - getRefreshToken: function() {}, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), - saveToken: function() {} + getRefreshToken: function () {}, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }), + saveToken: function () {} + }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model, + alwaysIssueNewRefreshToken: false }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); const token = {}; - return handler.revokeToken(token) - .then(function() { + return handler + .revokeToken(token) + .then(function () { model.revokeToken.callCount.should.equal(0); }) .catch(should.fail); }); - it('should not call `model.revokeToken()`', function() { + it('should not call `model.revokeToken()`', function () { const model = Model.from({ - getRefreshToken: function() {}, - revokeToken: sinon.stub().returns({ accessToken: 'foo', client: {}, refreshTokenExpiresAt: new Date(new Date() / 2), user: {} }), - saveToken: function() {} + getRefreshToken: function () {}, + revokeToken: sinon.stub().returns({ + accessToken: 'foo', + client: {}, + refreshTokenExpiresAt: new Date(new Date() / 2), + user: {} + }), + saveToken: function () {} + }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model, + alwaysIssueNewRefreshToken: true }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true }); const token = {}; - return handler.revokeToken(token) - .then(function() { + return handler + .revokeToken(token) + .then(function () { model.revokeToken.callCount.should.equal(1); model.revokeToken.firstCall.args.should.have.length(1); model.revokeToken.firstCall.args[0].should.equal(token); @@ -116,27 +172,37 @@ describe('RefreshTokenGrantType', function() { }); }); - describe('saveToken()', function() { - it('should call `model.saveToken()`', function() { + describe('saveToken()', function () { + it('should call `model.saveToken()`', function () { const client = {}; const user = {}; const model = Model.from({ - getRefreshToken: function() {}, - revokeToken: function() {}, + getRefreshToken: function () {}, + revokeToken: function () {}, saveToken: sinon.stub().returns(true) }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model + }); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'generateRefreshToken').returns('bar'); sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - return handler.saveToken(user, client, ['foobar']) - .then(function() { + return handler + .saveToken(user, client, ['foobar']) + .then(function () { model.saveToken.callCount.should.equal(1); model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: ['foobar'] }); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: ['foobar'] + }); model.saveToken.firstCall.args[1].should.equal(client); model.saveToken.firstCall.args[2].should.equal(user); model.saveToken.firstCall.thisValue.should.equal(model); @@ -144,26 +210,35 @@ describe('RefreshTokenGrantType', function() { .catch(should.fail); }); - it('should call `model.saveToken()` without refresh token', function() { + it('should call `model.saveToken()` without refresh token', function () { const client = {}; const user = {}; const model = Model.from({ - getRefreshToken: function() {}, - revokeToken: function() {}, + getRefreshToken: function () {}, + revokeToken: function () {}, saveToken: sinon.stub().returns(true) }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: false }); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model, + alwaysIssueNewRefreshToken: false + }); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'generateRefreshToken').returns('bar'); sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - return handler.saveToken(user, client, ['foobar']) - .then(function() { + return handler + .saveToken(user, client, ['foobar']) + .then(function () { model.saveToken.callCount.should.equal(1); model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', accessTokenExpiresAt: 'biz', scope: ['foobar'] }); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + scope: ['foobar'] + }); model.saveToken.firstCall.args[1].should.equal(client); model.saveToken.firstCall.args[2].should.equal(user); model.saveToken.firstCall.thisValue.should.equal(model); @@ -171,26 +246,37 @@ describe('RefreshTokenGrantType', function() { .catch(should.fail); }); - it('should call `model.saveToken()` with refresh token', function() { + it('should call `model.saveToken()` with refresh token', function () { const client = {}; const user = {}; const model = Model.from({ - getRefreshToken: function() {}, - revokeToken: function() {}, + getRefreshToken: function () {}, + revokeToken: function () {}, saveToken: sinon.stub().returns(true) }); - const handler = new RefreshTokenGrantType({ accessTokenLifetime: 120, model: model, alwaysIssueNewRefreshToken: true}); + const handler = new RefreshTokenGrantType({ + accessTokenLifetime: 120, + model: model, + alwaysIssueNewRefreshToken: true + }); sinon.stub(handler, 'generateAccessToken').returns('foo'); sinon.stub(handler, 'generateRefreshToken').returns('bar'); sinon.stub(handler, 'getAccessTokenExpiresAt').returns('biz'); sinon.stub(handler, 'getRefreshTokenExpiresAt').returns('baz'); - return handler.saveToken(user, client, ['foobar']) - .then(function() { + return handler + .saveToken(user, client, ['foobar']) + .then(function () { model.saveToken.callCount.should.equal(1); model.saveToken.firstCall.args.should.have.length(3); - model.saveToken.firstCall.args[0].should.eql({ accessToken: 'foo', accessTokenExpiresAt: 'biz', refreshToken: 'bar', refreshTokenExpiresAt: 'baz', scope: ['foobar'] }); + model.saveToken.firstCall.args[0].should.eql({ + accessToken: 'foo', + accessTokenExpiresAt: 'biz', + refreshToken: 'bar', + refreshTokenExpiresAt: 'baz', + scope: ['foobar'] + }); model.saveToken.firstCall.args[1].should.equal(client); model.saveToken.firstCall.args[2].should.equal(user); model.saveToken.firstCall.thisValue.should.equal(model); diff --git a/test/unit/handlers/authenticate-handler_test.js b/test/unit/handlers/authenticate-handler_test.js index e5384e01..fdb64251 100644 --- a/test/unit/handlers/authenticate-handler_test.js +++ b/test/unit/handlers/authenticate-handler_test.js @@ -16,20 +16,20 @@ const ServerError = require('../../../lib/errors/server-error'); * Test `AuthenticateHandler`. */ -describe('AuthenticateHandler', function() { - describe('getTokenFromRequest()', function() { - describe('with bearer token in the request authorization header', function() { +describe('AuthenticateHandler', function () { + describe('getTokenFromRequest()', function () { + describe('with bearer token in the request authorization header', function () { it('should throw an error if the token is malformed', () => { const handler = new AuthenticateHandler({ - model: { getAccessToken() {} }, + model: { getAccessToken() {} } }); const request = new Request({ body: {}, headers: { - Authorization: 'foo Bearer bar', + Authorization: 'foo Bearer bar' }, method: 'ANY', - query: {}, + query: {} }); try { @@ -38,19 +38,19 @@ describe('AuthenticateHandler', function() { should.fail('should.fail', ''); } catch (e) { e.should.be.an.instanceOf(InvalidRequestError); - e.message.should.equal( - 'Invalid request: malformed authorization header', - ); + e.message.should.equal('Invalid request: malformed authorization header'); } }); }); - describe('with bearer token in the request authorization header', function() { - it('should call `getTokenFromRequestHeader()`', function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('with bearer token in the request authorization header', function () { + it('should call `getTokenFromRequestHeader()`', function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: {}, - headers: { 'Authorization': 'Bearer foo' }, + headers: { Authorization: 'Bearer foo' }, method: {}, query: {} }); @@ -65,9 +65,11 @@ describe('AuthenticateHandler', function() { }); }); - describe('with bearer token in the request query', function() { - it('should call `getTokenFromRequestQuery()`', function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('with bearer token in the request query', function () { + it('should call `getTokenFromRequestQuery()`', function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: {}, headers: {}, @@ -85,9 +87,11 @@ describe('AuthenticateHandler', function() { }); }); - describe('with bearer token in the request body', function() { - it('should call `getTokenFromRequestBody()`', function() { - const handler = new AuthenticateHandler({ model: { getAccessToken: function() {} } }); + describe('with bearer token in the request body', function () { + it('should call `getTokenFromRequestBody()`', function () { + const handler = new AuthenticateHandler({ + model: { getAccessToken: function () {} } + }); const request = new Request({ body: { access_token: 'foo' }, headers: {}, @@ -106,15 +110,16 @@ describe('AuthenticateHandler', function() { }); }); - describe('getAccessToken()', function() { - it('should call `model.getAccessToken()`', function() { + describe('getAccessToken()', function () { + it('should call `model.getAccessToken()`', function () { const model = Model.from({ getAccessToken: sinon.stub().returns({ user: {} }) }); const handler = new AuthenticateHandler({ model: model }); - return handler.getAccessToken('foo') - .then(function() { + return handler + .getAccessToken('foo') + .then(function () { model.getAccessToken.callCount.should.equal(1); model.getAccessToken.firstCall.args.should.have.length(1); model.getAccessToken.firstCall.args[0].should.equal('foo'); @@ -124,10 +129,10 @@ describe('AuthenticateHandler', function() { }); }); - describe('validateAccessToken()', function() { - it('should fail if token has no valid `accessTokenExpiresAt` date', function() { + describe('validateAccessToken()', function () { + it('should fail if token has no valid `accessTokenExpiresAt` date', function () { const model = Model.from({ - getAccessToken: function() {} + getAccessToken: function () {} }); const handler = new AuthenticateHandler({ model: model }); @@ -136,17 +141,16 @@ describe('AuthenticateHandler', function() { handler.validateAccessToken({ user: {} }); - } - catch (err) { + } catch (err) { err.should.be.an.instanceOf(ServerError); failed = true; } failed.should.equal(true); }); - it('should succeed if token has valid `accessTokenExpiresAt` date', function() { + it('should succeed if token has valid `accessTokenExpiresAt` date', function () { const model = Model.from({ - getAccessToken: function() {} + getAccessToken: function () {} }); const handler = new AuthenticateHandler({ model: model }); try { @@ -154,23 +158,28 @@ describe('AuthenticateHandler', function() { user: {}, accessTokenExpiresAt: new Date(new Date().getTime() + 10000) }); - } - catch (err) { + } catch (err) { should.fail(); } }); }); - describe('verifyScope()', function() { - it('should call `model.getAccessToken()` if scope is defined', function() { + describe('verifyScope()', function () { + it('should call `model.getAccessToken()` if scope is defined', function () { const model = Model.from({ - getAccessToken: function() {}, + getAccessToken: function () {}, verifyScope: sinon.stub().returns(true) }); - const handler = new AuthenticateHandler({ addAcceptedScopesHeader: true, addAuthorizedScopesHeader: true, model: model, scope: 'bar' }); + const handler = new AuthenticateHandler({ + addAcceptedScopesHeader: true, + addAuthorizedScopesHeader: true, + model: model, + scope: 'bar' + }); - return handler.verifyScope(['foo']) - .then(function() { + return handler + .verifyScope(['foo']) + .then(function () { model.verifyScope.callCount.should.equal(1); model.verifyScope.firstCall.args.should.have.length(2); model.verifyScope.firstCall.args[0].should.eql(['foo'], ['bar']); diff --git a/test/unit/handlers/authorize-handler_test.js b/test/unit/handlers/authorize-handler_test.js index b539e480..fb4170db 100644 --- a/test/unit/handlers/authorize-handler_test.js +++ b/test/unit/handlers/authorize-handler_test.js @@ -15,19 +15,23 @@ const should = require('chai').should(); * Test `AuthorizeHandler`. */ -describe('AuthorizeHandler', function() { - describe('generateAuthorizationCode()', function() { - it('should call `model.generateAuthorizationCode()`', function() { +describe('AuthorizeHandler', function () { + describe('generateAuthorizationCode()', function () { + it('should call `model.generateAuthorizationCode()`', function () { const model = Model.from({ generateAuthorizationCode: sinon.stub().returns({}), - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - return handler.generateAuthorizationCode() - .then(function() { + return handler + .generateAuthorizationCode() + .then(function () { model.generateAuthorizationCode.callCount.should.equal(1); model.generateAuthorizationCode.firstCall.thisValue.should.equal(model); }) @@ -35,18 +39,30 @@ describe('AuthorizeHandler', function() { }); }); - describe('getClient()', function() { - it('should call `model.getClient()`', function() { + describe('getClient()', function () { + it('should call `model.getClient()`', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: sinon.stub().returns({ grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }), - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: sinon.stub().returns({ + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }), + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) - .then(function() { + return handler + .getClient(request) + .then(function () { model.getClient.callCount.should.equal(1); model.getClient.firstCall.args.should.have.length(2); model.getClient.firstCall.args[0].should.equal(12345); @@ -56,19 +72,31 @@ describe('AuthorizeHandler', function() { }); }); - describe('getUser()', function() { - it('should call `authenticateHandler.getUser()`', function() { - const authenticateHandler = { handle: sinon.stub().returns(Promise.resolve({})) }; + describe('getUser()', function () { + it('should call `authenticateHandler.getUser()`', function () { + const authenticateHandler = { + handle: sinon.stub().returns(Promise.resolve({})) + }; const model = Model.from({ - getClient: function() {}, - saveAuthorizationCode: function() {} + getClient: function () {}, + saveAuthorizationCode: function () {} + }); + const handler = new AuthorizeHandler({ + authenticateHandler: authenticateHandler, + authorizationCodeLifetime: 120, + model: model + }); + const request = new Request({ + body: {}, + headers: {}, + method: {}, + query: {} }); - const handler = new AuthorizeHandler({ authenticateHandler: authenticateHandler, authorizationCodeLifetime: 120, model: model }); - const request = new Request({ body: {}, headers: {}, method: {}, query: {} }); const response = new Response(); - return handler.getUser(request, response) - .then(function() { + return handler + .getUser(request, response) + .then(function () { authenticateHandler.handle.callCount.should.equal(1); authenticateHandler.handle.firstCall.args.should.have.length(2); authenticateHandler.handle.firstCall.args[0].should.equal(request); @@ -78,20 +106,29 @@ describe('AuthorizeHandler', function() { }); }); - describe('saveAuthorizationCode()', function() { - it('should call `model.saveAuthorizationCode()`', function() { + describe('saveAuthorizationCode()', function () { + it('should call `model.saveAuthorizationCode()`', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, + getAccessToken: function () {}, + getClient: function () {}, saveAuthorizationCode: sinon.stub().returns({}) }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model + }); - return handler.saveAuthorizationCode('foo', 'bar', ['qux'], 'biz', 'baz', 'boz') - .then(function() { + return handler + .saveAuthorizationCode('foo', 'bar', ['qux'], 'biz', 'baz', 'boz') + .then(function () { model.saveAuthorizationCode.callCount.should.equal(1); model.saveAuthorizationCode.firstCall.args.should.have.length(3); - model.saveAuthorizationCode.firstCall.args[0].should.eql({ authorizationCode: 'foo', expiresAt: 'bar', redirectUri: 'baz', scope: ['qux'] }); + model.saveAuthorizationCode.firstCall.args[0].should.eql({ + authorizationCode: 'foo', + expiresAt: 'bar', + redirectUri: 'baz', + scope: ['qux'] + }); model.saveAuthorizationCode.firstCall.args[1].should.equal('biz'); model.saveAuthorizationCode.firstCall.args[2].should.equal('boz'); model.saveAuthorizationCode.firstCall.thisValue.should.equal(model); @@ -99,19 +136,30 @@ describe('AuthorizeHandler', function() { .catch(should.fail); }); - it('should call `model.saveAuthorizationCode()` with code challenge', function() { + it('should call `model.saveAuthorizationCode()` with code challenge', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, + getAccessToken: function () {}, + getClient: function () {}, saveAuthorizationCode: sinon.stub().returns({}) }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model + }); - return handler.saveAuthorizationCode('foo', 'bar', ['qux'], 'biz', 'baz', 'boz', 'codeChallenge', 'codeChallengeMethod') - .then(function() { + return handler + .saveAuthorizationCode('foo', 'bar', ['qux'], 'biz', 'baz', 'boz', 'codeChallenge', 'codeChallengeMethod') + .then(function () { model.saveAuthorizationCode.callCount.should.equal(1); model.saveAuthorizationCode.firstCall.args.should.have.length(3); - model.saveAuthorizationCode.firstCall.args[0].should.eql({ authorizationCode: 'foo', expiresAt: 'bar', redirectUri: 'baz', scope: ['qux'], codeChallenge: 'codeChallenge', codeChallengeMethod: 'codeChallengeMethod' }); + model.saveAuthorizationCode.firstCall.args[0].should.eql({ + authorizationCode: 'foo', + expiresAt: 'bar', + redirectUri: 'baz', + scope: ['qux'], + codeChallenge: 'codeChallenge', + codeChallengeMethod: 'codeChallengeMethod' + }); model.saveAuthorizationCode.firstCall.args[1].should.equal('biz'); model.saveAuthorizationCode.firstCall.args[2].should.equal('boz'); model.saveAuthorizationCode.firstCall.thisValue.should.equal(model); @@ -120,21 +168,33 @@ describe('AuthorizeHandler', function() { }); }); - describe('validateRedirectUri()', function() { - it('should call `model.validateRedirectUri()`', function() { - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + describe('validateRedirectUri()', function () { + it('should call `model.validateRedirectUri()`', function () { + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const redirect_uri = 'http://example.com/cb/2'; const model = Model.from({ - getAccessToken: function() {}, + getAccessToken: function () {}, getClient: sinon.stub().returns(client), - saveAuthorizationCode: function() {}, + saveAuthorizationCode: function () {}, validateRedirectUri: sinon.stub().returns(true) }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret', redirect_uri }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret', redirect_uri }, + headers: {}, + method: {}, + query: {} + }); - return handler.getClient(request) - .then(function() { + return handler + .getClient(request) + .then(function () { model.getClient.callCount.should.equal(1); model.getClient.firstCall.args.should.have.length(2); model.getClient.firstCall.args[0].should.equal(12345); @@ -150,42 +210,64 @@ describe('AuthorizeHandler', function() { }); it('should be successful validation', function () { - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const redirect_uri = 'http://example.com/cb'; const model = Model.from({ - getAccessToken: function() {}, + getAccessToken: function () {}, getClient: sinon.stub().returns(client), - saveAuthorizationCode: function() {}, + saveAuthorizationCode: function () {}, validateRedirectUri: function (redirectUri, client) { return client.redirectUris.includes(redirectUri); } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret', redirect_uri }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret', redirect_uri }, + headers: {}, + method: {}, + query: {} + }); - return handler.getClient(request) - .then((client) => { - client.should.equal(client); - }); + return handler.getClient(request).then((client) => { + client.should.equal(client); + }); }); it('should be unsuccessful validation', function () { - const client = { grants: ['authorization_code'], redirectUris: ['http://example.com/cb'] }; + const client = { + grants: ['authorization_code'], + redirectUris: ['http://example.com/cb'] + }; const redirect_uri = 'http://example.com/callback'; const model = Model.from({ - getAccessToken: function() {}, + getAccessToken: function () {}, getClient: sinon.stub().returns(client), - saveAuthorizationCode: function() {}, + saveAuthorizationCode: function () {}, validateRedirectUri: function (redirectUri, client) { return client.redirectUris.includes(redirectUri); } }); - const handler = new AuthorizeHandler({ authorizationCodeLifetime: 120, model: model }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret', redirect_uri }, headers: {}, method: {}, query: {} }); + const handler = new AuthorizeHandler({ + authorizationCodeLifetime: 120, + model: model + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret', redirect_uri }, + headers: {}, + method: {}, + query: {} + }); - return handler.getClient(request) + return handler + .getClient(request) .then(() => { throw Error('should not resolve'); }) diff --git a/test/unit/handlers/token-handler_test.js b/test/unit/handlers/token-handler_test.js index a16be32d..bf092824 100644 --- a/test/unit/handlers/token-handler_test.js +++ b/test/unit/handlers/token-handler_test.js @@ -14,18 +14,28 @@ const should = require('chai').should(); * Test `TokenHandler`. */ -describe('TokenHandler', function() { - describe('getClient()', function() { - it('should call `model.getClient()`', function() { +describe('TokenHandler', function () { + describe('getClient()', function () { + it('should call `model.getClient()`', function () { const model = Model.from({ getClient: sinon.stub().returns({ grants: ['password'] }), - saveToken: function() {} + saveToken: function () {} + }); + const handler = new TokenHandler({ + accessTokenLifetime: 120, + model: model, + refreshTokenLifetime: 120 + }); + const request = new Request({ + body: { client_id: 12345, client_secret: 'secret' }, + headers: {}, + method: {}, + query: {} }); - const handler = new TokenHandler({ accessTokenLifetime: 120, model: model, refreshTokenLifetime: 120 }); - const request = new Request({ body: { client_id: 12345, client_secret: 'secret' }, headers: {}, method: {}, query: {} }); - return handler.getClient(request) - .then(function() { + return handler + .getClient(request) + .then(function () { model.getClient.callCount.should.equal(1); model.getClient.firstCall.args.should.have.length(2); model.getClient.firstCall.args[0].should.equal(12345); diff --git a/test/unit/models/model_wrapper_test.js b/test/unit/models/model_wrapper_test.js index 75b8ebb4..147c2215 100644 --- a/test/unit/models/model_wrapper_test.js +++ b/test/unit/models/model_wrapper_test.js @@ -1,5 +1,5 @@ const Model = require('../../../lib/model'); -const {expect} = require('chai'); +const { expect } = require('chai'); describe('ModelWrapper', () => { const expectThrows = async (fn) => { @@ -28,6 +28,5 @@ describe('ModelWrapper', () => { await expectThrows(() => m.verifyScope()); await expectThrows(() => m.validateRedirectUri()); await expectThrows(() => m.validateScope()); - }); -}); \ No newline at end of file +}); diff --git a/test/unit/models/token-model_test.js b/test/unit/models/token-model_test.js index 338a7f9d..bd8b6dfb 100644 --- a/test/unit/models/token-model_test.js +++ b/test/unit/models/token-model_test.js @@ -5,8 +5,8 @@ const should = require('chai').should(); * Test `Server`. */ -describe('TokenModel', function() { - describe('constructor()', function() { +describe('TokenModel', function () { + describe('constructor()', function () { it('throws, if data is empty', function () { try { new TokenModel(); @@ -102,17 +102,17 @@ describe('TokenModel', function() { e.message.should.equal('Invalid parameter: `refreshTokenExpiresAt`'); } }); - it('should calculate `accessTokenLifetime` if `accessTokenExpiresAt` is set', function() { + it('should calculate `accessTokenLifetime` if `accessTokenExpiresAt` is set', function () { const atExpiresAt = new Date(); atExpiresAt.setHours(new Date().getHours() + 1); - + const data = { accessToken: 'foo', client: 'bar', user: 'tar', accessTokenExpiresAt: atExpiresAt }; - + const model = new TokenModel(data); should.exist(model.accessTokenLifetime); model.accessTokenLifetime.should.a('number'); @@ -138,14 +138,17 @@ describe('TokenModel', function() { }); it('should set custom attributes on the customAttributes field if allowExtendedTokenAttributes is specified as true', () => { - const model = new TokenModel({ - accessToken: 'token', - client: 'client', - user: 'user', - myCustomAttribute: 'myCustomValue' - }, { - allowExtendedTokenAttributes: true - }); + const model = new TokenModel( + { + accessToken: 'token', + client: 'client', + user: 'user', + myCustomAttribute: 'myCustomValue' + }, + { + allowExtendedTokenAttributes: true + } + ); should.not.exist(model['myCustomAttribute']); model['customAttributes'].should.be.an('object'); diff --git a/test/unit/pkce/pkce_test.js b/test/unit/pkce/pkce_test.js index 363eb8db..cb945294 100644 --- a/test/unit/pkce/pkce_test.js +++ b/test/unit/pkce/pkce_test.js @@ -9,7 +9,7 @@ const should = require('chai').should(); const { base64URLEncode } = require('../../../lib/utils/string-util'); const { createHash } = require('../../../lib/utils/crypto-util'); -describe('PKCE', function() { +describe('PKCE', function () { describe(pkce.isPKCERequest.name, function () { it('returns, whether parameters define a PKCE request', function () { [ @@ -21,11 +21,14 @@ describe('PKCE', function() { [false, '', '123123123123123123123123123123123123123123123'], [false, undefined, '123123123123123123123123123123123123123123123'], [false, 'foo_code', 'bar'] - ].forEach(triple => { - should.equal(triple[0], pkce.isPKCERequest({ - grantType: triple[1], - codeVerifier: triple[2] - })); + ].forEach((triple) => { + should.equal( + triple[0], + pkce.isPKCERequest({ + grantType: triple[1], + codeVerifier: triple[2] + }) + ); }); }); }); @@ -37,10 +40,13 @@ describe('PKCE', function() { [false, ''], [false, '123123123112312312311231231231123123123112'], // too short [false, '123123123112312312311231231231123123123112+'], // invalid chars - [false, '123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123'], // too long + [ + false, + '123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123112312312311231231231123123123' + ], // too long // invalid chars - [true, '-_.~abcdefghijklmnopqrstuvwxyz0123456789ABCDEFHIJKLMNOPQRSTUVWXYZ'], - ].forEach(pair => { + [true, '-_.~abcdefghijklmnopqrstuvwxyz0123456789ABCDEFHIJKLMNOPQRSTUVWXYZ'] + ].forEach((pair) => { should.equal(pair[0], pkce.codeChallengeMatchesABNF(pair[1])); }); }); @@ -53,12 +59,15 @@ describe('PKCE', function() { [undefined, undefined, verifier], [undefined, null, verifier], [undefined, '', verifier], - [undefined, 'foo', verifier], - ].forEach(triple => { - should.equal(triple[0], pkce.getHashForCodeChallenge({ - method: triple[1], - verifier: triple[2], - })); + [undefined, 'foo', verifier] + ].forEach((triple) => { + should.equal( + triple[0], + pkce.getHashForCodeChallenge({ + method: triple[1], + verifier: triple[2] + }) + ); }); }); it('return the verifier on plain and undefined on S256 if verifier is falsy', function () { @@ -68,12 +77,15 @@ describe('PKCE', function() { [undefined, 'plain', ''], [undefined, 'S256', ''], [undefined, 'plain', null], - [undefined, 'S256', null], - ].forEach(triple => { - should.equal(triple[0], pkce.getHashForCodeChallenge({ - method: triple[1], - verifier: triple[2], - })); + [undefined, 'S256', null] + ].forEach((triple) => { + should.equal( + triple[0], + pkce.getHashForCodeChallenge({ + method: triple[1], + verifier: triple[2] + }) + ); }); }); it('returns the unhashed verifier when method is plain', function () { diff --git a/test/unit/request_test.js b/test/unit/request_test.js index ee5a2761..9b646ea5 100644 --- a/test/unit/request_test.js +++ b/test/unit/request_test.js @@ -27,14 +27,14 @@ function generateBaseRequest() { }; } -describe('Request', function() { +describe('Request', function () { it('should throw on missing args', function () { const args = [ [undefined, InvalidArgumentError, 'Missing parameter: `headers`'], - [null, TypeError, 'Cannot destructure property \'headers\''], + [null, TypeError, "Cannot destructure property 'headers'"], [{}, InvalidArgumentError, 'Missing parameter: `headers`'], - [{ headers: { }}, InvalidArgumentError, 'Missing parameter: `method`'], - [{ headers: {}, method: 'GET' }, InvalidArgumentError, 'Missing parameter: `query`'], + [{ headers: {} }, InvalidArgumentError, 'Missing parameter: `method`'], + [{ headers: {}, method: 'GET' }, InvalidArgumentError, 'Missing parameter: `query`'] ]; args.forEach(([value, error, message]) => { @@ -46,7 +46,7 @@ describe('Request', function() { } }); }); - it('should instantiate with a basic request', function() { + it('should instantiate with a basic request', function () { const originalRequest = generateBaseRequest(); const request = new Request(originalRequest); @@ -56,7 +56,7 @@ describe('Request', function() { request.body.should.eql(originalRequest.body); }); - it('should allow a request to be passed without a body', function() { + it('should allow a request to be passed without a body', function () { const originalRequest = generateBaseRequest(); delete originalRequest.body; @@ -67,34 +67,34 @@ describe('Request', function() { request.body.should.eql({}); }); - it('should throw if headers are not passed to the constructor', function() { + it('should throw if headers are not passed to the constructor', function () { const originalRequest = generateBaseRequest(); delete originalRequest.headers; - (function() { + (function () { new Request(originalRequest); }).should.throw('Missing parameter: `headers`'); }); - it('should throw if query string isn\'t passed to the constructor', function() { + it("should throw if query string isn't passed to the constructor", function () { const originalRequest = generateBaseRequest(); delete originalRequest.query; - (function() { + (function () { new Request(originalRequest); }).should.throw('Missing parameter: `query`'); }); - it('should throw if method isn\'t passed to the constructor', function() { + it("should throw if method isn't passed to the constructor", function () { const originalRequest = generateBaseRequest(); delete originalRequest.method; - (function() { + (function () { new Request(originalRequest); }).should.throw('Missing parameter: `method`'); }); - it('should convert all header keys to lowercase', function() { + it('should convert all header keys to lowercase', function () { const originalRequest = generateBaseRequest(); originalRequest.headers = { Foo: 'bar', @@ -108,7 +108,7 @@ describe('Request', function() { should.not.exist(request.headers.BAR); }); - it('should include additional properties passed in the request', function() { + it('should include additional properties passed in the request', function () { const originalRequest = generateBaseRequest(); originalRequest.custom = { newFoo: 'newBar' @@ -127,7 +127,7 @@ describe('Request', function() { request.custom2.should.eql(originalRequest.custom2); }); - it('should include additional properties passed in the request', function() { + it('should include additional properties passed in the request', function () { const originalRequest = generateBaseRequest(); originalRequest.custom = { newFoo: 'newBar' @@ -162,28 +162,28 @@ describe('Request', function() { request.get('content-type').should.equal('application/json'); }); - it('should allow getting of headers using `request.get`', function() { + it('should allow getting of headers using `request.get`', function () { const originalRequest = generateBaseRequest(); const request = new Request(originalRequest); request.get('bar').should.eql(originalRequest.headers.bar); }); - it('should allow getting of headers using `request.get`', function() { + it('should allow getting of headers using `request.get`', function () { const originalRequest = generateBaseRequest(); const request = new Request(originalRequest); request.get('bar').should.eql(originalRequest.headers.bar); }); - it('should allow getting of headers using `request.get`', function() { + it('should allow getting of headers using `request.get`', function () { const originalRequest = generateBaseRequest(); const request = new Request(originalRequest); request.get('bar').should.eql(originalRequest.headers.bar); }); - it('should validate the content-type', function() { + it('should validate the content-type', function () { const originalRequest = generateBaseRequest(); originalRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; @@ -192,7 +192,7 @@ describe('Request', function() { request.is('application/x-www-form-urlencoded').should.eql('application/x-www-form-urlencoded'); }); - it('should return false if the content-type is invalid', function() { + it('should return false if the content-type is invalid', function () { const originalRequest = generateBaseRequest(); originalRequest.headers['content-type'] = 'application/x-www-form-urlencoded'; originalRequest.headers['content-length'] = JSON.stringify(originalRequest.body).length; diff --git a/test/unit/response_test.js b/test/unit/response_test.js index af505ba9..9ad751f8 100644 --- a/test/unit/response_test.js +++ b/test/unit/response_test.js @@ -22,8 +22,8 @@ function generateBaseResponse() { }; } -describe('Request', function() { - it('should instantiate with a basic request', function() { +describe('Request', function () { + it('should instantiate with a basic request', function () { const originalResponse = generateBaseResponse(); const response = new Response(originalResponse); @@ -32,7 +32,7 @@ describe('Request', function() { response.status.should.eql(200); }); - it('should allow a response to be passed without a body', function() { + it('should allow a response to be passed without a body', function () { const originalResponse = generateBaseResponse(); delete originalResponse.body; @@ -42,7 +42,7 @@ describe('Request', function() { response.status.should.eql(200); }); - it('should allow a response to be passed without headers', function() { + it('should allow a response to be passed without headers', function () { const originalResponse = generateBaseResponse(); delete originalResponse.headers; @@ -52,7 +52,7 @@ describe('Request', function() { response.status.should.eql(200); }); - it('should convert all header keys to lowercase', function() { + it('should convert all header keys to lowercase', function () { const originalResponse = generateBaseResponse(); originalResponse.headers = { Foo: 'bar', @@ -66,7 +66,7 @@ describe('Request', function() { should.not.exist(response.headers.BAR); }); - it('should include additional properties passed in the response', function() { + it('should include additional properties passed in the response', function () { const originalResponse = generateBaseResponse(); originalResponse.custom = { newFoo: 'newBar' @@ -97,21 +97,21 @@ describe('Request', function() { response.get('content-type').should.equal('application/json'); }); - it('should allow getting of headers using `response.get`', function() { + it('should allow getting of headers using `response.get`', function () { const originalResponse = generateBaseResponse(); const response = new Response(originalResponse); response.get('bar').should.eql(originalResponse.headers.bar); }); - it('should allow getting of headers using `response.get`', function() { + it('should allow getting of headers using `response.get`', function () { const originalResponse = generateBaseResponse(); const response = new Response(originalResponse); response.get('bar').should.eql(originalResponse.headers.bar); }); - it('should allow setting of headers using `response.set`', function() { + it('should allow setting of headers using `response.set`', function () { const originalResponse = generateBaseResponse(); const response = new Response(originalResponse); @@ -121,7 +121,7 @@ describe('Request', function() { response.headers.newheader.should.eql('newvalue'); }); - it('should process redirect', function() { + it('should process redirect', function () { const originalResponse = generateBaseResponse(); const response = new Response(originalResponse); diff --git a/test/unit/server_test.js b/test/unit/server_test.js index f8caa2bc..704e4407 100644 --- a/test/unit/server_test.js +++ b/test/unit/server_test.js @@ -15,11 +15,11 @@ const sinon = require('sinon'); * Test `Server`. */ -describe('Server', function() { - describe('authenticate()', function() { - it('should call `handle`', function() { +describe('Server', function () { + describe('authenticate()', function () { + it('should call `handle`', function () { const model = Model.from({ - getAccessToken: function() {} + getAccessToken: function () {} }); const server = new Server({ model: model }); @@ -33,12 +33,12 @@ describe('Server', function() { }); }); - describe('authorize()', function() { - it('should call `handle`', function() { + describe('authorize()', function () { + it('should call `handle`', function () { const model = Model.from({ - getAccessToken: function() {}, - getClient: function() {}, - saveAuthorizationCode: function() {} + getAccessToken: function () {}, + getClient: function () {}, + saveAuthorizationCode: function () {} }); const server = new Server({ model: model }); @@ -52,11 +52,11 @@ describe('Server', function() { }); }); - describe('token()', function() { - it('should call `handle`', function() { + describe('token()', function () { + it('should call `handle`', function () { const model = Model.from({ - getClient: function() {}, - saveToken: function() {} + getClient: function () {}, + saveToken: function () {} }); const server = new Server({ model: model }); diff --git a/test/unit/utils/crypto-util_test.js b/test/unit/utils/crypto-util_test.js index ff7c8444..b25edf2d 100644 --- a/test/unit/utils/crypto-util_test.js +++ b/test/unit/utils/crypto-util_test.js @@ -12,7 +12,9 @@ describe(cryptoUtil.createHash.name, function () { cryptoUtil.createHash({}); } catch (e) { e.should.be.instanceOf(TypeError); - e.message.should.include('he "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView.'); + e.message.should.include( + 'he "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView.' + ); } }); }); diff --git a/test/unit/utils/date-util__test.js b/test/unit/utils/date-util__test.js index 47b8e7d5..f05a204f 100644 --- a/test/unit/utils/date-util__test.js +++ b/test/unit/utils/date-util__test.js @@ -3,7 +3,7 @@ const dateUtil = require('../../../lib/utils/date-util'); const sinon = require('sinon'); require('chai').should(); -describe('DateUtil', function() { +describe('DateUtil', function () { describe('getLifetimeFromExpiresAt', () => { const now = new Date('2023-01-01T00:00:00.000Z'); diff --git a/test/unit/utils/scope-util_test.js b/test/unit/utils/scope-util_test.js index 505262f5..8309753f 100644 --- a/test/unit/utils/scope-util_test.js +++ b/test/unit/utils/scope-util_test.js @@ -4,14 +4,14 @@ const should = require('chai').should(); describe(parseScope.name, () => { it('should return undefined on nullish values', () => { const values = [undefined, null]; - values.forEach(str => { + values.forEach((str) => { const compare = parseScope(str) === undefined; compare.should.equal(true); }); }); it('should throw on non-string values', () => { const invalid = [1, -1, true, false, {}, ['foo'], [], () => {}, Symbol('foo')]; - invalid.forEach(str => { + invalid.forEach((str) => { try { parseScope(str); should.fail(); @@ -22,7 +22,7 @@ describe(parseScope.name, () => { }); it('should throw on empty strings', () => { const invalid = ['', ' ', ' ', '\n', '\t', '\r']; - invalid.forEach(str => { + invalid.forEach((str) => { try { parseScope(str); should.fail(); @@ -35,11 +35,11 @@ describe(parseScope.name, () => { const values = [ ['foo', ['foo']], ['foo bar', ['foo', 'bar']], - ['foo bar', ['foo', 'bar']], + ['foo bar', ['foo', 'bar']] ]; values.forEach(([str, compare]) => { const parsed = parseScope(str); parsed.should.deep.equal(compare); }); }); -}); \ No newline at end of file +});