From 999b2a897617880994376f1d488716537d101eff Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Wed, 5 Nov 2025 16:11:18 +0100 Subject: [PATCH 01/20] CLI: Implement `auth login` command --- cli/commands/auth/login.ts | 99 ++++++++++++++++++++++++++++++++++++++ cli/index.ts | 5 ++ cli/lib/appdata.ts | 4 ++ cli/lib/browser.ts | 53 ++++++++++++++++++++ common/lib/oauth.ts | 7 ++- common/logger-actions.ts | 5 ++ package-lock.json | 49 +------------------ package.json | 1 + 8 files changed, 174 insertions(+), 49 deletions(-) create mode 100644 cli/commands/auth/login.ts create mode 100644 cli/lib/browser.ts diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts new file mode 100644 index 0000000000..b80cb358bd --- /dev/null +++ b/cli/commands/auth/login.ts @@ -0,0 +1,99 @@ +import { password } from '@inquirer/prompts'; +import { __ } from '@wordpress/i18n'; +import { SupportedLocale } from 'common/lib/locale'; +import { getAuthenticationUrl } from 'common/lib/oauth'; +import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; +import wpcomFactory from 'src/lib/wpcom-factory'; +import wpcomXhrRequest from 'src/lib/wpcom-xhr-request-factory'; +import { z } from 'zod'; +import { validateAccessToken } from 'cli/lib/api'; +import { lockAppdata, readAppdata, saveAppdata, unlockAppdata } from 'cli/lib/appdata'; +import { openBrowser } from 'cli/lib/browser'; +import { Logger, LoggerError } from 'cli/logger'; +import { StudioArgv } from 'cli/types'; + +const meResponseSchema = z.object( { + ID: z.number(), + email: z.string().email(), + display_name: z.string(), +} ); + +const CLI_REDIRECT_URI = `https://developer.wordpress.com/copy-oauth-token`; + +export async function runCommand( locale: SupportedLocale = 'en' ): Promise< void > { + const logger = new Logger< LoggerAction >(); + + try { + const existingData = await readAppdata(); + if ( existingData.authToken?.accessToken ) { + await validateAccessToken( existingData.authToken.accessToken ); + logger.reportSuccess( __( 'Already authenticated with WordPress.com' ) ); + return; + } + + logger.reportStart( LoggerAction.LOGIN, __( 'Opening browser for authentication…' ) ); + + const authUrl = getAuthenticationUrl( locale, CLI_REDIRECT_URI ); + await openBrowser( authUrl ); + logger.reportSuccess( __( 'Browser opened successfully' ) ); + + console.log( __( 'Please complete authentication in your browser.' ) ); + console.log( '' ); + + const accessToken = await password( { + message: __( 'Authentication token:' ), + } ); + + logger.reportSuccess( __( 'Authentication completed successfully!' ) ); + + const wpcom = wpcomFactory( accessToken, wpcomXhrRequest ); + const rawResponse = await wpcom.req.get( '/me', { fields: 'ID,login,email,display_name' } ); + const user = meResponseSchema.parse( rawResponse ); + + const now = new Date(); + const twoWeeksInSeconds = 2 * 7 * 24 * 60 * 60; + + try { + await lockAppdata(); + const userData = await readAppdata(); + userData.authToken = { + accessToken, + id: user.ID, + email: user.email, + displayName: user.display_name, + expiresIn: twoWeeksInSeconds, + expirationTime: now.getTime() + twoWeeksInSeconds, + }; + await saveAppdata( userData ); + } finally { + await unlockAppdata(); + } + + logger.reportKeyValuePair( 'email', user.email ); + logger.reportKeyValuePair( 'display_name', user.display_name ); + } catch ( error ) { + if ( error instanceof LoggerError ) { + logger.reportError( error ); + } else { + logger.reportError( new LoggerError( __( 'Authentication failed' ), error ) ); + } + throw error; + } +} + +export const registerCommand = ( yargs: StudioArgv ) => { + return yargs.command( { + command: 'login', + describe: __( 'Log in to WordPress.com' ), + builder: ( yargs ) => { + return yargs.option( 'locale', { + type: 'string', + default: 'en', + description: __( 'Locale for the authentication flow' ), + } ); + }, + handler: async ( argv ) => { + await runCommand( argv.locale as SupportedLocale ); + }, + } ); +}; diff --git a/cli/index.ts b/cli/index.ts index 06a99308da..b24b0255e0 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,6 +1,7 @@ import 'cli/polyfills/browser-globals.js'; import path from 'node:path'; import { __ } from '@wordpress/i18n'; +import { registerCommand as registerAuthLoginCommand } from 'cli/commands/auth/login'; import { suppressPunycodeWarning } from 'common/lib/suppress-punycode-warning'; import { StatsGroup, StatsMetric } from 'common/types/stats'; import yargs from 'yargs'; @@ -45,6 +46,10 @@ async function main() { ); } } ) + .command( 'auth', __( 'Manage authentication' ), ( authYargs ) => { + registerAuthLoginCommand( authYargs ); + authYargs.demandCommand( 1, __( 'You must provide a valid auth command' ) ); + } ) .command( 'preview', __( 'Manage preview sites' ), ( previewYargs ) => { registerCreateCommand( previewYargs ); registerListCommand( previewYargs ); diff --git a/cli/lib/appdata.ts b/cli/lib/appdata.ts index 7fe8636052..262dd347de 100644 --- a/cli/lib/appdata.ts +++ b/cli/lib/appdata.ts @@ -46,7 +46,11 @@ const userDataSchema = z authToken: z .object( { accessToken: z.string().min( 1, __( 'Access token cannot be empty' ) ), + expiresIn: z.number(), + expirationTime: z.number(), id: z.number().optional(), + email: z.string(), + displayName: z.string().default( '' ), } ) .passthrough() .optional(), diff --git a/cli/lib/browser.ts b/cli/lib/browser.ts new file mode 100644 index 0000000000..23736316bb --- /dev/null +++ b/cli/lib/browser.ts @@ -0,0 +1,53 @@ +import { spawn } from 'child_process'; +import { __ } from '@wordpress/i18n'; +import { LoggerError } from 'cli/logger'; + +/** + * Opens the default browser with the specified URL + */ +export async function openBrowser( url: string ): Promise< void > { + const platform = process.platform; + let cmd: string; + let args: string[]; + + switch ( platform ) { + case 'darwin': + cmd = 'open'; + args = [ url ]; + break; + case 'win32': + cmd = 'PowerShell'; + args = [ + '-NoProfile', + '-NonInteractive', + '-ExecutionPolicy', + 'Bypass', + '-Command', + 'Start', + `"${ url }"`, + ]; + break; + case 'linux': + cmd = 'xdg-open'; + args = [ url ]; + break; + } + + return new Promise( ( resolve, reject ) => { + const child = spawn( cmd, args ); + + child.on( 'error', ( error ) => { + reject( + new LoggerError( __( 'Failed to open browser. Please open the URL manually.' ), error ) + ); + } ); + + child.on( 'exit', ( code ) => { + if ( code === 0 ) { + resolve(); + } else { + reject( new LoggerError( __( 'Failed to open browser. Please open the URL manually.' ) ) ); + } + } ); + } ); +} diff --git a/common/lib/oauth.ts b/common/lib/oauth.ts index 4a8dd92408..3407e99413 100644 --- a/common/lib/oauth.ts +++ b/common/lib/oauth.ts @@ -4,11 +4,14 @@ import { SupportedLocale } from 'common/lib/locale'; const SCOPES = 'global'; const REDIRECT_URI = `${ PROTOCOL_PREFIX }://auth`; -export function getAuthenticationUrl( locale: SupportedLocale ): string { +export function getAuthenticationUrl( + locale: SupportedLocale, + redirectUri = REDIRECT_URI +): string { const url = new URL( 'https://public-api.wordpress.com/oauth2/authorize' ); url.searchParams.set( 'response_type', 'token' ); url.searchParams.set( 'client_id', CLIENT_ID ); - url.searchParams.set( 'redirect_uri', REDIRECT_URI ); + url.searchParams.set( 'redirect_uri', redirectUri ); url.searchParams.set( 'scope', SCOPES ); url.searchParams.set( 'locale', locale ); diff --git a/common/logger-actions.ts b/common/logger-actions.ts index f447823a00..0e07a70fb3 100644 --- a/common/logger-actions.ts +++ b/common/logger-actions.ts @@ -1,6 +1,11 @@ // Store the actions in a separate file to avoid Webpack issues when importing them in the Studio // source code +export enum AuthCommandLoggerAction { + LOGIN = 'login', + LOGOUT = 'logout', +} + export enum PreviewCommandLoggerAction { VALIDATE = 'validate', ARCHIVE = 'archive', diff --git a/package-lock.json b/package-lock.json index a3437ff2a5..c88ca24c56 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@automattic/interpolate-components": "^1.2.1", "@formatjs/intl-locale": "^3.4.5", "@formatjs/intl-localematcher": "^0.5.4", + "@inquirer/prompts": "^7.9.0", "@php-wasm/node": "^3.0.18", "@php-wasm/scopes": "^3.0.18", "@php-wasm/universal": "^3.0.18", @@ -4847,9 +4848,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -4858,9 +4857,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/core": "^10.3.0", @@ -4884,9 +4881,7 @@ "version": "5.1.19", "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -4907,9 +4902,7 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/figures": "^1.0.14", @@ -4936,9 +4929,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">= 12" } @@ -4947,9 +4938,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "dev": true, "license": "ISC", - "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -4958,9 +4947,7 @@ "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", - "peer": true, "engines": { "node": ">=14" }, @@ -4972,9 +4959,7 @@ "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", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4986,9 +4971,7 @@ "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, "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5002,9 +4985,7 @@ "version": "4.2.21", "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/external-editor": "^1.0.2", @@ -5026,9 +5007,7 @@ "version": "4.0.21", "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9", @@ -5050,9 +5029,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "chardet": "^2.1.0", "iconv-lite": "^0.7.0" @@ -5073,17 +5050,13 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5099,7 +5072,6 @@ "version": "1.0.14", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -5109,9 +5081,7 @@ "version": "4.2.5", "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -5132,9 +5102,7 @@ "version": "3.0.21", "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -5155,9 +5123,7 @@ "version": "4.0.21", "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/core": "^10.3.0", @@ -5179,9 +5145,7 @@ "version": "7.9.0", "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/checkbox": "^4.3.0", "@inquirer/confirm": "^5.1.19", @@ -5210,9 +5174,7 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9", @@ -5234,9 +5196,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/figures": "^1.0.14", @@ -5259,9 +5219,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/core": "^10.3.0", @@ -5285,9 +5243,7 @@ "version": "3.0.9", "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", - "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -29210,7 +29166,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" diff --git a/package.json b/package.json index 164e32601a..281ee19801 100644 --- a/package.json +++ b/package.json @@ -119,6 +119,7 @@ "@automattic/interpolate-components": "^1.2.1", "@formatjs/intl-locale": "^3.4.5", "@formatjs/intl-localematcher": "^0.5.4", + "@inquirer/prompts": "^7.9.0", "@php-wasm/node": "^3.0.18", "@php-wasm/scopes": "^3.0.18", "@php-wasm/universal": "^3.0.18", From 8650b024a5f87e86a1e522fc0db806c7f8e5f614 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 08:45:16 +0100 Subject: [PATCH 02/20] Fix lint and tests --- cli/index.ts | 2 +- cli/lib/tests/appdata.test.ts | 4 ++++ cli/lib/tests/snapshots.test.ts | 19 ++++++++++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/cli/index.ts b/cli/index.ts index b24b0255e0..f9ebc6ef0b 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -1,10 +1,10 @@ import 'cli/polyfills/browser-globals.js'; import path from 'node:path'; import { __ } from '@wordpress/i18n'; -import { registerCommand as registerAuthLoginCommand } from 'cli/commands/auth/login'; import { suppressPunycodeWarning } from 'common/lib/suppress-punycode-warning'; import { StatsGroup, StatsMetric } from 'common/types/stats'; import yargs from 'yargs'; +import { registerCommand as registerAuthLoginCommand } from 'cli/commands/auth/login'; import { registerCommand as registerCreateCommand } from 'cli/commands/preview/create'; import { registerCommand as registerDeleteCommand } from 'cli/commands/preview/delete'; import { registerCommand as registerListCommand } from 'cli/commands/preview/list'; diff --git a/cli/lib/tests/appdata.test.ts b/cli/lib/tests/appdata.test.ts index 9b1c9e8ed9..5de265b48b 100644 --- a/cli/lib/tests/appdata.test.ts +++ b/cli/lib/tests/appdata.test.ts @@ -175,6 +175,10 @@ describe( 'Appdata Module', () => { it( 'should return auth token when it exists', async () => { const mockAuthToken = { accessToken: 'valid-token', + displayName: 'User Name', + email: 'user@example.com', + expirationTime: 0, + expiresIn: 3600, id: 123, }; diff --git a/cli/lib/tests/snapshots.test.ts b/cli/lib/tests/snapshots.test.ts index 3f45fa0917..b374f93c0b 100644 --- a/cli/lib/tests/snapshots.test.ts +++ b/cli/lib/tests/snapshots.test.ts @@ -35,6 +35,15 @@ jest.mock( 'cli/lib/api', () => ( { validateAccessToken: jest.fn().mockResolvedValue( undefined ), } ) ); +const mockAuthToken = Object.freeze( { + accessToken: 'mock-token', + displayName: 'User Name', + email: 'user@example.com', + expirationTime: 0, + expiresIn: 3600, + id: 123, +} ); + describe( 'Snapshots Module', () => { const mockHomeDir = '/mock/home'; const mockSiteFolderName = 'folder'; @@ -70,8 +79,8 @@ describe( 'Snapshots Module', () => { ], snapshots: [], authToken: { + ...mockAuthToken, id: mockUserId, - accessToken: 'mock-token', }, }; @@ -118,8 +127,8 @@ describe( 'Snapshots Module', () => { ], snapshots: [ existingSnapshot ], authToken: { + ...mockAuthToken, id: mockUserId, - accessToken: 'mock-token', }, }; @@ -156,8 +165,8 @@ describe( 'Snapshots Module', () => { ], snapshots: [], authToken: { + ...mockAuthToken, id: mockUserId, - accessToken: 'mock-token', }, }; @@ -222,8 +231,8 @@ describe( 'Snapshots Module', () => { newSites: [ existingNewSite ], snapshots: [], authToken: { + ...mockAuthToken, id: mockUserId, - accessToken: 'mock-token', }, }; @@ -291,8 +300,8 @@ describe( 'Snapshots Module', () => { sites: [], snapshots: [], authToken: { + ...mockAuthToken, id: mockUserId, - accessToken: 'mock-token', }, }; From fc661e032df008bb2db7a40d401a844995e31dbd Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 10:07:04 +0100 Subject: [PATCH 03/20] Add tests, tweak command --- cli/commands/auth/login.ts | 72 +++++------ cli/commands/auth/tests/login.test.ts | 178 ++++++++++++++++++++++++++ cli/index.ts | 2 +- cli/lib/api.ts | 20 +++ cli/lib/browser.ts | 10 +- 5 files changed, 234 insertions(+), 48 deletions(-) create mode 100644 cli/commands/auth/tests/login.test.ts diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index b80cb358bd..d17ee8e8ff 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -1,23 +1,14 @@ import { password } from '@inquirer/prompts'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { SupportedLocale } from 'common/lib/locale'; import { getAuthenticationUrl } from 'common/lib/oauth'; import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; -import wpcomFactory from 'src/lib/wpcom-factory'; -import wpcomXhrRequest from 'src/lib/wpcom-xhr-request-factory'; -import { z } from 'zod'; -import { validateAccessToken } from 'cli/lib/api'; +import { validateAccessToken, getUserInfo } from 'cli/lib/api'; import { lockAppdata, readAppdata, saveAppdata, unlockAppdata } from 'cli/lib/appdata'; import { openBrowser } from 'cli/lib/browser'; import { Logger, LoggerError } from 'cli/logger'; import { StudioArgv } from 'cli/types'; -const meResponseSchema = z.object( { - ID: z.number(), - email: z.string().email(), - display_name: z.string(), -} ); - const CLI_REDIRECT_URI = `https://developer.wordpress.com/copy-oauth-token`; export async function runCommand( locale: SupportedLocale = 'en' ): Promise< void > { @@ -25,37 +16,48 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi try { const existingData = await readAppdata(); + if ( existingData.authToken?.accessToken ) { - await validateAccessToken( existingData.authToken.accessToken ); - logger.reportSuccess( __( 'Already authenticated with WordPress.com' ) ); - return; + try { + await validateAccessToken( existingData.authToken.accessToken ); + logger.reportSuccess( __( 'Already authenticated with WordPress.com' ) ); + return; + } catch ( error ) { + // Assume the token is invalid and proceed with authentication + } } logger.reportStart( LoggerAction.LOGIN, __( 'Opening browser for authentication…' ) ); const authUrl = getAuthenticationUrl( locale, CLI_REDIRECT_URI ); - await openBrowser( authUrl ); - logger.reportSuccess( __( 'Browser opened successfully' ) ); + + try { + await openBrowser( authUrl ); + logger.reportSuccess( __( 'Browser opened successfully' ) ); + } catch ( error ) { + // If the browser fails to open, allow users to manually open the URL + const loggerError = new LoggerError( + sprintf( __( 'Failed to open browser. Please open the URL manually: %s' ), authUrl ), + error + ); + logger.reportError( loggerError ); + } console.log( __( 'Please complete authentication in your browser.' ) ); console.log( '' ); - const accessToken = await password( { - message: __( 'Authentication token:' ), - } ); + const accessToken = await password( { message: __( 'Authentication token:' ) } ); + const user = await getUserInfo( accessToken ); logger.reportSuccess( __( 'Authentication completed successfully!' ) ); - const wpcom = wpcomFactory( accessToken, wpcomXhrRequest ); - const rawResponse = await wpcom.req.get( '/me', { fields: 'ID,login,email,display_name' } ); - const user = meResponseSchema.parse( rawResponse ); - - const now = new Date(); - const twoWeeksInSeconds = 2 * 7 * 24 * 60 * 60; - try { await lockAppdata(); const userData = await readAppdata(); + + const now = new Date(); + const twoWeeksInSeconds = 2 * 7 * 24 * 60 * 60; + userData.authToken = { accessToken, id: user.ID, @@ -64,36 +66,26 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi expiresIn: twoWeeksInSeconds, expirationTime: now.getTime() + twoWeeksInSeconds, }; + await saveAppdata( userData ); } finally { await unlockAppdata(); } - - logger.reportKeyValuePair( 'email', user.email ); - logger.reportKeyValuePair( 'display_name', user.display_name ); } catch ( error ) { if ( error instanceof LoggerError ) { logger.reportError( error ); } else { logger.reportError( new LoggerError( __( 'Authentication failed' ), error ) ); } - throw error; } } -export const registerCommand = ( yargs: StudioArgv ) => { +export const registerCommand = ( yargs: StudioArgv, locale: SupportedLocale ) => { return yargs.command( { command: 'login', describe: __( 'Log in to WordPress.com' ), - builder: ( yargs ) => { - return yargs.option( 'locale', { - type: 'string', - default: 'en', - description: __( 'Locale for the authentication flow' ), - } ); - }, - handler: async ( argv ) => { - await runCommand( argv.locale as SupportedLocale ); + handler: async () => { + await runCommand( locale ); }, } ); }; diff --git a/cli/commands/auth/tests/login.test.ts b/cli/commands/auth/tests/login.test.ts new file mode 100644 index 0000000000..b9d69f8e18 --- /dev/null +++ b/cli/commands/auth/tests/login.test.ts @@ -0,0 +1,178 @@ +import { password } from '@inquirer/prompts'; +import { getAuthenticationUrl } from 'common/lib/oauth'; +import { validateAccessToken, getUserInfo } from 'cli/lib/api'; +import { lockAppdata, readAppdata, saveAppdata, unlockAppdata } from 'cli/lib/appdata'; +import { openBrowser } from 'cli/lib/browser'; +import { Logger, LoggerError } from 'cli/logger'; + +jest.mock( '@inquirer/prompts' ); +jest.mock( 'common/lib/oauth' ); +jest.mock( 'cli/lib/api' ); +jest.mock( 'cli/lib/appdata', () => ( { + ...jest.requireActual( 'cli/lib/appdata' ), + lockAppdata: jest.fn(), + readAppdata: jest.fn(), + saveAppdata: jest.fn(), + unlockAppdata: jest.fn(), +} ) ); +jest.mock( 'cli/lib/browser' ); +jest.mock( 'cli/logger' ); + +describe( 'Auth Login Command', () => { + const mockAccessToken = 'mock-access-token-12345'; + const mockAuthUrl = 'https://public-api.wordpress.com/oauth2/authorize?client_id=123'; + const mockUserData = { + ID: 12345, + email: 'test@example.com', + display_name: 'Test User', + }; + const mockAppdata = { + authToken: { + accessToken: 'existing-token', + id: 999, + email: 'existing@example.com', + displayName: 'Existing User', + expiresIn: 1209600, + expirationTime: Date.now() + 1209600000, + }, + }; + + let mockLogger: { + reportStart: jest.Mock; + reportSuccess: jest.Mock; + reportError: jest.Mock; + reportKeyValuePair: jest.Mock; + }; + + beforeEach( () => { + jest.clearAllMocks(); + + mockLogger = { + reportStart: jest.fn(), + reportSuccess: jest.fn(), + reportError: jest.fn(), + reportKeyValuePair: jest.fn(), + }; + + ( Logger as jest.Mock ).mockReturnValue( mockLogger ); + ( getAuthenticationUrl as jest.Mock ).mockReturnValue( mockAuthUrl ); + ( validateAccessToken as jest.Mock ).mockResolvedValue( undefined ); + ( getUserInfo as jest.Mock ).mockResolvedValue( mockUserData ); + ( openBrowser as jest.Mock ).mockResolvedValue( undefined ); + ( password as jest.Mock ).mockResolvedValue( mockAccessToken ); + ( readAppdata as jest.Mock ).mockResolvedValue( {} ); + ( lockAppdata as jest.Mock ).mockResolvedValue( undefined ); + ( unlockAppdata as jest.Mock ).mockResolvedValue( undefined ); + ( saveAppdata as jest.Mock ).mockResolvedValue( undefined ); + } ); + + afterEach( () => { + jest.restoreAllMocks(); + } ); + + it( 'should skip login if already authenticated', async () => { + ( readAppdata as jest.Mock ).mockResolvedValue( mockAppdata ); + + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( validateAccessToken ).toHaveBeenCalledWith( 'existing-token' ); + expect( openBrowser ).not.toHaveBeenCalled(); + expect( password ).not.toHaveBeenCalled(); + } ); + + it( 'should complete the login process successfully', async () => { + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( getAuthenticationUrl ).toHaveBeenCalledWith( + 'en', + 'https://developer.wordpress.com/copy-oauth-token' + ); + expect( openBrowser ).toHaveBeenCalledWith( mockAuthUrl ); + expect( password ).toHaveBeenCalledWith( { + message: 'Authentication token:', + } ); + expect( getUserInfo ).toHaveBeenCalledWith( mockAccessToken ); + expect( lockAppdata ).toHaveBeenCalled(); + expect( saveAppdata ).toHaveBeenCalledWith( { + authToken: { + accessToken: mockAccessToken, + id: mockUserData.ID, + email: mockUserData.email, + displayName: mockUserData.display_name, + expiresIn: expect.any( Number ), + expirationTime: expect.any( Number ), + }, + } ); + expect( unlockAppdata ).toHaveBeenCalled(); + } ); + + it( 'should proceed with login if existing token is invalid', async () => { + ( readAppdata as jest.Mock ).mockResolvedValue( mockAppdata ); + ( validateAccessToken as jest.Mock ).mockRejectedValue( new Error( 'Invalid token' ) ); + + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( validateAccessToken ).toHaveBeenCalledWith( 'existing-token' ); + expect( openBrowser ).toHaveBeenCalled(); + expect( password ).toHaveBeenCalled(); + } ); + + it( 'should handle browser open failure', async () => { + const browserError = new LoggerError( 'Failed to open browser' ); + ( openBrowser as jest.Mock ).mockRejectedValue( browserError ); + + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( password ).toHaveBeenCalled(); + } ); + + it( 'should handle API error when fetching user info', async () => { + const apiError = new LoggerError( 'Failed to fetch user info' ); + ( getUserInfo as jest.Mock ).mockRejectedValue( apiError ); + + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( mockLogger.reportError ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + expect( getUserInfo ).toHaveBeenCalled(); + } ); + + it( 'should unlock appdata even if save fails', async () => { + const saveError = new Error( 'Failed to save' ); + ( saveAppdata as jest.Mock ).mockRejectedValue( saveError ); + + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( mockLogger.reportError ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + expect( lockAppdata ).toHaveBeenCalled(); + expect( unlockAppdata ).toHaveBeenCalled(); + } ); + + it( 'should handle lock appdata failure', async () => { + const lockError = new Error( 'Failed to lock' ); + ( lockAppdata as jest.Mock ).mockRejectedValue( lockError ); + + const { runCommand } = await import( '../login' ); + await runCommand( 'en' ); + + expect( mockLogger.reportError ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + } ); + + it( 'should use provided locale', async () => { + const { runCommand } = await import( '../login' ); + await runCommand( 'fr' ); + + expect( getAuthenticationUrl ).toHaveBeenCalledWith( + 'fr', + 'https://developer.wordpress.com/copy-oauth-token' + ); + } ); +} ); diff --git a/cli/index.ts b/cli/index.ts index f9ebc6ef0b..1b2434e078 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -47,7 +47,7 @@ async function main() { } } ) .command( 'auth', __( 'Manage authentication' ), ( authYargs ) => { - registerAuthLoginCommand( authYargs ); + registerAuthLoginCommand( authYargs, locale ); authYargs.demandCommand( 1, __( 'You must provide a valid auth command' ) ); } ) .command( 'preview', __( 'Manage preview sites' ), ( previewYargs ) => { diff --git a/cli/lib/api.ts b/cli/lib/api.ts index 19c1fe57eb..827a540b3c 100644 --- a/cli/lib/api.ts +++ b/cli/lib/api.ts @@ -144,3 +144,23 @@ export async function validateAccessToken( token: string ): Promise< void > { throw new LoggerError( __( 'Invalid authentication token' ), error ); } } + +const userResponseSchema = z.object( { + ID: z.number(), + email: z.string().email(), + display_name: z.string(), +} ); + +export async function getUserInfo( + token: string +): Promise< z.infer< typeof userResponseSchema > > { + const wpcom = wpcomFactory( token, wpcomXhrRequest ); + try { + const rawResponse = await wpcom.req.get( '/me', { + fields: 'ID,login,email,display_name', + } ); + return userResponseSchema.parse( rawResponse ); + } catch ( error ) { + throw new LoggerError( __( 'Failed to fetch user info' ), error ); + } +} diff --git a/cli/lib/browser.ts b/cli/lib/browser.ts index 23736316bb..21fd755fbc 100644 --- a/cli/lib/browser.ts +++ b/cli/lib/browser.ts @@ -1,5 +1,5 @@ import { spawn } from 'child_process'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { LoggerError } from 'cli/logger'; /** @@ -36,17 +36,13 @@ export async function openBrowser( url: string ): Promise< void > { return new Promise( ( resolve, reject ) => { const child = spawn( cmd, args ); - child.on( 'error', ( error ) => { - reject( - new LoggerError( __( 'Failed to open browser. Please open the URL manually.' ), error ) - ); - } ); + child.on( 'error', reject ); child.on( 'exit', ( code ) => { if ( code === 0 ) { resolve(); } else { - reject( new LoggerError( __( 'Failed to open browser. Please open the URL manually.' ) ) ); + reject( new Error( 'Failed to open browser' ) ); } } ); } ); From c8b228c79fdb140be5f98df3ad4f939579da8a60 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 10:11:42 +0100 Subject: [PATCH 04/20] Consider expiration time --- cli/commands/auth/login.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index d17ee8e8ff..fd9f39479e 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -16,8 +16,9 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi try { const existingData = await readAppdata(); + const now = new Date().getTime(); - if ( existingData.authToken?.accessToken ) { + if ( existingData.authToken?.accessToken && now < existingData.authToken?.expirationTime ) { try { await validateAccessToken( existingData.authToken.accessToken ); logger.reportSuccess( __( 'Already authenticated with WordPress.com' ) ); From 9fcc45f37e09e911aa25ee855aaa1ea276d68728 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 10:40:12 +0100 Subject: [PATCH 05/20] Move logic around --- cli/commands/auth/login.ts | 29 ++++++++++++++------------- cli/commands/auth/tests/login.test.ts | 22 +++++++++++--------- cli/lib/appdata.ts | 2 +- cli/lib/tests/appdata.test.ts | 2 +- cli/lib/tests/snapshots.test.ts | 2 +- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index fd9f39479e..f102a85b48 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -3,8 +3,14 @@ import { __, sprintf } from '@wordpress/i18n'; import { SupportedLocale } from 'common/lib/locale'; import { getAuthenticationUrl } from 'common/lib/oauth'; import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; -import { validateAccessToken, getUserInfo } from 'cli/lib/api'; -import { lockAppdata, readAppdata, saveAppdata, unlockAppdata } from 'cli/lib/appdata'; +import { getUserInfo } from 'cli/lib/api'; +import { + getAuthToken, + lockAppdata, + readAppdata, + saveAppdata, + unlockAppdata, +} from 'cli/lib/appdata'; import { openBrowser } from 'cli/lib/browser'; import { Logger, LoggerError } from 'cli/logger'; import { StudioArgv } from 'cli/types'; @@ -15,19 +21,14 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi const logger = new Logger< LoggerAction >(); try { - const existingData = await readAppdata(); - const now = new Date().getTime(); - - if ( existingData.authToken?.accessToken && now < existingData.authToken?.expirationTime ) { - try { - await validateAccessToken( existingData.authToken.accessToken ); - logger.reportSuccess( __( 'Already authenticated with WordPress.com' ) ); - return; - } catch ( error ) { - // Assume the token is invalid and proceed with authentication - } - } + await getAuthToken(); + logger.reportSuccess( __( 'Already authenticated with WordPress.com' ) ); + return; + } catch ( error ) { + // Assume the token is invalid and proceed with authentication + } + try { logger.reportStart( LoggerAction.LOGIN, __( 'Opening browser for authentication…' ) ); const authUrl = getAuthenticationUrl( locale, CLI_REDIRECT_URI ); diff --git a/cli/commands/auth/tests/login.test.ts b/cli/commands/auth/tests/login.test.ts index b9d69f8e18..a7d188abed 100644 --- a/cli/commands/auth/tests/login.test.ts +++ b/cli/commands/auth/tests/login.test.ts @@ -1,7 +1,13 @@ import { password } from '@inquirer/prompts'; import { getAuthenticationUrl } from 'common/lib/oauth'; -import { validateAccessToken, getUserInfo } from 'cli/lib/api'; -import { lockAppdata, readAppdata, saveAppdata, unlockAppdata } from 'cli/lib/appdata'; +import { getUserInfo } from 'cli/lib/api'; +import { + getAuthToken, + lockAppdata, + readAppdata, + saveAppdata, + unlockAppdata, +} from 'cli/lib/appdata'; import { openBrowser } from 'cli/lib/browser'; import { Logger, LoggerError } from 'cli/logger'; @@ -14,6 +20,7 @@ jest.mock( 'cli/lib/appdata', () => ( { readAppdata: jest.fn(), saveAppdata: jest.fn(), unlockAppdata: jest.fn(), + getAuthToken: jest.fn(), } ) ); jest.mock( 'cli/lib/browser' ); jest.mock( 'cli/logger' ); @@ -56,11 +63,11 @@ describe( 'Auth Login Command', () => { ( Logger as jest.Mock ).mockReturnValue( mockLogger ); ( getAuthenticationUrl as jest.Mock ).mockReturnValue( mockAuthUrl ); - ( validateAccessToken as jest.Mock ).mockResolvedValue( undefined ); ( getUserInfo as jest.Mock ).mockResolvedValue( mockUserData ); ( openBrowser as jest.Mock ).mockResolvedValue( undefined ); ( password as jest.Mock ).mockResolvedValue( mockAccessToken ); - ( readAppdata as jest.Mock ).mockResolvedValue( {} ); + ( readAppdata as jest.Mock ).mockResolvedValue( mockAppdata ); + ( getAuthToken as jest.Mock ).mockRejectedValue( new Error( 'Mock error' ) ); ( lockAppdata as jest.Mock ).mockResolvedValue( undefined ); ( unlockAppdata as jest.Mock ).mockResolvedValue( undefined ); ( saveAppdata as jest.Mock ).mockResolvedValue( undefined ); @@ -71,12 +78,11 @@ describe( 'Auth Login Command', () => { } ); it( 'should skip login if already authenticated', async () => { - ( readAppdata as jest.Mock ).mockResolvedValue( mockAppdata ); + ( getAuthToken as jest.Mock ).mockResolvedValue( mockAppdata.authToken ); const { runCommand } = await import( '../login' ); await runCommand( 'en' ); - expect( validateAccessToken ).toHaveBeenCalledWith( 'existing-token' ); expect( openBrowser ).not.toHaveBeenCalled(); expect( password ).not.toHaveBeenCalled(); } ); @@ -109,13 +115,9 @@ describe( 'Auth Login Command', () => { } ); it( 'should proceed with login if existing token is invalid', async () => { - ( readAppdata as jest.Mock ).mockResolvedValue( mockAppdata ); - ( validateAccessToken as jest.Mock ).mockRejectedValue( new Error( 'Invalid token' ) ); - const { runCommand } = await import( '../login' ); await runCommand( 'en' ); - expect( validateAccessToken ).toHaveBeenCalledWith( 'existing-token' ); expect( openBrowser ).toHaveBeenCalled(); expect( password ).toHaveBeenCalled(); } ); diff --git a/cli/lib/appdata.ts b/cli/lib/appdata.ts index 262dd347de..2f284cc2a8 100644 --- a/cli/lib/appdata.ts +++ b/cli/lib/appdata.ts @@ -149,7 +149,7 @@ export async function getAuthToken(): Promise< ValidatedAuthToken > { try { const { authToken } = await readAppdata(); - if ( ! authToken?.accessToken || ! authToken?.id ) { + if ( ! authToken?.accessToken || ! authToken?.id || Date.now() >= authToken?.expirationTime ) { throw new Error( 'Authentication required' ); } diff --git a/cli/lib/tests/appdata.test.ts b/cli/lib/tests/appdata.test.ts index 5de265b48b..4ea3f08bf9 100644 --- a/cli/lib/tests/appdata.test.ts +++ b/cli/lib/tests/appdata.test.ts @@ -177,7 +177,7 @@ describe( 'Appdata Module', () => { accessToken: 'valid-token', displayName: 'User Name', email: 'user@example.com', - expirationTime: 0, + expirationTime: Date.now() + 3600000, // 1 hour in the future expiresIn: 3600, id: 123, }; diff --git a/cli/lib/tests/snapshots.test.ts b/cli/lib/tests/snapshots.test.ts index b374f93c0b..f80a07c700 100644 --- a/cli/lib/tests/snapshots.test.ts +++ b/cli/lib/tests/snapshots.test.ts @@ -39,7 +39,7 @@ const mockAuthToken = Object.freeze( { accessToken: 'mock-token', displayName: 'User Name', email: 'user@example.com', - expirationTime: 0, + expirationTime: Date.now() + 3600000, // 1 hour in the future expiresIn: 3600, id: 123, } ); From 36e6059955971de9836ec0a82bad01105fda77f8 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 10:54:08 +0100 Subject: [PATCH 06/20] Unwrap --- cli/commands/auth/login.ts | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index f102a85b48..75a966c8e9 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -28,26 +28,28 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi // Assume the token is invalid and proceed with authentication } - try { - logger.reportStart( LoggerAction.LOGIN, __( 'Opening browser for authentication…' ) ); + logger.reportStart( LoggerAction.LOGIN, __( 'Opening browser for authentication…' ) ); - const authUrl = getAuthenticationUrl( locale, CLI_REDIRECT_URI ); + const authUrl = getAuthenticationUrl( locale, CLI_REDIRECT_URI ); - try { - await openBrowser( authUrl ); - logger.reportSuccess( __( 'Browser opened successfully' ) ); - } catch ( error ) { - // If the browser fails to open, allow users to manually open the URL - const loggerError = new LoggerError( - sprintf( __( 'Failed to open browser. Please open the URL manually: %s' ), authUrl ), - error - ); - logger.reportError( loggerError ); - } + try { + await openBrowser( authUrl ); + logger.reportSuccess( __( 'Browser opened successfully' ) ); + } catch ( error ) { + // If the browser fails to open, allow users to manually open the URL + const loggerError = new LoggerError( + sprintf( __( 'Failed to open browser. Please open the URL manually: %s' ), authUrl ), + error + ); + logger.reportError( loggerError ); + } - console.log( __( 'Please complete authentication in your browser.' ) ); - console.log( '' ); + console.log( + __( 'Please complete authentication in your browser and paste the generated token here.' ) + ); + console.log( '' ); + try { const accessToken = await password( { message: __( 'Authentication token:' ) } ); const user = await getUserInfo( accessToken ); From a228ae9394c507e11adcbd3aea84b526afe644ea Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 11:20:12 +0100 Subject: [PATCH 07/20] Fix type error --- cli/commands/auth/login.ts | 11 ++++++----- cli/commands/auth/tests/login.test.ts | 21 +++++++++++++-------- cli/index.ts | 6 +++--- cli/lib/i18n.ts | 8 ++++++-- 4 files changed, 28 insertions(+), 18 deletions(-) diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index 75a966c8e9..bd0ee01b94 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -1,6 +1,5 @@ import { password } from '@inquirer/prompts'; import { __, sprintf } from '@wordpress/i18n'; -import { SupportedLocale } from 'common/lib/locale'; import { getAuthenticationUrl } from 'common/lib/oauth'; import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; import { getUserInfo } from 'cli/lib/api'; @@ -12,12 +11,13 @@ import { unlockAppdata, } from 'cli/lib/appdata'; import { openBrowser } from 'cli/lib/browser'; +import { getAppLocale } from 'cli/lib/i18n'; import { Logger, LoggerError } from 'cli/logger'; import { StudioArgv } from 'cli/types'; const CLI_REDIRECT_URI = `https://developer.wordpress.com/copy-oauth-token`; -export async function runCommand( locale: SupportedLocale = 'en' ): Promise< void > { +export async function runCommand(): Promise< void > { const logger = new Logger< LoggerAction >(); try { @@ -30,7 +30,8 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi logger.reportStart( LoggerAction.LOGIN, __( 'Opening browser for authentication…' ) ); - const authUrl = getAuthenticationUrl( locale, CLI_REDIRECT_URI ); + const appLocale = await getAppLocale(); + const authUrl = getAuthenticationUrl( appLocale, CLI_REDIRECT_URI ); try { await openBrowser( authUrl ); @@ -84,12 +85,12 @@ export async function runCommand( locale: SupportedLocale = 'en' ): Promise< voi } } -export const registerCommand = ( yargs: StudioArgv, locale: SupportedLocale ) => { +export const registerCommand = ( yargs: StudioArgv ) => { return yargs.command( { command: 'login', describe: __( 'Log in to WordPress.com' ), handler: async () => { - await runCommand( locale ); + await runCommand(); }, } ); }; diff --git a/cli/commands/auth/tests/login.test.ts b/cli/commands/auth/tests/login.test.ts index a7d188abed..02c397e59b 100644 --- a/cli/commands/auth/tests/login.test.ts +++ b/cli/commands/auth/tests/login.test.ts @@ -9,6 +9,7 @@ import { unlockAppdata, } from 'cli/lib/appdata'; import { openBrowser } from 'cli/lib/browser'; +import { getAppLocale } from 'cli/lib/i18n'; import { Logger, LoggerError } from 'cli/logger'; jest.mock( '@inquirer/prompts' ); @@ -23,6 +24,7 @@ jest.mock( 'cli/lib/appdata', () => ( { getAuthToken: jest.fn(), } ) ); jest.mock( 'cli/lib/browser' ); +jest.mock( 'cli/lib/i18n' ); jest.mock( 'cli/logger' ); describe( 'Auth Login Command', () => { @@ -63,6 +65,7 @@ describe( 'Auth Login Command', () => { ( Logger as jest.Mock ).mockReturnValue( mockLogger ); ( getAuthenticationUrl as jest.Mock ).mockReturnValue( mockAuthUrl ); + ( getAppLocale as jest.Mock ).mockResolvedValue( 'en' ); ( getUserInfo as jest.Mock ).mockResolvedValue( mockUserData ); ( openBrowser as jest.Mock ).mockResolvedValue( undefined ); ( password as jest.Mock ).mockResolvedValue( mockAccessToken ); @@ -81,7 +84,7 @@ describe( 'Auth Login Command', () => { ( getAuthToken as jest.Mock ).mockResolvedValue( mockAppdata.authToken ); const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( openBrowser ).not.toHaveBeenCalled(); expect( password ).not.toHaveBeenCalled(); @@ -89,7 +92,7 @@ describe( 'Auth Login Command', () => { it( 'should complete the login process successfully', async () => { const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( getAuthenticationUrl ).toHaveBeenCalledWith( 'en', @@ -116,7 +119,7 @@ describe( 'Auth Login Command', () => { it( 'should proceed with login if existing token is invalid', async () => { const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( openBrowser ).toHaveBeenCalled(); expect( password ).toHaveBeenCalled(); @@ -127,7 +130,7 @@ describe( 'Auth Login Command', () => { ( openBrowser as jest.Mock ).mockRejectedValue( browserError ); const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( password ).toHaveBeenCalled(); } ); @@ -137,7 +140,7 @@ describe( 'Auth Login Command', () => { ( getUserInfo as jest.Mock ).mockRejectedValue( apiError ); const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( mockLogger.reportError ).toHaveBeenCalled(); expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); @@ -149,7 +152,7 @@ describe( 'Auth Login Command', () => { ( saveAppdata as jest.Mock ).mockRejectedValue( saveError ); const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( mockLogger.reportError ).toHaveBeenCalled(); expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); @@ -162,15 +165,17 @@ describe( 'Auth Login Command', () => { ( lockAppdata as jest.Mock ).mockRejectedValue( lockError ); const { runCommand } = await import( '../login' ); - await runCommand( 'en' ); + await runCommand(); expect( mockLogger.reportError ).toHaveBeenCalled(); expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); } ); it( 'should use provided locale', async () => { + ( getAppLocale as jest.Mock ).mockResolvedValue( 'fr' ); + const { runCommand } = await import( '../login' ); - await runCommand( 'fr' ); + await runCommand(); expect( getAuthenticationUrl ).toHaveBeenCalledWith( 'fr', diff --git a/cli/index.ts b/cli/index.ts index 1b2434e078..159407dca2 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -19,12 +19,12 @@ import { StudioArgv } from 'cli/types'; suppressPunycodeWarning(); async function main() { - const locale = await loadTranslations(); + const yargsLocale = await loadTranslations(); const studioArgv: StudioArgv = yargs( process.argv.slice( 2 ) ) .scriptName( 'studio' ) .usage( __( 'WordPress Studio CLI' ) ) - .locale( locale ) + .locale( yargsLocale ) .version( version ) .option( 'avoid-telemetry', { type: 'boolean', @@ -47,7 +47,7 @@ async function main() { } } ) .command( 'auth', __( 'Manage authentication' ), ( authYargs ) => { - registerAuthLoginCommand( authYargs, locale ); + registerAuthLoginCommand( authYargs ); authYargs.demandCommand( 1, __( 'You must provide a valid auth command' ) ); } ) .command( 'preview', __( 'Manage preview sites' ), ( previewYargs ) => { diff --git a/cli/lib/i18n.ts b/cli/lib/i18n.ts index 12cde2db7d..e06896288a 100644 --- a/cli/lib/i18n.ts +++ b/cli/lib/i18n.ts @@ -37,10 +37,14 @@ function mapToYargsLocale( locale: SupportedLocale ): string { } } -export async function loadTranslations() { +export async function getAppLocale(): Promise< SupportedLocale > { const appdataLocale = await getLocaleFromAppdata(); const envLocale = getLocaleFromEnvironment(); - const locale = appdataLocale || envLocale || DEFAULT_LOCALE; + return appdataLocale || envLocale || DEFAULT_LOCALE; +} + +export async function loadTranslations() { + const locale = await getAppLocale(); const translations = getLocaleData( locale )?.messages; if ( translations ) { From b838c0cf8d4a2ae805fdef32975b8330a70c8d60 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 12:58:45 +0100 Subject: [PATCH 08/20] CLI: Implement `auth logout` command --- cli/commands/auth/logout.ts | 55 +++++++++++++ cli/commands/auth/tests/logout.test.ts | 109 +++++++++++++++++++++++++ cli/index.ts | 2 + cli/lib/api.ts | 13 +++ 4 files changed, 179 insertions(+) create mode 100644 cli/commands/auth/logout.ts create mode 100644 cli/commands/auth/tests/logout.test.ts diff --git a/cli/commands/auth/logout.ts b/cli/commands/auth/logout.ts new file mode 100644 index 0000000000..40a86ddb6d --- /dev/null +++ b/cli/commands/auth/logout.ts @@ -0,0 +1,55 @@ +import { __ } from '@wordpress/i18n'; +import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; +import { revokeAuthToken } from 'cli/lib/api'; +import { + readAppdata, + saveAppdata, + lockAppdata, + unlockAppdata, + getAuthToken, +} from 'cli/lib/appdata'; +import { Logger, LoggerError } from 'cli/logger'; +import { StudioArgv } from 'cli/types'; + +export async function runCommand(): Promise< void > { + const logger = new Logger< LoggerAction >(); + + logger.reportStart( LoggerAction.LOGOUT, __( 'Logging out…' ) ); + let token: Awaited< ReturnType< typeof getAuthToken > >; + + try { + token = await getAuthToken(); + } catch ( error ) { + logger.reportSuccess( __( 'Already logged out' ) ); + return; + } + + try { + await revokeAuthToken( token.accessToken ); + + await lockAppdata(); + const userData = await readAppdata(); + delete userData.authToken; + await saveAppdata( userData ); + + logger.reportSuccess( __( 'Successfully logged out' ) ); + } catch ( error ) { + if ( error instanceof LoggerError ) { + logger.reportError( error ); + } else { + logger.reportError( new LoggerError( __( 'Failed to log out' ), error ) ); + } + } finally { + await unlockAppdata(); + } +} + +export const registerCommand = ( yargs: StudioArgv ) => { + return yargs.command( { + command: 'logout', + describe: __( 'Log out and clear WordPress.com authentication' ), + handler: async () => { + await runCommand(); + }, + } ); +}; diff --git a/cli/commands/auth/tests/logout.test.ts b/cli/commands/auth/tests/logout.test.ts new file mode 100644 index 0000000000..5d7f71de92 --- /dev/null +++ b/cli/commands/auth/tests/logout.test.ts @@ -0,0 +1,109 @@ +import { revokeAuthToken } from 'cli/lib/api'; +import { + getAuthToken, + lockAppdata, + readAppdata, + saveAppdata, + unlockAppdata, +} from 'cli/lib/appdata'; +import { Logger, LoggerError } from 'cli/logger'; + +jest.mock( 'cli/lib/appdata' ); +jest.mock( 'cli/logger' ); +jest.mock( 'cli/lib/api' ); + +describe( 'Auth Logout Command', () => { + const mockAppdata = { + authToken: { + accessToken: 'existing-token', + id: 999, + email: 'existing@example.com', + displayName: 'Existing User', + expiresIn: 1209600, + expirationTime: Date.now() + 1209600000, + }, + }; + + let mockLogger: { + reportStart: jest.Mock; + reportSuccess: jest.Mock; + reportError: jest.Mock; + }; + + beforeEach( () => { + jest.clearAllMocks(); + + mockLogger = { + reportStart: jest.fn(), + reportSuccess: jest.fn(), + reportError: jest.fn(), + }; + + ( Logger as jest.Mock ).mockReturnValue( mockLogger ); + ( getAuthToken as jest.Mock ).mockResolvedValue( mockAppdata.authToken ); + ( revokeAuthToken as jest.Mock ).mockResolvedValue( undefined ); + ( lockAppdata as jest.Mock ).mockResolvedValue( undefined ); + ( unlockAppdata as jest.Mock ).mockResolvedValue( undefined ); + ( readAppdata as jest.Mock ).mockResolvedValue( JSON.parse( JSON.stringify( mockAppdata ) ) ); + ( saveAppdata as jest.Mock ).mockResolvedValue( undefined ); + } ); + + afterEach( () => { + jest.restoreAllMocks(); + } ); + + it( 'should complete the logout process successfully', async () => { + const { runCommand } = await import( '../logout' ); + await runCommand(); + + expect( getAuthToken ).toHaveBeenCalled(); + expect( revokeAuthToken ).toHaveBeenCalled(); + expect( lockAppdata ).toHaveBeenCalled(); + expect( readAppdata ).toHaveBeenCalled(); + expect( saveAppdata ).toHaveBeenCalledWith( {} ); + expect( unlockAppdata ).toHaveBeenCalled(); + expect( mockLogger.reportSuccess ).toHaveBeenCalledWith( 'Successfully logged out' ); + } ); + + it( 'should report an error if revoking the token fails', async () => { + ( revokeAuthToken as jest.Mock ).mockRejectedValue( new Error( 'Failed to revoke token' ) ); + + const { runCommand } = await import( '../logout' ); + await runCommand(); + + expect( getAuthToken ).toHaveBeenCalled(); + expect( lockAppdata ).not.toHaveBeenCalled(); + expect( readAppdata ).not.toHaveBeenCalled(); + expect( saveAppdata ).not.toHaveBeenCalledWith( {} ); + expect( unlockAppdata ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + } ); + + it( 'should report already logged out if no auth token exists', async () => { + ( getAuthToken as jest.Mock ).mockRejectedValue( new Error( 'No auth token' ) ); + + const { runCommand } = await import( '../logout' ); + await runCommand(); + + expect( getAuthToken ).toHaveBeenCalled(); + expect( revokeAuthToken ).not.toHaveBeenCalled(); + expect( lockAppdata ).not.toHaveBeenCalled(); + expect( readAppdata ).not.toHaveBeenCalled(); + expect( saveAppdata ).not.toHaveBeenCalled(); + expect( mockLogger.reportSuccess ).toHaveBeenCalledWith( 'Already logged out' ); + } ); + + it( 'should unlock appdata even if save fails', async () => { + ( saveAppdata as jest.Mock ).mockRejectedValue( new Error( 'Failed to save' ) ); + + const { runCommand } = await import( '../logout' ); + await runCommand(); + + expect( revokeAuthToken ).toHaveBeenCalled(); + expect( lockAppdata ).toHaveBeenCalled(); + expect( unlockAppdata ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + } ); +} ); diff --git a/cli/index.ts b/cli/index.ts index 159407dca2..f02605ea78 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -5,6 +5,7 @@ import { suppressPunycodeWarning } from 'common/lib/suppress-punycode-warning'; import { StatsGroup, StatsMetric } from 'common/types/stats'; import yargs from 'yargs'; import { registerCommand as registerAuthLoginCommand } from 'cli/commands/auth/login'; +import { registerCommand as registerAuthLogoutCommand } from 'cli/commands/auth/logout'; import { registerCommand as registerCreateCommand } from 'cli/commands/preview/create'; import { registerCommand as registerDeleteCommand } from 'cli/commands/preview/delete'; import { registerCommand as registerListCommand } from 'cli/commands/preview/list'; @@ -48,6 +49,7 @@ async function main() { } ) .command( 'auth', __( 'Manage authentication' ), ( authYargs ) => { registerAuthLoginCommand( authYargs ); + registerAuthLogoutCommand( authYargs ); authYargs.demandCommand( 1, __( 'You must provide a valid auth command' ) ); } ) .command( 'preview', __( 'Manage preview sites' ), ( previewYargs ) => { diff --git a/cli/lib/api.ts b/cli/lib/api.ts index 827a540b3c..ac709b1851 100644 --- a/cli/lib/api.ts +++ b/cli/lib/api.ts @@ -164,3 +164,16 @@ export async function getUserInfo( throw new LoggerError( __( 'Failed to fetch user info' ), error ); } } + +export async function revokeAuthToken( token: string ): Promise< void > { + const wpcom = wpcomFactory( token, wpcomXhrRequest ); + try { + await wpcom.req.del( { + apiNamespace: 'wpcom/v2', + path: '/studio-app/token', + method: 'DELETE', + } ); + } catch ( error ) { + throw new LoggerError( __( 'Failed to revoke token' ), error ); + } +} From 46343201b816a7a35cf5fda70311b2c01ddf5b9b Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 13:31:33 +0100 Subject: [PATCH 09/20] CLI: Implement `auth status` command --- cli/commands/auth/status.ts | 43 +++++++++++++ cli/commands/auth/tests/status.test.ts | 87 ++++++++++++++++++++++++++ cli/index.ts | 2 + cli/lib/api.ts | 3 +- common/logger-actions.ts | 1 + 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 cli/commands/auth/status.ts create mode 100644 cli/commands/auth/tests/status.test.ts diff --git a/cli/commands/auth/status.ts b/cli/commands/auth/status.ts new file mode 100644 index 0000000000..ea863c01c9 --- /dev/null +++ b/cli/commands/auth/status.ts @@ -0,0 +1,43 @@ +import { __, sprintf } from '@wordpress/i18n'; +import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; +import { getUserInfo } from 'cli/lib/api'; +import { getAuthToken } from 'cli/lib/appdata'; +import { Logger, LoggerError } from 'cli/logger'; +import { StudioArgv } from 'cli/types'; + +export async function runCommand(): Promise< void > { + const logger = new Logger< LoggerAction >(); + + logger.reportStart( LoggerAction.STATUS_CHECK, __( 'Checking authentication status…' ) ); + let token: Awaited< ReturnType< typeof getAuthToken > >; + + try { + token = await getAuthToken(); + } catch ( error ) { + logger.reportError( new LoggerError( __( 'Authentication token is invalid or expired' ) ) ); + return; + } + + try { + const userData = await getUserInfo( token.accessToken ); + logger.reportSuccess( + sprintf( __( 'Successfully authenticated with WordPress.com as `%s`' ), userData.username ) + ); + } catch ( error ) { + if ( error instanceof LoggerError ) { + logger.reportError( error ); + } else { + logger.reportError( new LoggerError( __( 'Failed to check authentication status' ), error ) ); + } + } +} + +export const registerCommand = ( yargs: StudioArgv ) => { + return yargs.command( { + command: 'status', + describe: __( 'Check authentication status' ), + handler: async () => { + await runCommand(); + }, + } ); +}; diff --git a/cli/commands/auth/tests/status.test.ts b/cli/commands/auth/tests/status.test.ts new file mode 100644 index 0000000000..9d2350e207 --- /dev/null +++ b/cli/commands/auth/tests/status.test.ts @@ -0,0 +1,87 @@ +import { getUserInfo } from 'cli/lib/api'; +import { getAuthToken } from 'cli/lib/appdata'; +import { Logger, LoggerError } from 'cli/logger'; + +jest.mock( 'cli/lib/api' ); +jest.mock( 'cli/lib/appdata' ); +jest.mock( 'cli/logger' ); + +describe( 'Auth Status Command', () => { + const mockToken = { + accessToken: 'existing-token', + id: 999, + email: 'existing@example.com', + displayName: 'Existing User', + expiresIn: 1209600, + expirationTime: Date.now() + 1209600000, + }; + const mockUserData = { + username: 'testuser', + }; + + let mockLogger: { + reportStart: jest.Mock; + reportSuccess: jest.Mock; + reportError: jest.Mock; + }; + + beforeEach( () => { + jest.clearAllMocks(); + + mockLogger = { + reportStart: jest.fn(), + reportSuccess: jest.fn(), + reportError: jest.fn(), + }; + + ( Logger as unknown as jest.Mock ).mockReturnValue( mockLogger ); + ( getAuthToken as jest.Mock ).mockResolvedValue( mockToken ); + ( getUserInfo as jest.Mock ).mockResolvedValue( mockUserData ); + } ); + + afterEach( () => { + jest.restoreAllMocks(); + } ); + + it( 'should report success when authenticated', async () => { + const { runCommand } = await import( '../status' ); + await runCommand(); + + expect( mockLogger.reportStart ).toHaveBeenCalled(); + expect( getAuthToken ).toHaveBeenCalled(); + expect( getUserInfo ).toHaveBeenCalledWith( mockToken.accessToken ); + expect( mockLogger.reportSuccess ).toHaveBeenCalledWith( + expect.stringContaining( 'Successfully authenticated with WordPress.com as `testuser`' ) + ); + } ); + + it( 'should report error when token is invalid', async () => { + ( getAuthToken as jest.Mock ).mockRejectedValue( new Error( 'Token error' ) ); + + const { runCommand } = await import( '../status' ); + await runCommand(); + + expect( mockLogger.reportError ).toHaveBeenCalled(); + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + expect( getUserInfo ).not.toHaveBeenCalled(); + } ); + + it( 'should forward LoggerError from getUserInfo', async () => { + const apiError = new LoggerError( 'API error' ); + ( getUserInfo as jest.Mock ).mockRejectedValue( apiError ); + + const { runCommand } = await import( '../status' ); + await runCommand(); + + expect( mockLogger.reportError ).toHaveBeenCalledWith( apiError ); + } ); + + it( 'should wrap unknown error when getUserInfo fails', async () => { + ( getUserInfo as jest.Mock ).mockRejectedValue( new Error( 'Unknown error' ) ); + + const { runCommand } = await import( '../status' ); + await runCommand(); + + expect( mockLogger.reportError ).toHaveBeenCalledWith( expect.any( LoggerError ) ); + } ); +} ); diff --git a/cli/index.ts b/cli/index.ts index f02605ea78..3fcf65f471 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -6,6 +6,7 @@ import { StatsGroup, StatsMetric } from 'common/types/stats'; import yargs from 'yargs'; import { registerCommand as registerAuthLoginCommand } from 'cli/commands/auth/login'; import { registerCommand as registerAuthLogoutCommand } from 'cli/commands/auth/logout'; +import { registerCommand as registerAuthStatusCommand } from 'cli/commands/auth/status'; import { registerCommand as registerCreateCommand } from 'cli/commands/preview/create'; import { registerCommand as registerDeleteCommand } from 'cli/commands/preview/delete'; import { registerCommand as registerListCommand } from 'cli/commands/preview/list'; @@ -50,6 +51,7 @@ async function main() { .command( 'auth', __( 'Manage authentication' ), ( authYargs ) => { registerAuthLoginCommand( authYargs ); registerAuthLogoutCommand( authYargs ); + registerAuthStatusCommand( authYargs ); authYargs.demandCommand( 1, __( 'You must provide a valid auth command' ) ); } ) .command( 'preview', __( 'Manage preview sites' ), ( previewYargs ) => { diff --git a/cli/lib/api.ts b/cli/lib/api.ts index ac709b1851..7c8956922a 100644 --- a/cli/lib/api.ts +++ b/cli/lib/api.ts @@ -149,6 +149,7 @@ const userResponseSchema = z.object( { ID: z.number(), email: z.string().email(), display_name: z.string(), + username: z.string(), } ); export async function getUserInfo( @@ -157,7 +158,7 @@ export async function getUserInfo( const wpcom = wpcomFactory( token, wpcomXhrRequest ); try { const rawResponse = await wpcom.req.get( '/me', { - fields: 'ID,login,email,display_name', + fields: 'ID,username,email,display_name', } ); return userResponseSchema.parse( rawResponse ); } catch ( error ) { diff --git a/common/logger-actions.ts b/common/logger-actions.ts index 0e07a70fb3..b847b7d1e2 100644 --- a/common/logger-actions.ts +++ b/common/logger-actions.ts @@ -4,6 +4,7 @@ export enum AuthCommandLoggerAction { LOGIN = 'login', LOGOUT = 'logout', + STATUS_CHECK = 'status_check', } export enum PreviewCommandLoggerAction { From c1799fe6f05c8d3d87c6664dd05b23daa29ec327 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 13:46:27 +0100 Subject: [PATCH 10/20] Address review comments --- cli/commands/auth/login.ts | 2 +- cli/lib/appdata.ts | 4 ++-- cli/lib/browser.ts | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index bd0ee01b94..b032768729 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -69,7 +69,7 @@ export async function runCommand(): Promise< void > { email: user.email, displayName: user.display_name, expiresIn: twoWeeksInSeconds, - expirationTime: now.getTime() + twoWeeksInSeconds, + expirationTime: now.getTime() + twoWeeksInSeconds * 1000, }; await saveAppdata( userData ); diff --git a/cli/lib/appdata.ts b/cli/lib/appdata.ts index 2f284cc2a8..b0d4147ff9 100644 --- a/cli/lib/appdata.ts +++ b/cli/lib/appdata.ts @@ -46,8 +46,8 @@ const userDataSchema = z authToken: z .object( { accessToken: z.string().min( 1, __( 'Access token cannot be empty' ) ), - expiresIn: z.number(), - expirationTime: z.number(), + expiresIn: z.number(), // Seconds + expirationTime: z.number(), // Milliseconds since the Unix epoch id: z.number().optional(), email: z.string(), displayName: z.string().default( '' ), diff --git a/cli/lib/browser.ts b/cli/lib/browser.ts index 21fd755fbc..2375d5b486 100644 --- a/cli/lib/browser.ts +++ b/cli/lib/browser.ts @@ -1,6 +1,5 @@ import { spawn } from 'child_process'; -import { __, sprintf } from '@wordpress/i18n'; -import { LoggerError } from 'cli/logger'; +import { __ } from '@wordpress/i18n'; /** * Opens the default browser with the specified URL From 23aa26c89975ed410a05d749509f48b7a04118aa Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Thu, 6 Nov 2025 13:47:59 +0100 Subject: [PATCH 11/20] Reject unsupported platforms --- cli/lib/browser.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cli/lib/browser.ts b/cli/lib/browser.ts index 2375d5b486..90902f8164 100644 --- a/cli/lib/browser.ts +++ b/cli/lib/browser.ts @@ -30,6 +30,8 @@ export async function openBrowser( url: string ): Promise< void > { cmd = 'xdg-open'; args = [ url ]; break; + default: + return Promise.reject( new Error( __( 'Unsupported platform' ) ) ); } return new Promise( ( resolve, reject ) => { From e13fd3459598ef59ef0aae31eec580b0138df333 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Fri, 7 Nov 2025 10:47:35 +0100 Subject: [PATCH 12/20] Address review feedback --- cli/commands/auth/login.ts | 47 ++++++++++++++++++++------------------ common/constants.ts | 1 + common/logger-actions.ts | 1 - 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/cli/commands/auth/login.ts b/cli/commands/auth/login.ts index b032768729..f2691e7d34 100644 --- a/cli/commands/auth/login.ts +++ b/cli/commands/auth/login.ts @@ -1,5 +1,6 @@ -import { password } from '@inquirer/prompts'; +import { input } from '@inquirer/prompts'; import { __, sprintf } from '@wordpress/i18n'; +import { DEFAULT_TOKEN_LIFETIME_MS } from 'common/constants'; import { getAuthenticationUrl } from 'common/lib/oauth'; import { AuthCommandLoggerAction as LoggerAction } from 'common/logger-actions'; import { getUserInfo } from 'cli/lib/api'; @@ -50,38 +51,40 @@ export async function runCommand(): Promise< void > { ); console.log( '' ); - try { - const accessToken = await password( { message: __( 'Authentication token:' ) } ); - const user = await getUserInfo( accessToken ); + let accessToken: Awaited< ReturnType< typeof input > >; + let user: Awaited< ReturnType< typeof getUserInfo > >; + try { + accessToken = await input( { message: __( 'Authentication token:' ) } ); + user = await getUserInfo( accessToken ); logger.reportSuccess( __( 'Authentication completed successfully!' ) ); + } catch ( error ) { + logger.reportError( new LoggerError( __( 'Authentication failed. Please try again.' ) ) ); + return; + } - try { - await lockAppdata(); - const userData = await readAppdata(); - - const now = new Date(); - const twoWeeksInSeconds = 2 * 7 * 24 * 60 * 60; + try { + await lockAppdata(); + const userData = await readAppdata(); - userData.authToken = { - accessToken, - id: user.ID, - email: user.email, - displayName: user.display_name, - expiresIn: twoWeeksInSeconds, - expirationTime: now.getTime() + twoWeeksInSeconds * 1000, - }; + userData.authToken = { + accessToken, + id: user.ID, + email: user.email, + displayName: user.display_name, + expiresIn: DEFAULT_TOKEN_LIFETIME_MS / 1000, + expirationTime: Date.now() + DEFAULT_TOKEN_LIFETIME_MS, + }; - await saveAppdata( userData ); - } finally { - await unlockAppdata(); - } + await saveAppdata( userData ); } catch ( error ) { if ( error instanceof LoggerError ) { logger.reportError( error ); } else { logger.reportError( new LoggerError( __( 'Authentication failed' ), error ) ); } + } finally { + await unlockAppdata(); } } diff --git a/common/constants.ts b/common/constants.ts index 2d9340f665..be81d540e7 100644 --- a/common/constants.ts +++ b/common/constants.ts @@ -7,6 +7,7 @@ export const DAY_MS = HOUR_MS * 24; // OAuth constants export const CLIENT_ID = '95109'; export const PROTOCOL_PREFIX = 'wpcom-local-dev'; +export const DEFAULT_TOKEN_LIFETIME_MS = DAY_MS * 14; export const LOCKFILE_NAME = 'appdata-v1.json.lock'; export const LOCKFILE_STALE_TIME = 5000; diff --git a/common/logger-actions.ts b/common/logger-actions.ts index 0e07a70fb3..7694ec7655 100644 --- a/common/logger-actions.ts +++ b/common/logger-actions.ts @@ -3,7 +3,6 @@ export enum AuthCommandLoggerAction { LOGIN = 'login', - LOGOUT = 'logout', } export enum PreviewCommandLoggerAction { From c72a70dfd5b8c73ce88c03f9d9b9ba9e3ce30dca Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Fri, 7 Nov 2025 10:49:12 +0100 Subject: [PATCH 13/20] Fix test --- cli/commands/auth/tests/login.test.ts | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/cli/commands/auth/tests/login.test.ts b/cli/commands/auth/tests/login.test.ts index 02c397e59b..00265df241 100644 --- a/cli/commands/auth/tests/login.test.ts +++ b/cli/commands/auth/tests/login.test.ts @@ -1,4 +1,4 @@ -import { password } from '@inquirer/prompts'; +import { input } from '@inquirer/prompts'; import { getAuthenticationUrl } from 'common/lib/oauth'; import { getUserInfo } from 'cli/lib/api'; import { @@ -15,14 +15,7 @@ import { Logger, LoggerError } from 'cli/logger'; jest.mock( '@inquirer/prompts' ); jest.mock( 'common/lib/oauth' ); jest.mock( 'cli/lib/api' ); -jest.mock( 'cli/lib/appdata', () => ( { - ...jest.requireActual( 'cli/lib/appdata' ), - lockAppdata: jest.fn(), - readAppdata: jest.fn(), - saveAppdata: jest.fn(), - unlockAppdata: jest.fn(), - getAuthToken: jest.fn(), -} ) ); +jest.mock( 'cli/lib/appdata' ); jest.mock( 'cli/lib/browser' ); jest.mock( 'cli/lib/i18n' ); jest.mock( 'cli/logger' ); @@ -68,7 +61,7 @@ describe( 'Auth Login Command', () => { ( getAppLocale as jest.Mock ).mockResolvedValue( 'en' ); ( getUserInfo as jest.Mock ).mockResolvedValue( mockUserData ); ( openBrowser as jest.Mock ).mockResolvedValue( undefined ); - ( password as jest.Mock ).mockResolvedValue( mockAccessToken ); + ( input as jest.Mock ).mockResolvedValue( mockAccessToken ); ( readAppdata as jest.Mock ).mockResolvedValue( mockAppdata ); ( getAuthToken as jest.Mock ).mockRejectedValue( new Error( 'Mock error' ) ); ( lockAppdata as jest.Mock ).mockResolvedValue( undefined ); @@ -87,7 +80,7 @@ describe( 'Auth Login Command', () => { await runCommand(); expect( openBrowser ).not.toHaveBeenCalled(); - expect( password ).not.toHaveBeenCalled(); + expect( input ).not.toHaveBeenCalled(); } ); it( 'should complete the login process successfully', async () => { @@ -99,7 +92,7 @@ describe( 'Auth Login Command', () => { 'https://developer.wordpress.com/copy-oauth-token' ); expect( openBrowser ).toHaveBeenCalledWith( mockAuthUrl ); - expect( password ).toHaveBeenCalledWith( { + expect( input ).toHaveBeenCalledWith( { message: 'Authentication token:', } ); expect( getUserInfo ).toHaveBeenCalledWith( mockAccessToken ); @@ -122,7 +115,7 @@ describe( 'Auth Login Command', () => { await runCommand(); expect( openBrowser ).toHaveBeenCalled(); - expect( password ).toHaveBeenCalled(); + expect( input ).toHaveBeenCalled(); } ); it( 'should handle browser open failure', async () => { @@ -132,7 +125,7 @@ describe( 'Auth Login Command', () => { const { runCommand } = await import( '../login' ); await runCommand(); - expect( password ).toHaveBeenCalled(); + expect( input ).toHaveBeenCalled(); } ); it( 'should handle API error when fetching user info', async () => { From 6ba6a053fddc5058a7cb1200bd6a4326d06a5c29 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Fri, 7 Nov 2025 10:51:08 +0100 Subject: [PATCH 14/20] Fix --- common/logger-actions.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/common/logger-actions.ts b/common/logger-actions.ts index 7694ec7655..0e07a70fb3 100644 --- a/common/logger-actions.ts +++ b/common/logger-actions.ts @@ -3,6 +3,7 @@ export enum AuthCommandLoggerAction { LOGIN = 'login', + LOGOUT = 'logout', } export enum PreviewCommandLoggerAction { From fc816bf55b86198b06599ec17652e416f3dbedae Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 09:56:20 +0000 Subject: [PATCH 15/20] docs: Update CLI documentation for auth login command Add comprehensive documentation for the new `studio auth login` command including usage instructions, flow description, and important notes about token lifetime and authentication sharing between CLI and desktop app. Co-authored-by: Fredrik Rombach Ekelund --- docs/ai-instructions.md | 52 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/docs/ai-instructions.md b/docs/ai-instructions.md index 6e1c74a194..cc8ebe791b 100644 --- a/docs/ai-instructions.md +++ b/docs/ai-instructions.md @@ -39,6 +39,56 @@ npm test -- path/to/test.test.ts npm test -- --testNamePattern="test name pattern" ``` +## CLI Commands + +The Studio CLI provides commands for managing authentication, preview sites, and local sites (beta). All CLI commands follow this pattern: + +```bash +npm run cli:build && node dist/cli/main.js +``` + +### Authentication Commands + +#### `studio auth login` +Log in to WordPress.com using OAuth2 authentication. + +**Usage:** +```bash +node dist/cli/main.js auth login +``` + +**Description:** +This command initiates the WordPress.com OAuth2 authentication flow: +1. Opens your default browser to the WordPress.com authorization page +2. After authorization, you'll be redirected to a page with your access token +3. Copy the token and paste it back into the terminal +4. The token is stored in your app data and shared with the Studio desktop app + +**Options:** +- None required + +**Example:** +```bash +npm run cli:build +node dist/cli/main.js auth login +# Browser opens for authentication +# Copy token from browser and paste when prompted +``` + +**Notes:** +- The access token is valid for 2 weeks +- If already authenticated, the command will notify you +- Authentication is shared between the CLI and the Studio desktop app +- If the browser fails to open, the URL will be displayed for manual opening + +### Preview Site Commands + +See the existing preview site commands (create, list, delete, update) in `cli/commands/preview/`. + +### Local Site Commands (Beta) + +Local site management commands are available when the `studioSitesCli` beta feature is enabled in app data. + ## WordPress Studio - Architecture Overview WordPress Studio is a desktop application for creating, managing, and testing WordPress sites locally. It's built as an Electron desktop application with a React renderer, powered by WordPress Playground and PHP WASM. @@ -109,11 +159,13 @@ WordPress Studio is a desktop application for creating, managing, and testing Wo ### `/cli` - Command-Line Interface - **`index.ts`** - CLI entry point using yargs - **`commands/`** - Command implementations + - `auth/` - Authentication commands (login to WordPress.com) - `preview/` - Preview site management commands - `site/` - Local site management commands (beta) - **`lib/`** - CLI-specific utilities and helpers - `appdata.ts` - Reading app configuration - `i18n.ts` - Locale loading for CLI + - `browser.ts` - Cross-platform browser opening utility ### `/common` - Shared Code (Both Main and Renderer) - **`lib/`** - Shared utility libraries From 5748109116dc4f440bc1778272fe235ff995c7b3 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Mon, 17 Nov 2025 10:57:42 +0100 Subject: [PATCH 16/20] Restore package-lock.json --- package-lock.json | 2400 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 1997 insertions(+), 403 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5a59936107..e72998835d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "@automattic/interpolate-components": "^1.2.1", "@formatjs/intl-locale": "^3.4.5", "@formatjs/intl-localematcher": "^0.5.4", - "@inquirer/prompts": "^7.9.0", "@php-wasm/node": "^3.0.19", "@php-wasm/scopes": "^3.0.19", "@php-wasm/universal": "^3.0.19", @@ -476,21 +475,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", + "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/generator": "^7.28.3", "@babel/helper-compilation-targets": "^7.27.2", "@babel/helper-module-transforms": "^7.28.3", "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/traverse": "^7.28.4", + "@babel/types": "^7.28.4", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -516,13 +515,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", + "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.28.3", + "@babel/types": "^7.28.2", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -784,9 +783,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.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -832,12 +831,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", + "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.5" + "@babel/types": "^7.28.4" }, "bin": { "parser": "bin/babel-parser.js" @@ -2356,12 +2355,10 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", - "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -2381,17 +2378,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", + "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", + "@babel/generator": "^7.28.3", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", + "@babel/parser": "^7.28.4", "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", + "@babel/types": "^7.28.4", "debug": "^4.3.1" }, "engines": { @@ -2399,13 +2396,13 @@ } }, "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", + "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-validator-identifier": "^7.27.1" }, "engines": { "node": ">=6.9.0" @@ -3942,6 +3939,40 @@ "node": ">=14.14" } }, + "node_modules/@emnapi/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emotion/babel-plugin": { "version": "11.11.0", "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", @@ -4100,177 +4131,602 @@ "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" }, - "node_modules/@esbuild/darwin-arm64": { + "node_modules/@esbuild/aix-ppc64": { "version": "0.25.9", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", - "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz", + "integrity": "sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==", "cpu": [ - "arm64" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "aix" ], "engines": { "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "node_modules/@esbuild/android-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.9.tgz", + "integrity": "sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==", + "cpu": [ + "arm" + ], "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "node_modules/@esbuild/android-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.9.tgz", + "integrity": "sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "node_modules/@esbuild/android-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.9.tgz", + "integrity": "sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.9.tgz", + "integrity": "sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.9.tgz", + "integrity": "sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", - "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.9.tgz", + "integrity": "sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.9.tgz", + "integrity": "sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "node": ">=18" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "node_modules/@esbuild/linux-arm": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.9.tgz", + "integrity": "sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==", + "cpu": [ + "arm" + ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.9.tgz", + "integrity": "sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@floating-ui/core": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", - "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", - "dependencies": { - "@floating-ui/utils": "^0.2.7" + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.9.tgz", + "integrity": "sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@floating-ui/dom": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", - "dependencies": { - "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.7" + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.9.tgz", + "integrity": "sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", - "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.9.tgz", + "integrity": "sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==", + "cpu": [ + "mips64el" + ], + "dev": true, "license": "MIT", - "dependencies": { + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.9.tgz", + "integrity": "sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.9.tgz", + "integrity": "sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.9.tgz", + "integrity": "sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.9.tgz", + "integrity": "sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.9.tgz", + "integrity": "sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.9.tgz", + "integrity": "sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.9.tgz", + "integrity": "sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.9.tgz", + "integrity": "sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.9.tgz", + "integrity": "sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.9.tgz", + "integrity": "sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.9.tgz", + "integrity": "sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.9.tgz", + "integrity": "sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.9.tgz", + "integrity": "sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", + "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "dependencies": { + "@floating-ui/utils": "^0.2.7" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.7" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.8.tgz", + "integrity": "sha512-HOdqOt3R3OGeTKidaLvJKcgg75S6tibQ3Tif4eyd91QnIJWr0NLvoXFpJA/j8HqkFSL68GDca9AuyWEHlhyClw==", + "license": "MIT", + "dependencies": { "@floating-ui/dom": "^1.6.1" }, "peerDependencies": { @@ -4389,7 +4845,9 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", + "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -4398,7 +4856,9 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/core": "^10.3.0", @@ -4422,7 +4882,9 @@ "version": "5.1.19", "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -4443,7 +4905,9 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/figures": "^1.0.14", @@ -4470,7 +4934,9 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, "license": "ISC", + "peer": true, "engines": { "node": ">= 12" } @@ -4479,7 +4945,9 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, "license": "ISC", + "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -4488,7 +4956,9 @@ "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", + "peer": true, "engines": { "node": ">=14" }, @@ -4500,7 +4970,9 @@ "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", + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4512,7 +4984,9 @@ "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, "license": "MIT", + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -4526,7 +5000,9 @@ "version": "4.2.21", "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/external-editor": "^1.0.2", @@ -4548,7 +5024,9 @@ "version": "4.0.21", "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9", @@ -4570,7 +5048,9 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "chardet": "^2.1.0", "iconv-lite": "^0.7.0" @@ -4591,13 +5071,17 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "license": "MIT" + "dev": true, + "license": "MIT", + "peer": true }, "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -4613,6 +5097,7 @@ "version": "1.0.14", "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -4622,7 +5107,9 @@ "version": "4.2.5", "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -4643,7 +5130,9 @@ "version": "3.0.21", "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9" @@ -4664,7 +5153,9 @@ "version": "4.0.21", "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/core": "^10.3.0", @@ -4686,7 +5177,9 @@ "version": "7.9.0", "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/checkbox": "^4.3.0", "@inquirer/confirm": "^5.1.19", @@ -4715,7 +5208,9 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/type": "^3.0.9", @@ -4737,7 +5232,9 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/core": "^10.3.0", "@inquirer/figures": "^1.0.14", @@ -4760,7 +5257,9 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@inquirer/ansi": "^1.0.1", "@inquirer/core": "^10.3.0", @@ -4784,7 +5283,9 @@ "version": "3.0.9", "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", + "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -5775,6 +6276,19 @@ "node": ">= 12.13.0" } }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, "node_modules/@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents.3", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", @@ -6856,80 +7370,344 @@ "node": ">=14" } }, - "node_modules/@opentelemetry/sql-common": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", - "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.1.0" - }, + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", + "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0" + } + }, + "node_modules/@paralleldrive/cuid2": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", + "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.1.5" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", + "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^1.0.3", + "is-glob": "^4.0.3", + "micromatch": "^4.0.5", + "node-addon-api": "^7.0.0" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.1", + "@parcel/watcher-darwin-arm64": "2.5.1", + "@parcel/watcher-darwin-x64": "2.5.1", + "@parcel/watcher-freebsd-x64": "2.5.1", + "@parcel/watcher-linux-arm-glibc": "2.5.1", + "@parcel/watcher-linux-arm-musl": "2.5.1", + "@parcel/watcher-linux-arm64-glibc": "2.5.1", + "@parcel/watcher-linux-arm64-musl": "2.5.1", + "@parcel/watcher-linux-x64-glibc": "2.5.1", + "@parcel/watcher-linux-x64-musl": "2.5.1", + "@parcel/watcher-win32-arm64": "2.5.1", + "@parcel/watcher-win32-ia32": "2.5.1", + "@parcel/watcher-win32-x64": "2.5.1" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz", + "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", + "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz", + "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz", + "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz", + "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz", + "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz", + "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz", + "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz", + "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz", + "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=14" + "node": ">= 10.0.0" }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@paralleldrive/cuid2": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@paralleldrive/cuid2/-/cuid2-2.2.2.tgz", - "integrity": "sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz", + "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.1.5" + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher": { + "node_modules/@parcel/watcher-win32-ia32": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz", - "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz", + "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==", + "cpu": [ + "ia32" + ], "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, + "os": [ + "win32" + ], "peer": true, - "dependencies": { - "detect-libc": "^1.0.3", - "is-glob": "^4.0.3", - "micromatch": "^4.0.5", - "node-addon-api": "^7.0.0" - }, "engines": { "node": ">= 10.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.1", - "@parcel/watcher-darwin-arm64": "2.5.1", - "@parcel/watcher-darwin-x64": "2.5.1", - "@parcel/watcher-freebsd-x64": "2.5.1", - "@parcel/watcher-linux-arm-glibc": "2.5.1", - "@parcel/watcher-linux-arm-musl": "2.5.1", - "@parcel/watcher-linux-arm64-glibc": "2.5.1", - "@parcel/watcher-linux-arm64-musl": "2.5.1", - "@parcel/watcher-linux-x64-glibc": "2.5.1", - "@parcel/watcher-linux-x64-musl": "2.5.1", - "@parcel/watcher-win32-arm64": "2.5.1", - "@parcel/watcher-win32-ia32": "2.5.1", - "@parcel/watcher-win32-x64": "2.5.1" } }, - "node_modules/@parcel/watcher-darwin-arm64": { + "node_modules/@parcel/watcher-win32-x64": { "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz", - "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz", + "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ], "peer": true, "engines": { @@ -7241,13 +8019,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.52.0.tgz", - "integrity": "sha512-uh6W7sb55hl7D6vsAeA+V2p5JnlAqzhqFyF0VcJkKZXkgnFcVG9PziERRHQfPLfNGx1C292a4JqbWzhR8L4R1g==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz", + "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.52.0" + "playwright": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -7309,35 +8087,273 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.47", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", - "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.43", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.43.tgz", + "integrity": "sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/plugin-virtual": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", + "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.2.tgz", + "integrity": "sha512-uLN8NAiFVIRKX9ZQha8wy6UUs06UNSZ32xj6giK/rmMXAgKahwExvK6SsmgU5/brh4w/nSgj8e0k3c1HBQpa0A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.2.tgz", + "integrity": "sha512-oEouqQk2/zxxj22PNcGSskya+3kV0ZKH+nQxuCCOGJ4oTXBdNTbv+f/E3c74cNLeMO1S5wVWacSws10TTSB77g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz", + "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.2.tgz", + "integrity": "sha512-Wa/Wn8RFkIkr1vy1k1PB//VYhLnlnn5eaJkfTQKivirOvzu5uVd2It01ukeQstMursuz7S1bU+8WW+1UPXpa8A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.2.tgz", + "integrity": "sha512-QkzxvH3kYN9J1w7D1A+yIMdI1pPekD+pWx7G5rXgnIlQ1TVYVC6hLl7SOV9pi5q9uIDF9AuIGkuzcbF7+fAhow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.2.tgz", + "integrity": "sha512-dkYXB0c2XAS3a3jmyDkX4Jk0m7gWLFzq1C3qUnJJ38AyxIF5G/dyS4N9B30nvFseCfgtCEdbYFhk0ChoCGxPog==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.2.tgz", + "integrity": "sha512-9VlPY/BN3AgbukfVHAB8zNFWB/lKEuvzRo1NKev0Po8sYFKx0i+AQlCYftgEjcL43F2h9Ui1ZSdVBc4En/sP2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.2.tgz", + "integrity": "sha512-+GdKWOvsifaYNlIVf07QYan1J5F141+vGm5/Y8b9uCZnG/nxoGqgCmR24mv0koIWWuqvFYnbURRqw1lv7IBINw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.2.tgz", + "integrity": "sha512-df0Eou14ojtUdLQdPFnymEQteENwSJAdLf5KCDrmZNsy1c3YaCNaJvYsEUHnrg+/DLBH612/R0xd3dD03uz2dg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.2.tgz", + "integrity": "sha512-iPeouV0UIDtz8j1YFR4OJ/zf7evjauqv7jQ/EFs0ClIyL+by++hiaDAfFipjOgyz6y6xbDvJuiU4HwpVMpRFDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.50.2.tgz", + "integrity": "sha512-OL6KaNvBopLlj5fTa5D5bau4W82f+1TyTZRr2BdnfsrnQnmdxh4okMxR2DcDkJuh4KeoQZVuvHvzuD/lyLn2Kw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.2.tgz", + "integrity": "sha512-I21VJl1w6z/K5OTRl6aS9DDsqezEZ/yKpbqlvfHbW0CEF5IL8ATBMuUx6/mp683rKTK8thjs/0BaNrZLXetLag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.2.tgz", + "integrity": "sha512-Hq6aQJT/qFFHrYMjS20nV+9SKrXL2lvFBENZoKfoTH2kKDOJqff5OSJr4x72ZaG/uUn+XmBnGhfr4lwMRrmqCQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.2.tgz", + "integrity": "sha512-82rBSEXRv5qtKyr0xZ/YMF531oj2AIpLZkeNYxmKNN6I2sVE9PGegN99tYDLK2fYHJITL1P2Lgb4ZXnv0PjQvw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.2.tgz", + "integrity": "sha512-4Q3S3Hy7pC6uaRo9gtXUTJ+EKo9AKs3BXKc2jYypEcMQ49gDPFU2P1ariX9SEtBzE5egIX6fSUmbmGazwBVF9w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.2.tgz", + "integrity": "sha512-9Jie/At6qk70dNIcopcL4p+1UirusEtznpNtcq/u/C5cC4HBX7qSGsYIcG6bdxj15EYWhHiu02YvmdPzylIZlA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/plugin-virtual": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@rollup/plugin-virtual/-/plugin-virtual-3.0.2.tgz", - "integrity": "sha512-10monEYsBp3scM4/ND4LNH5Rxvh3e/cVeL3jWTgZ2SrQ+BmUoQcopVQvnaMcOnykb1VkxUFuDAN+0FnpTFRy2A==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.2.tgz", + "integrity": "sha512-HPNJwxPL3EmhzeAnsWQCM3DcoqOz3/IC6de9rWfGR8ZCuEHETi9km66bH/wG3YH0V3nyzyFEGUZeL5PKyy4xvw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@rollup/rollup-darwin-arm64": { + "node_modules/@rollup/rollup-openharmony-arm64": { "version": "4.50.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.2.tgz", - "integrity": "sha512-OZuTVTpj3CDSIxmPgGH8en/XtirV5nfljHZ3wrNwvgkT5DQLhIKAeuFSiwtbMto6oVexV0k1F1zqURPKf5rI1Q==", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.2.tgz", + "integrity": "sha512-nMKvq6FRHSzYfKLHZ+cChowlEkR2lj/V0jYj9JnGUVPL2/mIeFGmVM2mLaFeNa5Jev7W7TovXqXIG2d39y1KYA==", "cpu": [ "arm64" ], @@ -7345,7 +8361,49 @@ "license": "MIT", "optional": true, "os": [ - "darwin" + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.2.tgz", + "integrity": "sha512-eFUvvnTYEKeTyHEijQKz81bLrUQOXKZqECeiWH6tb8eXXbZk+CXSG2aFrig2BQ/pjiVRj36zysjgILkqarS2YA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.2.tgz", + "integrity": "sha512-cBaWmXqyfRhH8zmUxK3d3sAhEWLrtMjWBRwdMMHJIXSjvjLKvv49adxiEz+FJ8AP90apSDDBx2Tyd/WylV6ikA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.50.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.2.tgz", + "integrity": "sha512-APwKy6YUhvZaEoHyM+9xqmTpviEI+9eL7LoCH+aLcvWYHJ663qG5zx7WzWZY+a9qkg5JtzcMyJ9z0WtQBMDmgA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" ] }, "node_modules/@rtsao/scc": { @@ -7635,6 +8693,135 @@ "node": ">=10" } }, + "node_modules/@sentry/cli-linux-arm": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.54.0.tgz", + "integrity": "sha512-Brx/MsIBXmMuP/rRZos8pMxW5mSZoYmR0tDO483RR9hfE6PnyxhvNOTkLLm6fMd3pGmiG4sr25jYeYQglhIpRA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-arm64": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.54.0.tgz", + "integrity": "sha512-ocE6gBD2GiMH8Vm0OdlD8tz9eq4uiTmG2Nb0sQshcTDZ7DkOGEmtbg2Je2F1Eug6wR/zQWzD/t0bMUm6L0X0Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-i686": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.54.0.tgz", + "integrity": "sha512-GZyLbZjDX8e635O8iVbzkHs9KGUo5UK0PGbTsjxlKHNgWAf1SY+y+wtWLrF46AhxUveeV/ydEUOJJjcDgXW3+g==", + "cpu": [ + "x86", + "ia32" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-linux-x64": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.54.0.tgz", + "integrity": "sha512-NyTM6dp+/cFiULUTGlxlaa83pL+FdWHwPE5IkQ6EiqpsO0auacVwWJIIvj4EbFS7XQ8bgjUA3Rf83lZeI+ZPvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux", + "freebsd", + "android" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-arm64": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-arm64/-/cli-win32-arm64-2.54.0.tgz", + "integrity": "sha512-oVsdo7yWAokGtnl2cbuxvPv3Pu3ge8n9Oyp+iNT1S98XJ/QtRGT8L2ZClNllzEeVFFoZWlK7RVT5xh7OI4ge/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-i686": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.54.0.tgz", + "integrity": "sha512-YvBUq5ky80j2fulllft6ZCtLslwrNc5s8dXV7Jr7IUUmTcVcvkOdgWwAsGRjTmZxXZbfaRaYE2fEvfFwjmciTA==", + "cpu": [ + "x86", + "ia32" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@sentry/cli-win32-x64": { + "version": "2.54.0", + "resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.54.0.tgz", + "integrity": "sha512-Jn5abpRrbdcQrec+8QTgGdX8wxTdQr4bm81I/suJ3bXpID+fsiAnp+yclKlq8LWlj5q7uATnGJ4QpajDT9qBRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, "node_modules/@sentry/core": { "version": "9.46.0", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-9.46.0.tgz", @@ -8016,18 +9203,171 @@ } } }, - "node_modules/@swc/core-darwin-arm64": { + "node_modules/@swc/core-darwin-arm64": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.5.tgz", + "integrity": "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.13.5.tgz", + "integrity": "sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.13.5.tgz", + "integrity": "sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.13.5.tgz", + "integrity": "sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.13.5.tgz", + "integrity": "sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.13.5.tgz", + "integrity": "sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.13.5.tgz", + "integrity": "sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.13.5.tgz", + "integrity": "sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { "version": "1.13.5", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.13.5.tgz", - "integrity": "sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.13.5.tgz", + "integrity": "sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw==", "cpu": [ - "arm64" + "ia32" ], "dev": true, "license": "Apache-2.0 AND MIT", "optional": true, "os": [ - "darwin" + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.13.5.tgz", + "integrity": "sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" ], "engines": { "node": ">=10" @@ -8259,6 +9599,17 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/appdmg": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@types/appdmg/-/appdmg-0.5.5.tgz", @@ -9119,6 +10470,34 @@ "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", "license": "ISC" }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@unrs/resolver-binding-darwin-arm64": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", @@ -9133,6 +10512,233 @@ "darwin" ] }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@use-gesture/core": { "version": "10.3.1", "resolved": "https://registry.npmjs.org/@use-gesture/core/-/core-10.3.1.tgz", @@ -9150,16 +10756,16 @@ } }, "node_modules/@vitejs/plugin-react": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz", - "integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.0.tgz", + "integrity": "sha512-4LuWrg7EKWgQaMJfnN+wcmbAW+VSsCmqGohftWjuct47bv8uE4n/nPpq4XjJPsxgq00GGG5J8dvBczp8uxScew==", "dev": true, "license": "MIT", "dependencies": { - "@babel/core": "^7.28.5", + "@babel/core": "^7.28.4", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.47", + "@rolldown/pluginutils": "1.0.0-beta.43", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, @@ -9323,13 +10929,13 @@ } }, "node_modules/@wordpress/a11y": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.35.0.tgz", - "integrity": "sha512-37DeBnBU20lLpQjwAZx0fkPsrrXT4COMSRhZOiFifv7wCiNW1DIukfqReAc/yZ6x0wOtqXKA3n905D8zm5NF5A==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-4.34.0.tgz", + "integrity": "sha512-l4/Q1nnLMi1nQJWl4y3Rdr9zQnxYgGqL0ZJwz1vOI8qqSO2Uug8wVCrVIsKIuUQHuD+ya/Q5hqQIedXKAdTvsQ==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/dom-ready": "^4.35.0", - "@wordpress/i18n": "^6.8.0" + "@wordpress/dom-ready": "^4.34.0", + "@wordpress/i18n": "^6.7.0" }, "engines": { "node": ">=18.12.0", @@ -9337,9 +10943,9 @@ } }, "node_modules/@wordpress/base-styles": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-6.11.0.tgz", - "integrity": "sha512-olV27w/QCztQj7xs/WssxrGJh7jyI+dVsQBw1p+LOo+XxRhFq6MvcUH6vEBXpU78ICtlqEx/uR3eYwEy1hQhUw==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-6.10.0.tgz", + "integrity": "sha512-Dw/1Om7Kv9YXvN6RaSOmzq2id1MrHZ+rUS2uHNkadeF3Jv+W0Zewl9iCBJarB6Nf72GMkktPwpaRrwhc6zPLIg==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9347,9 +10953,9 @@ } }, "node_modules/@wordpress/components": { - "version": "30.8.0", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-30.8.0.tgz", - "integrity": "sha512-lVcPXXeip41K6VmvVLkIPPbhsfIn5QZ9AFozkPEZPDOcpFvvYTnT4hDRM5+Pi9xrO2TOGhbXoJmYlFjAx19xSw==", + "version": "30.7.0", + "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-30.7.0.tgz", + "integrity": "sha512-LlXjicK7zXnwmFSTnxByVwL+Muh4QGcqunxlBg3+Ni8yLtQyTKb6yS8wGUCE7USGEMOlEX1NYvp6i3DOZk1tiw==", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.4.15", @@ -9363,24 +10969,24 @@ "@types/gradient-parser": "1.1.0", "@types/highlight-words-core": "1.2.1", "@use-gesture/react": "^10.3.1", - "@wordpress/a11y": "^4.35.0", - "@wordpress/base-styles": "^6.11.0", - "@wordpress/compose": "^7.35.0", - "@wordpress/date": "^5.35.0", - "@wordpress/deprecated": "^4.35.0", - "@wordpress/dom": "^4.35.0", - "@wordpress/element": "^6.35.0", - "@wordpress/escape-html": "^3.35.0", - "@wordpress/hooks": "^4.35.0", - "@wordpress/html-entities": "^4.35.0", - "@wordpress/i18n": "^6.8.0", - "@wordpress/icons": "^11.2.0", - "@wordpress/is-shallow-equal": "^5.35.0", - "@wordpress/keycodes": "^4.35.0", - "@wordpress/primitives": "^4.35.0", - "@wordpress/private-apis": "^1.35.0", - "@wordpress/rich-text": "^7.35.0", - "@wordpress/warning": "^3.35.0", + "@wordpress/a11y": "^4.34.0", + "@wordpress/base-styles": "^6.10.0", + "@wordpress/compose": "^7.34.0", + "@wordpress/date": "^5.34.0", + "@wordpress/deprecated": "^4.34.0", + "@wordpress/dom": "^4.34.0", + "@wordpress/element": "^6.34.0", + "@wordpress/escape-html": "^3.34.0", + "@wordpress/hooks": "^4.34.0", + "@wordpress/html-entities": "^4.34.0", + "@wordpress/i18n": "^6.7.0", + "@wordpress/icons": "^11.1.0", + "@wordpress/is-shallow-equal": "^5.34.0", + "@wordpress/keycodes": "^4.34.0", + "@wordpress/primitives": "^4.34.0", + "@wordpress/private-apis": "^1.34.0", + "@wordpress/rich-text": "^7.34.0", + "@wordpress/warning": "^3.34.0", "change-case": "^4.1.2", "clsx": "^2.1.1", "colord": "^2.7.0", @@ -9409,9 +11015,10 @@ } }, "node_modules/@wordpress/components/node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", + "license": "MIT" }, "node_modules/@wordpress/components/node_modules/uuid": { "version": "9.0.1", @@ -9426,19 +11033,19 @@ } }, "node_modules/@wordpress/compose": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.35.0.tgz", - "integrity": "sha512-UUQ31Rfi+KFfqT5wkbTgq0nMh+QfbLvshhm30+EGr8R3bYziHhfLKhIL2YQXf4MIX4owOFdKgbAt4GFeVI24ng==", + "version": "7.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-7.34.0.tgz", + "integrity": "sha512-gCgsU/VB8mvP9WqzOJLpd9p6ErTBC9qMhP9HQWnmW/SiYm0mhmNaknyr1viu4QYDlMeTVsCycNiP+MacUDCUzg==", "license": "GPL-2.0-or-later", "dependencies": { "@types/mousetrap": "^1.6.8", - "@wordpress/deprecated": "^4.35.0", - "@wordpress/dom": "^4.35.0", - "@wordpress/element": "^6.35.0", - "@wordpress/is-shallow-equal": "^5.35.0", - "@wordpress/keycodes": "^4.35.0", - "@wordpress/priority-queue": "^3.35.0", - "@wordpress/undo-manager": "^1.35.0", + "@wordpress/deprecated": "^4.34.0", + "@wordpress/dom": "^4.34.0", + "@wordpress/element": "^6.34.0", + "@wordpress/is-shallow-equal": "^5.34.0", + "@wordpress/keycodes": "^4.34.0", + "@wordpress/priority-queue": "^3.34.0", + "@wordpress/undo-manager": "^1.34.0", "change-case": "^4.1.2", "clipboard": "^2.0.11", "mousetrap": "^1.6.5", @@ -9453,18 +11060,18 @@ } }, "node_modules/@wordpress/data": { - "version": "10.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.35.0.tgz", - "integrity": "sha512-rAhyjbnDI9lOPBiJITDOwHJd8+WNmkurqwMJYDjJRqCYAl/mPx9vy6JIgIkyRWQQNiGYrCAv1z6qLqS2Cypg3Q==", + "version": "10.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-10.34.0.tgz", + "integrity": "sha512-3xk2NHweks8TLHyhTnMuIXTV2IVBCcejpGMTJeAayLoh0i/G+285EMz7O1t6fIu3u5uXCd/vQdJ2ewLTiIqXiQ==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/compose": "^7.35.0", - "@wordpress/deprecated": "^4.35.0", - "@wordpress/element": "^6.35.0", - "@wordpress/is-shallow-equal": "^5.35.0", - "@wordpress/priority-queue": "^3.35.0", - "@wordpress/private-apis": "^1.35.0", - "@wordpress/redux-routine": "^5.35.0", + "@wordpress/compose": "^7.34.0", + "@wordpress/deprecated": "^4.34.0", + "@wordpress/element": "^6.34.0", + "@wordpress/is-shallow-equal": "^5.34.0", + "@wordpress/priority-queue": "^3.34.0", + "@wordpress/private-apis": "^1.34.0", + "@wordpress/redux-routine": "^5.34.0", "deepmerge": "^4.3.0", "equivalent-key-map": "^0.2.2", "is-plain-object": "^5.0.0", @@ -9482,25 +11089,25 @@ } }, "node_modules/@wordpress/dataviews": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@wordpress/dataviews/-/dataviews-10.3.0.tgz", - "integrity": "sha512-7mBcW4Vris+8Be3ESUPkhe85AwAbwO+2ocvi4UDF6jEzeyH7GQxq+1k4Lq4vAc+pNBf0IehZV598+qs8nk9j2w==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@wordpress/dataviews/-/dataviews-10.2.0.tgz", + "integrity": "sha512-Kwt5tB4SRkyWFVVqgGNraRajNm5lACObrzLV1f2A2343dQ88cgiS5iukI9qdhzy7CiGIHN7UrQaFbpDoTtOKAA==", "license": "GPL-2.0-or-later", "dependencies": { "@ariakit/react": "^0.4.15", - "@wordpress/base-styles": "^6.11.0", - "@wordpress/components": "^30.8.0", - "@wordpress/compose": "^7.35.0", - "@wordpress/data": "^10.35.0", - "@wordpress/date": "^5.35.0", - "@wordpress/element": "^6.35.0", - "@wordpress/i18n": "^6.8.0", - "@wordpress/icons": "^11.2.0", - "@wordpress/keycodes": "^4.35.0", - "@wordpress/primitives": "^4.35.0", - "@wordpress/private-apis": "^1.35.0", - "@wordpress/url": "^4.35.0", - "@wordpress/warning": "^3.35.0", + "@wordpress/base-styles": "^6.10.0", + "@wordpress/components": "^30.7.0", + "@wordpress/compose": "^7.34.0", + "@wordpress/data": "^10.34.0", + "@wordpress/date": "^5.34.0", + "@wordpress/element": "^6.34.0", + "@wordpress/i18n": "^6.7.0", + "@wordpress/icons": "^11.1.0", + "@wordpress/keycodes": "^4.34.0", + "@wordpress/primitives": "^4.34.0", + "@wordpress/private-apis": "^1.34.0", + "@wordpress/url": "^4.34.0", + "@wordpress/warning": "^3.34.0", "clsx": "^2.1.1", "colord": "^2.7.0", "date-fns": "^4.1.0", @@ -9528,12 +11135,12 @@ } }, "node_modules/@wordpress/date": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.35.0.tgz", - "integrity": "sha512-xXJf703MtQCbgoAT1DSwRu+iWcgb6UFAoBnnzq8ohZCICsBxEGOOr+EAgblvFSNPV3MCtUOr98zRCAuGon3Gqw==", + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-5.34.0.tgz", + "integrity": "sha512-0HbuRIL8b1KtpAU1ANG58iY07p9m0+jGUDpJCvJlPOQiCP0nDDLws9C5vTPrRiJnosxj6elyHtyt4LQnHAFJRA==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/deprecated": "^4.35.0", + "@wordpress/deprecated": "^4.34.0", "moment": "^2.29.4", "moment-timezone": "^0.5.40" }, @@ -9543,12 +11150,12 @@ } }, "node_modules/@wordpress/deprecated": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.35.0.tgz", - "integrity": "sha512-+TruZtmDxRfVw02c1de7ofGC3CrcaPCUXCCbwfP6ruy1zM3IC3rtJfyTbqKPqO1y4uI+9Kqe5VEobqRKT3HQSg==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-4.34.0.tgz", + "integrity": "sha512-SuQX1CX97dBVPmN33zdzdjkBHajkOpr1WUdLfiP5aR8xS9CAlyMJgfYygBxFZeMKmsbBYENDVJtrulw4lPvkKw==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/hooks": "^4.35.0" + "@wordpress/hooks": "^4.34.0" }, "engines": { "node": ">=18.12.0", @@ -9556,12 +11163,12 @@ } }, "node_modules/@wordpress/dom": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.35.0.tgz", - "integrity": "sha512-mM/8m548RaWtkBonpCYHprXgyVFjKcFJWyHfWZz17j01xIbzBq+//cR/Lff86EiEuwynedqlFoEJUcgvPkrJZw==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-4.34.0.tgz", + "integrity": "sha512-W2gk4kkjhEHBLg/6nrJJ4QfvRguuzAx83S8UXS4tYtcYKh5vCzzcDPv8hN3cMS75R5nZBBzHgNfquS5iDhSXOA==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/deprecated": "^4.35.0" + "@wordpress/deprecated": "^4.34.0" }, "engines": { "node": ">=18.12.0", @@ -9569,9 +11176,9 @@ } }, "node_modules/@wordpress/dom-ready": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.35.0.tgz", - "integrity": "sha512-u8ifPAFsIAkBG3ehcZdnt+b3t2S0gD3dyDMKgl+GO95wq6kJFqo/NYNQqsjeYUMOFX7cL9D0F2gxiBB4D/AQIA==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-4.34.0.tgz", + "integrity": "sha512-LclbzuGRtDkF/NrygvnjtO+hcQsnq/iC+iEa78KvHJXQB8daWvrImgqhsD99K53e8AeUwtUFPFwLac5Co14jOg==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9579,14 +11186,14 @@ } }, "node_modules/@wordpress/element": { - "version": "6.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.35.0.tgz", - "integrity": "sha512-RmxQsk0ANoHtxDc6anbUH/lHL7Mmbbdn016WKHYVh4+79EzN1tBeM8OML2gHpllUISmIYQvO4wIPSmEVzRh+Gw==", + "version": "6.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-6.34.0.tgz", + "integrity": "sha512-WoCBhGa7fTd9NB0B1XS+hF64vmglI90tEskQxxfqtgby1IiLj7TjG+zyVeW1UdrKja3zSAhZTqZc1wjpEtbcoQ==", "license": "GPL-2.0-or-later", "dependencies": { "@types/react": "^18.2.79", "@types/react-dom": "^18.2.25", - "@wordpress/escape-html": "^3.35.0", + "@wordpress/escape-html": "^3.34.0", "change-case": "^4.1.2", "is-plain-object": "^5.0.0", "react": "^18.3.0", @@ -9598,9 +11205,9 @@ } }, "node_modules/@wordpress/escape-html": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.35.0.tgz", - "integrity": "sha512-thY7RGAI6UijG3sbBm4IRzMX9lnHkEA/vR3Y0E5BGQYzNFwc+i7t1Lm4scpEBnL3UEQxdlD1wiJTH4pv5olV+Q==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-3.34.0.tgz", + "integrity": "sha512-uDkh9w970Lnh43GTw/8csw0BkWY08tzYo2gqIF1I26N7YnpwRbVnv1Swet8PFvv8YDxpfejWBFfA7so4nciKfw==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9608,9 +11215,9 @@ } }, "node_modules/@wordpress/hooks": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.35.0.tgz", - "integrity": "sha512-PQcAv/zfMYn5sPScOWDu1vgYkyHaDFt7+1IHvwR0RGE0AdQrdnKjvm6VJ4ALugA+zvJZkBZxLk5Gm+NZGAWIMg==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-4.34.0.tgz", + "integrity": "sha512-uZcgAMDhf6OzYCUoDqq//wYsfC7yx+XUd2av07aROn8SKTkWRfu7zweJHsOBmK0TkCx976ELoL/SZZfHPcj3aw==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9618,9 +11225,9 @@ } }, "node_modules/@wordpress/html-entities": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.35.0.tgz", - "integrity": "sha512-43K8viPNNWUxmCKfKN2Dx/TgJitbGeGCfWBj0aloRoeqOUeEuDkWoak+XiIrJKpwYHTYhqtePl7COMWPzwkqbw==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-4.34.0.tgz", + "integrity": "sha512-TYYNhGbHEAuVH48Q5+Muy1Bc1G32yK+4btLhkiQOtRXfa/p7f+3bUMe1/t3wgdmU1hM//wS6dsJ2wvXa9rBCeA==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9628,13 +11235,13 @@ } }, "node_modules/@wordpress/i18n": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.8.0.tgz", - "integrity": "sha512-lNMjf0VXWm2qzkEI+v1psvb26FN+B32sO6nLOFxs5Lay/E0WVqCw31DiRw8nETlzVwsMheO+iy0lCSOLvg+jog==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-6.7.0.tgz", + "integrity": "sha512-156R15kz17WkFJ0mtoVt9ByFvt4i9zcstFiXC1HjMKr3zV1DZSplvcJeNJTENJBRX8sE+Be0NPevaC8LCodjgw==", "license": "GPL-2.0-or-later", "dependencies": { "@tannin/sprintf": "^1.3.2", - "@wordpress/hooks": "^4.35.0", + "@wordpress/hooks": "^4.34.0", "gettext-parser": "^1.3.1", "memize": "^2.1.0", "tannin": "^1.2.0" @@ -9648,13 +11255,13 @@ } }, "node_modules/@wordpress/icons": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-11.2.0.tgz", - "integrity": "sha512-9OIymLlwanLkSjKbUyKwF4Z4LnCojQsulQNGsZVpaqx7ryqEGEMvNJ5BvrzUWBoQpX9nvJBvK+obE1zxE0vt+g==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-11.1.0.tgz", + "integrity": "sha512-N61MEoI9dU3fDQu7tdY1/kUSOhERyAnKHcVDWl3KWNFDuNuelnoUCMSckNV4T1Jz/M+2Mkov/J39Mroqo782zQ==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/element": "^6.35.0", - "@wordpress/primitives": "^4.35.0" + "@wordpress/element": "^6.34.0", + "@wordpress/primitives": "^4.34.0" }, "engines": { "node": ">=18.12.0", @@ -9662,9 +11269,9 @@ } }, "node_modules/@wordpress/is-shallow-equal": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.35.0.tgz", - "integrity": "sha512-ooM/QFzxu8Ueqsv0D/z0+X6grbVws3GFMSxdM12eZO1B0/x6JPAtq4msZkoxqeQ4zoR0ghYHFXzv3k+Ch1tsFw==", + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-5.34.0.tgz", + "integrity": "sha512-p401k9SahwMOlmQq9DsKnfpHbax6QtE1hB6qTS/1VfhKLYy/DHc43OKafrwGB5G+rHntrsBNsO9r63DRcl4bbQ==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9672,12 +11279,12 @@ } }, "node_modules/@wordpress/keycodes": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.35.0.tgz", - "integrity": "sha512-+cvb9I4VorJRUsPC4C/2e0QWMz8hkjQIvjz3BjTkIXyWlxsSRSk/+a/YCrfyyA5ysuR9PgwKxxI7/ZaAPvOC6w==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.34.0.tgz", + "integrity": "sha512-x/Z+tbcics353Kc1oymrWrnQ8BErpYk112yncli0VXYPGa1OYDoYiUs2Fh49wWXorlx3Dtw6mI+hbiJ14gGp7g==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/i18n": "^6.8.0" + "@wordpress/i18n": "^6.7.0" }, "engines": { "node": ">=18.12.0", @@ -9685,12 +11292,12 @@ } }, "node_modules/@wordpress/primitives": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.35.0.tgz", - "integrity": "sha512-F7FqOM9tkgwc0DwFqsgtOcvREJgBHALbCBFwv1kmxRadknD6YsBdmpamceN2UIHi9NnOM0Gruo2vJNKjoN4bEw==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-4.34.0.tgz", + "integrity": "sha512-6M/xFse9Da6oC+EZKGGOVCvbX/f5OOw539lyhugnS0sQ+NIWNvvwDh6VW1bCaWQ6uaZDUYbbQeD6Ax97NQuV+w==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/element": "^6.35.0", + "@wordpress/element": "^6.34.0", "clsx": "^2.1.1" }, "engines": { @@ -9702,9 +11309,9 @@ } }, "node_modules/@wordpress/priority-queue": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.35.0.tgz", - "integrity": "sha512-kLdPx09CnPMPUL5hI/3SUgbBVEka20iWBxM2pvwJGrn3bleY0WxGqLtoUksn6yQds9d7jjS5cKoBYxY1H8MHgg==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-3.34.0.tgz", + "integrity": "sha512-6qxUP36bvSTvKkxoOhfSPmMZbSt4eCt5diQEugW9LXCuHA6lfWQ2sh1tWWzKpLD9zQCzeYIeVqA1jYHjbO929Q==", "license": "GPL-2.0-or-later", "dependencies": { "requestidlecallback": "^0.3.0" @@ -9715,9 +11322,9 @@ } }, "node_modules/@wordpress/private-apis": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.35.0.tgz", - "integrity": "sha512-gpwYCAuWSjSps7KnmPfUSdJUf5iq8P0ln1eZPcnjs3IwRDUrKW9eUrO0jID+XUsi63qi5c+lv9UkwI8M8C9c5A==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-1.34.0.tgz", + "integrity": "sha512-6AgwgkVZOlXu6kJpQrAtC5WiRfUfxCu/oOKMeN3m8YddJTKj8eRNO7hHfQa0TCOZi7dEEtnnmrREMb0EFIzmPQ==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -9741,9 +11348,9 @@ } }, "node_modules/@wordpress/redux-routine": { - "version": "5.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.35.0.tgz", - "integrity": "sha512-qc3MLyPWzpujvrP1wVg3xCAuZF+BItGSIIOikMk6xLN63FlNRxjh88gZ65evjU47Ik5KOjYqx3bt/GFdmzJOxw==", + "version": "5.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-5.34.0.tgz", + "integrity": "sha512-OYODJsho0wwCGrzEutelzBQpWHDS0quwJPGqx4TIWgoBnQtObcPyeqXDMGDJXfAFYP1KT3iE7hsU280EASxpng==", "license": "GPL-2.0-or-later", "dependencies": { "is-plain-object": "^5.0.0", @@ -9759,19 +11366,19 @@ } }, "node_modules/@wordpress/rich-text": { - "version": "7.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.35.0.tgz", - "integrity": "sha512-GhR9unaSAeVd2UQ6/WgYyAfP/xSE4VD43XuxY6hV4LaU0Qobi/N38Pamkln4eMhORcY8RzNQSkpFX27Nj/fxTQ==", + "version": "7.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-7.34.0.tgz", + "integrity": "sha512-zlzrxCFrUjG4wBrEhK7CNXc8vk5Ynq5GE/BC4dXJtk+/EgFNaFtZmusJdHnJSJx46WPeBcDjZk4W7ozAbXzaiA==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/a11y": "^4.35.0", - "@wordpress/compose": "^7.35.0", - "@wordpress/data": "^10.35.0", - "@wordpress/deprecated": "^4.35.0", - "@wordpress/element": "^6.35.0", - "@wordpress/escape-html": "^3.35.0", - "@wordpress/i18n": "^6.8.0", - "@wordpress/keycodes": "^4.35.0", + "@wordpress/a11y": "^4.34.0", + "@wordpress/compose": "^7.34.0", + "@wordpress/data": "^10.34.0", + "@wordpress/deprecated": "^4.34.0", + "@wordpress/element": "^6.34.0", + "@wordpress/escape-html": "^3.34.0", + "@wordpress/i18n": "^6.7.0", + "@wordpress/keycodes": "^4.34.0", "colord": "2.9.3", "memize": "^2.1.0" }, @@ -9784,12 +11391,12 @@ } }, "node_modules/@wordpress/undo-manager": { - "version": "1.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.35.0.tgz", - "integrity": "sha512-WyJWGLhLvkB2FF/o+QmgAoPo3NTEi5HQDwYbSEpw1pUZm7W3U/QwcaW6cWW3D/9OUtnHY4kfMGxrI5del2tYyA==", + "version": "1.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-1.34.0.tgz", + "integrity": "sha512-NQ/LGpaFoEYCKA0Uyg7RO04wx1MF27Jdv2S2tS81sFUO2/L0FJKyW1AQptx7SGEMIxgH9Sn4XIOdsQmLE4nGww==", "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/is-shallow-equal": "^5.35.0" + "@wordpress/is-shallow-equal": "^5.34.0" }, "engines": { "node": ">=18.12.0", @@ -9797,9 +11404,9 @@ } }, "node_modules/@wordpress/url": { - "version": "4.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.35.0.tgz", - "integrity": "sha512-h6KK0OePnc64T50BwVWmQb7xmcMW0XDtfh+1m/a0tlzXGLU4TnBjUUs+a0h0y6Tdla14lc2BtbLJLFwky06vbg==", + "version": "4.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-4.34.0.tgz", + "integrity": "sha512-gsBKwOQsn2bxcQjMnrHqKNgvSpSimP7fCOKbSoi+ALYmqybECLtadWTQJi/nNk06xzQrcX10xIhykJs3mks4yg==", "license": "GPL-2.0-or-later", "dependencies": { "remove-accents": "^0.5.0" @@ -9810,9 +11417,9 @@ } }, "node_modules/@wordpress/warning": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.35.0.tgz", - "integrity": "sha512-2UGZuHenf84UHdotBxv9ZCtlsFIy5u4QTUPBnx1gH4N9zEuJs+JiCtlOzgcl0JzT3xFK5y3cXLLVqlhf8tDMBQ==", + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-3.34.0.tgz", + "integrity": "sha512-WemuVXjaekzCDsWbDPj/RZSy44mIjPIy35DaoJgfLcgkXMH2GRBRSomhZMkWyGatD39vdXm0nqe95LsLDqrwCg==", "license": "GPL-2.0-or-later", "engines": { "node": ">=18.12.0", @@ -22276,13 +23883,13 @@ } }, "node_modules/playwright": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz", - "integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz", + "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.52.0" + "playwright-core": "1.56.1" }, "bin": { "playwright": "cli.js" @@ -22295,9 +23902,9 @@ } }, "node_modules/playwright-core": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz", - "integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==", + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -23327,11 +24934,6 @@ "node": ">=4" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" - }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -27365,15 +28967,6 @@ "wp-error": "^1.3.0" } }, - "node_modules/wpcom-xhr-request/node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -27636,6 +29229,7 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" From 7b1c743f45297ebf6be8222df19ff9e20794d8e0 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Mon, 17 Nov 2025 10:58:05 +0100 Subject: [PATCH 17/20] Install inquirer dependency again --- package-lock.json | 239 +++++++++++++++++++--------------------------- package.json | 2 +- 2 files changed, 98 insertions(+), 143 deletions(-) diff --git a/package-lock.json b/package-lock.json index e72998835d..66ab6503fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "@automattic/interpolate-components": "^1.2.1", "@formatjs/intl-locale": "^3.4.5", "@formatjs/intl-localematcher": "^0.5.4", + "@inquirer/prompts": "^7.10.1", "@php-wasm/node": "^3.0.19", "@php-wasm/scopes": "^3.0.19", "@php-wasm/universal": "^3.0.19", @@ -4842,29 +4843,25 @@ } }, "node_modules/@inquirer/ansi": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.1.tgz", - "integrity": "sha512-yqq0aJW/5XPhi5xOAL1xRCpe1eh8UFVgYFpFsjEqmIR8rKLyP+HINvFXwUaxYICflJrVlxnp7lLN6As735kVpw==", - "dev": true, + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" } }, "node_modules/@inquirer/checkbox": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.0.tgz", - "integrity": "sha512-5+Q3PKH35YsnoPTh75LucALdAxom6xh5D1oeY561x4cqBuH24ZFVyFREPe14xgnrtmGu3EEt1dIi60wRVSnGCw==", - "dev": true, + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -4879,15 +4876,13 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.19", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.19.tgz", - "integrity": "sha512-wQNz9cfcxrtEnUyG5PndC8g3gZ7lGDBzmWiXZkX8ot3vfZ+/BLjR8EvyGX4YzQLeVqtAlY/YScZpW7CW8qMoDQ==", - "dev": true, + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -4902,21 +4897,19 @@ } }, "node_modules/@inquirer/core": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.0.tgz", - "integrity": "sha512-Uv2aPPPSK5jeCplQmQ9xadnFx2Zhj9b5Dj7bU6ZeCdDNNY11nhYy4btcSdtDguHqCT2h5oNeQTcUNSGGLA7NTA==", - "dev": true, + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", "cli-width": "^4.1.0", "mute-stream": "^2.0.0", "signal-exit": "^4.1.0", "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.2" + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -4934,9 +4927,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">= 12" } @@ -4945,9 +4936,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", - "dev": true, "license": "ISC", - "peer": true, "engines": { "node": "^18.17.0 || >=20.5.0" } @@ -4956,9 +4945,7 @@ "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", - "peer": true, "engines": { "node": ">=14" }, @@ -4970,9 +4957,7 @@ "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", - "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -4984,9 +4969,7 @@ "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, "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -4997,16 +4980,14 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.21", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.21.tgz", - "integrity": "sha512-MjtjOGjr0Kh4BciaFShYpZ1s9400idOdvQ5D7u7lE6VztPFoyLcVNE5dXBmEEIQq5zi4B9h2kU+q7AVBxJMAkQ==", - "dev": true, + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/external-editor": "^1.0.2", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -5021,16 +5002,14 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.21.tgz", - "integrity": "sha512-+mScLhIcbPFmuvU3tAGBed78XvYHSvCl6dBiYMlzCLhpr0bzGzd8tfivMMeqND6XZiaZ1tgusbUHJEfc6YzOdA==", - "dev": true, + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -5045,14 +5024,12 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.2.tgz", - "integrity": "sha512-yy9cOoBnx58TlsPrIxauKIFQTiyH+0MK4e97y4sV9ERbI+zDxw7i2hxHLCIEGIE/8PPvDxGhgzIOTSOWcs6/MQ==", - "dev": true, + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "license": "MIT", - "peer": true, "dependencies": { - "chardet": "^2.1.0", + "chardet": "^2.1.1", "iconv-lite": "^0.7.0" }, "engines": { @@ -5071,17 +5048,13 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dev": true, "license": "MIT", - "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -5094,25 +5067,22 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.14.tgz", - "integrity": "sha512-DbFgdt+9/OZYFM+19dbpXOSeAstPy884FPy1KjDu4anWwymZeOYhMY1mdFri172htv6mvc/uvIAAi7b7tvjJBQ==", - "dev": true, + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/@inquirer/input": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.2.5.tgz", - "integrity": "sha512-7GoWev7P6s7t0oJbenH0eQ0ThNdDJbEAEtVt9vsrYZ9FulIokvd823yLyhQlWHJPGce1wzP53ttfdCZmonMHyA==", - "dev": true, + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -5127,15 +5097,13 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.21.tgz", - "integrity": "sha512-5QWs0KGaNMlhbdhOSCFfKsW+/dcAVC2g4wT/z2MCiZM47uLgatC5N20kpkDQf7dHx+XFct/MJvvNGy6aYJn4Pw==", - "dev": true, + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -5150,16 +5118,14 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.21", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.21.tgz", - "integrity": "sha512-xxeW1V5SbNFNig2pLfetsDb0svWlKuhmr7MPJZMYuDnCTkpVBI+X/doudg4pznc1/U+yYmWFFOi4hNvGgUo7EA==", - "dev": true, + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -5174,23 +5140,21 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.9.0.tgz", - "integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==", - "dev": true, + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/checkbox": "^4.3.0", - "@inquirer/confirm": "^5.1.19", - "@inquirer/editor": "^4.2.21", - "@inquirer/expand": "^4.0.21", - "@inquirer/input": "^4.2.5", - "@inquirer/number": "^3.0.21", - "@inquirer/password": "^4.0.21", - "@inquirer/rawlist": "^4.1.9", - "@inquirer/search": "^3.2.0", - "@inquirer/select": "^4.4.0" + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" }, "engines": { "node": ">=18" @@ -5205,16 +5169,14 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.9.tgz", - "integrity": "sha512-AWpxB7MuJrRiSfTKGJ7Y68imYt8P9N3Gaa7ySdkFj1iWjr6WfbGAhdZvw/UnhFXTHITJzxGUI9k8IX7akAEBCg==", - "dev": true, + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -5229,17 +5191,15 @@ } }, "node_modules/@inquirer/search": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.0.tgz", - "integrity": "sha512-a5SzB/qrXafDX1Z4AZW3CsVoiNxcIYCzYP7r9RzrfMpaLpB+yWi5U8BWagZyLmwR0pKbbL5umnGRd0RzGVI8bQ==", - "dev": true, + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -5254,18 +5214,16 @@ } }, "node_modules/@inquirer/select": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.0.tgz", - "integrity": "sha512-kaC3FHsJZvVyIjYBs5Ih8y8Bj4P/QItQWrZW22WJax7zTN+ZPXVGuOM55vzbdCP9zKUiBd9iEJVdesujfF+cAA==", - "dev": true, + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", "license": "MIT", - "peer": true, "dependencies": { - "@inquirer/ansi": "^1.0.1", - "@inquirer/core": "^10.3.0", - "@inquirer/figures": "^1.0.14", - "@inquirer/type": "^3.0.9", - "yoctocolors-cjs": "^2.1.2" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" @@ -5280,12 +5238,10 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.9.tgz", - "integrity": "sha512-QPaNt/nmE2bLGQa9b7wwyRJoLZ7pN6rcyXvzU0YCmivmJyq1BVo94G98tStRWkoD1RgDX5C+dPlhhHzNdu/W/w==", - "dev": true, + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -29229,7 +29185,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", - "dev": true, "license": "MIT", "engines": { "node": ">=18" diff --git a/package.json b/package.json index 6cffd8dd9c..4be42f264e 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "@automattic/interpolate-components": "^1.2.1", "@formatjs/intl-locale": "^3.4.5", "@formatjs/intl-localematcher": "^0.5.4", - "@inquirer/prompts": "^7.9.0", + "@inquirer/prompts": "^7.10.1", "@php-wasm/node": "^3.0.19", "@php-wasm/scopes": "^3.0.19", "@php-wasm/universal": "^3.0.19", From d8feb6b34c679e84d68945d022e1a54508fb9e45 Mon Sep 17 00:00:00 2001 From: Fredrik Rombach Ekelund Date: Mon, 17 Nov 2025 11:12:18 +0100 Subject: [PATCH 18/20] Tweak --- cli/lib/browser.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cli/lib/browser.ts b/cli/lib/browser.ts index 90902f8164..7a9c44dd28 100644 --- a/cli/lib/browser.ts +++ b/cli/lib/browser.ts @@ -1,5 +1,4 @@ import { spawn } from 'child_process'; -import { __ } from '@wordpress/i18n'; /** * Opens the default browser with the specified URL @@ -31,7 +30,7 @@ export async function openBrowser( url: string ): Promise< void > { args = [ url ]; break; default: - return Promise.reject( new Error( __( 'Unsupported platform' ) ) ); + return Promise.reject( new Error( 'Unsupported platform' ) ); } return new Promise( ( resolve, reject ) => { From 1cc1fe0e3f7ec7442ad950312caf71eab21631d6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 10:25:32 +0000 Subject: [PATCH 19/20] docs: Update CLI documentation for auth commands Add documentation for `auth logout` and `auth status` commands. Co-authored-by: Fredrik Rombach Ekelund --- docs/ai-instructions.md | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/ai-instructions.md b/docs/ai-instructions.md index cc8ebe791b..715add8704 100644 --- a/docs/ai-instructions.md +++ b/docs/ai-instructions.md @@ -81,6 +81,62 @@ node dist/cli/main.js auth login - Authentication is shared between the CLI and the Studio desktop app - If the browser fails to open, the URL will be displayed for manual opening +#### `studio auth logout` +Log out and clear WordPress.com authentication. + +**Usage:** +```bash +node dist/cli/main.js auth logout +``` + +**Description:** +This command logs you out of WordPress.com by: +1. Revoking the auth token with WordPress.com +2. Removing the token from your app data +3. Clearing authentication shared with the Studio desktop app + +**Options:** +- None required + +**Example:** +```bash +npm run cli:build +node dist/cli/main.js auth logout +``` + +**Notes:** +- If already logged out, the command will notify you +- This affects both the CLI and the Studio desktop app + +#### `studio auth status` +Check authentication status with WordPress.com. + +**Usage:** +```bash +node dist/cli/main.js auth status +``` + +**Description:** +This command checks your authentication status by: +1. Reading the auth token from app data +2. Making an API request to verify the token is valid +3. Displaying your WordPress.com username if authenticated + +**Options:** +- None required + +**Example:** +```bash +npm run cli:build +node dist/cli/main.js auth status +# Output: Successfully authenticated with WordPress.com as `username` +# OR: Authentication token is invalid or expired +``` + +**Notes:** +- Useful for verifying authentication before running other commands +- Displays your WordPress.com username when authenticated + ### Preview Site Commands See the existing preview site commands (create, list, delete, update) in `cli/commands/preview/`. From 32337205c905bf0e547f975279aa4058d70067a1 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Mon, 17 Nov 2025 16:05:09 +0000 Subject: [PATCH 20/20] docs: Add CLI documentation for auth status command Co-authored-by: Fredrik Rombach Ekelund --- docs/ai-instructions.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/docs/ai-instructions.md b/docs/ai-instructions.md index 242ae08db4..75665766ed 100644 --- a/docs/ai-instructions.md +++ b/docs/ai-instructions.md @@ -110,6 +110,37 @@ node dist/cli/main.js auth logout - Logout is shared between the CLI and the Studio desktop app - The token is revoked on WordPress.com, invalidating all sessions using that token +#### `studio auth status` +Check authentication status and display the current WordPress.com username. + +**Usage:** +```bash +node dist/cli/main.js auth status +``` + +**Description:** +This command checks if you are currently authenticated with WordPress.com by: +1. Reading the authentication token from your local app data +2. Verifying the token's validity by making an API request to WordPress.com +3. Displaying your WordPress.com username if authenticated + +**Options:** +- None required + +**Example:** +```bash +npm run cli:build +node dist/cli/main.js auth status +# Output when authenticated: ✓ Successfully authenticated with WordPress.com as `username` +# Output when not authenticated: ✗ Authentication token is invalid or expired +``` + +**Notes:** +- The command will check both token existence and validity +- If the token has expired (older than 2 weeks), you'll need to log in again +- Authentication state is shared between the CLI and the Studio desktop app +- No authentication token will be created; use `auth login` if not authenticated + ### Preview Site Commands See the existing preview site commands (create, list, delete, update) in `cli/commands/preview/`.