From 7d710a0433a0ae210f0219e55cc3488c2a0d264f Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 17:25:29 -0500 Subject: [PATCH 1/8] Fixed pre-commit lint hook routing for all workspaces (#27724) no ref - `.lintstagedrc.cjs` previously maintained a manual `SCOPED_WORKSPACES` allowlist; files outside the listed workspaces fell through to a root `eslint` invocation. - That root path fails for workspaces whose eslint configs enable `eslint-plugin-tailwindcss`. The plugin resolves tailwindcss via `local-pkg.getPackageInfoSync("tailwindcss")` from `process.cwd()`, and tailwindcss is not a root dependency. Result: `Error: Could not find tailwindcss`. - The allowlist was only extended reactively (e.g. `apps/posts` / `apps/shade` in #26970 when Tailwind v4 + plugin v4-beta surfaced the failure). Seven other workspaces have been latently broken for local commits ever since: `apps/activitypub`, `apps/admin-x-design-system`, `apps/admin-x-framework`, `apps/admin-x-settings`, `apps/comments-ui`, `apps/signup-form`, `apps/stats`. CI doesn't notice because `.github/hooks/pre-commit.bash` exits early under `$CI`. - Replaced the allowlist with auto-discovery: walk up from each staged file to its nearest `package.json` and run `pnpm --dir exec eslint`. New workspaces and new tailwindcss-plugin adopters are picked up automatically; the dichotomy between "scoped" and "root" eslint goes away. - Every workspace in the repo has an eslint config (either `.eslintrc.*` / `eslint.config.*` or an inline `eslintConfig` in `package.json`), so scoped runs always find a config. --- .lintstagedrc.cjs | 129 ++++++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 45 deletions(-) diff --git a/.lintstagedrc.cjs b/.lintstagedrc.cjs index 43aefb95792..58ca03aef53 100644 --- a/.lintstagedrc.cjs +++ b/.lintstagedrc.cjs @@ -1,69 +1,108 @@ const path = require('path'); +const fs = require('fs'); -const SCOPED_WORKSPACES = [ - 'e2e', - 'apps/admin', - 'apps/posts', - 'apps/shade' -]; +const ROOT = process.cwd(); -function normalize(file) { - return file.split(path.sep).join('/'); -} - -function isInWorkspace(file, workspace) { - const normalizedFile = normalize(path.relative(process.cwd(), file)); - const normalizedWorkspace = normalize(workspace); - - return normalizedFile === normalizedWorkspace || normalizedFile.startsWith(`${normalizedWorkspace}/`); +function normalize(p) { + return p.split(path.sep).join('/'); } function shellQuote(value) { return `'${value.replace(/'/g, `'\\''`)}'`; } -function buildScopedEslintCommand(workspace, files) { - if (files.length === 0) { - return null; +// Parse the `packages:` list from pnpm-workspace.yaml. We only need the simple +// glob shapes pnpm allows here (`apps/*`, `ghost/*`, `e2e`); anything fancier +// would warrant a real YAML parser. +function loadWorkspacePatterns() { + const yaml = fs.readFileSync(path.join(ROOT, 'pnpm-workspace.yaml'), 'utf8'); + const lines = yaml.split('\n'); + const start = lines.findIndex(line => /^packages:\s*$/.test(line)); + if (start === -1) { + return []; } + const patterns = []; + for (let i = start + 1; i < lines.length; i++) { + const line = lines[i]; + if (/^\s+-\s+/.test(line)) { + const match = line.match(/^\s+-\s+['"]?([^'"\s]+)['"]?\s*$/); + if (match) { + patterns.push(match[1]); + } + } else if (line.trim() !== '' && !/^\s/.test(line)) { + break; + } + } + return patterns; +} - const relativeFiles = files - .map(file => normalize(path.relative(workspace, file))) - .map(shellQuote) - .join(' '); - - return `pnpm --dir ${shellQuote(workspace)} exec eslint --cache ${relativeFiles}`; +function expandPattern(pattern) { + const segments = pattern.split('/'); + let candidates = ['']; + for (const segment of segments) { + const next = []; + for (const base of candidates) { + const dir = base ? path.join(ROOT, base) : ROOT; + if (segment === '*') { + if (!fs.existsSync(dir)) { + continue; + } + for (const entry of fs.readdirSync(dir, {withFileTypes: true})) { + if (entry.isDirectory()) { + next.push(base ? `${base}/${entry.name}` : entry.name); + } + } + } else { + const candidate = base ? `${base}/${segment}` : segment; + if (fs.existsSync(path.join(ROOT, candidate))) { + next.push(candidate); + } + } + } + candidates = next; + } + return candidates; } -function buildRootEslintCommand(files) { - if (files.length === 0) { - return null; +const WORKSPACES = new Set( + loadWorkspacePatterns().flatMap(expandPattern) +); + +function findWorkspace(file) { + let dir = path.dirname(path.resolve(file)); + while (dir.startsWith(ROOT) && dir !== ROOT) { + const rel = normalize(path.relative(ROOT, dir)); + if (WORKSPACES.has(rel)) { + return rel; + } + dir = path.dirname(dir); } + return null; +} - const quotedFiles = files.map(file => shellQuote(normalize(file))).join(' '); - return `eslint --cache ${quotedFiles}`; +function buildCommand(workspace, files) { + const base = workspace ? path.join(ROOT, workspace) : ROOT; + const relativeFiles = files + .map(file => normalize(path.relative(base, file))) + .map(shellQuote) + .join(' '); + const dirArg = workspace ? `--dir ${shellQuote(workspace)} ` : ''; + return `pnpm ${dirArg}exec eslint --cache -- ${relativeFiles}`; } module.exports = { '*.{js,ts,tsx,jsx,cjs}': (files) => { - const workspaceGroups = new Map(SCOPED_WORKSPACES.map(workspace => [workspace, []])); - const rootFiles = []; - + const groups = new Map(); for (const file of files) { - const workspace = SCOPED_WORKSPACES.find(candidate => isInWorkspace(file, candidate)); - - if (workspace) { - workspaceGroups.get(workspace).push(file); - } else { - rootFiles.push(file); + const workspace = findWorkspace(file); + const key = workspace ?? ''; + if (!groups.has(key)) { + groups.set(key, []); } + groups.get(key).push(file); } - - return [ - ...SCOPED_WORKSPACES - .map(workspace => buildScopedEslintCommand(workspace, workspaceGroups.get(workspace))) - .filter(Boolean), - buildRootEslintCommand(rootFiles) - ].filter(Boolean); + return [...groups.entries()].map(([workspace, wsFiles]) => + buildCommand(workspace || null, wsFiles) + ); } }; From 9f23ba7dbac85912a52d5e5b64fd6e715c18215c Mon Sep 17 00:00:00 2001 From: Evan Hahn Date: Wed, 6 May 2026 17:36:58 -0500 Subject: [PATCH 2/8] Made admin API middleware test more realistic (#27729) ref 986f78ec062eef13c25225ea091407eaa53486a9 Let's test this middleware without stubbing. --- .../server/web/api/admin/middleware.test.js | 409 ++++++++---------- 1 file changed, 192 insertions(+), 217 deletions(-) diff --git a/ghost/core/test/unit/server/web/api/admin/middleware.test.js b/ghost/core/test/unit/server/web/api/admin/middleware.test.js index 172e8fa5233..1ff14aed245 100644 --- a/ghost/core/test/unit/server/web/api/admin/middleware.test.js +++ b/ghost/core/test/unit/server/web/api/admin/middleware.test.js @@ -1,248 +1,223 @@ -const assert = require('node:assert/strict'); -const sinon = require('sinon'); -const errors = require('@tryghost/errors'); +const express = require('express'); +const request = require('supertest'); // Module under test const middleware = require('../../../../../../core/server/web/api/endpoints/admin/middleware'); -describe('Admin API Middleware', function () { - describe('tokenPermissionCheck', function () { - let req, res, next; - - beforeEach(function () { - req = { - method: 'GET', - path: '/posts/', - url: '/posts', - query: {} - }; - res = {}; - next = sinon.stub(); - }); +const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; + +const createApiKey = (userId) => { + return { + get(field) { + if (field === 'user_id') { + return userId; + } + } + }; +}; + +const createApp = ({apiKey = null, user = null} = {}) => { + const app = express(); + + app.use((req, res, next) => { + req.api_key = apiKey; + req.user = user; + next(); + }); - afterEach(function () { - sinon.restore(); - }); + app.use(tokenPermissionCheck); - describe('User Authentication (no API key)', function () { - it('should call next() when user is authenticated without API key', function () { - req.api_key = null; - req.user = {id: 'abcd1234'}; + app.use((req, res) => { + res.json({ok: true}); + }); - // Get the notImplemented middleware from the authAdminApi array - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); + app.use((err, req, res, _next) => { + void _next; - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); + res.status(err.statusCode || 500).json({ + error: { + message: err.message, + statusCode: err.statusCode + } }); + }); - describe('Staff Token Authentication', function () { - beforeEach(function () { - // Mock api_key as a Bookshelf model with get() method - req.api_key = { - get: sinon.stub().withArgs('user_id').returns('abcd1234') - }; - req.user = {id: 'abcd1234', role: 'Editor'}; - }); - - it('should allow staff tokens to access regular endpoints', function () { - req.path = '/posts/'; - req.method = 'GET'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); - - it('should block staff tokens from DELETE /db/ endpoint', function () { - req.path = '/db/'; - req.method = 'DELETE'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); - assert.equal(error.message, 'Staff tokens are not allowed to access this endpoint'); - }); - - it('should block staff tokens from PUT /users/owner/ endpoint', function () { - req.path = '/users/owner/'; - req.method = 'PUT'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); - assert.equal(error.message, 'Staff tokens are not allowed to access this endpoint'); - }); - - it('should allow staff tokens to POST to /db/ endpoint', function () { - req.path = '/db/'; - req.method = 'POST'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); - - it('should allow staff tokens to GET /users/owner/ endpoint', function () { - req.path = '/users/owner/'; - req.method = 'GET'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); - - it('should allow staff tokens to access endpoints without trailing slash', function () { - req.path = '/posts'; - req.method = 'GET'; - - const notImplemented = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - notImplemented(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); - - it('should block staff tokens from DELETE /db (without trailing slash)', function () { - req.path = '/db'; - req.method = 'DELETE'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); + return app; +}; - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); - assert.equal(error.message, 'Staff tokens are not allowed to access this endpoint'); +describe('Admin API Middleware', function () { + describe('tokenPermissionCheck', function () { + describe('User Authentication (no API key)', function () { + it('should call next() when user is authenticated without API key', async function () { + await request(createApp({ + user: {id: 'abcd1234'} + })) + .get('/posts') + .expect(200) + .expect({ok: true}); }); + }); - it('should block staff tokens from PUT /users/owner (without trailing slash)', function () { - req.path = '/users/owner'; - req.method = 'PUT'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); - assert.equal(error.message, 'Staff tokens are not allowed to access this endpoint'); + describe('Staff Token Authentication', function () { + const app = createApp({ + apiKey: createApiKey('abcd1234'), + user: {id: 'abcd1234', role: 'Editor'} + }); + + it('should allow staff tokens to access regular endpoints', async function () { + await request(app) + .get('/posts/') + .expect(200) + .expect({ok: true}); + }); + + it('should block staff tokens from DELETE /db/ endpoint', async function () { + await request(app) + .delete('/db/') + .expect(403) + .expect({ + error: { + message: 'Staff tokens are not allowed to access this endpoint', + statusCode: 403 + } + }); + }); + + it('should block staff tokens from PUT /users/owner/ endpoint', async function () { + await request(app) + .put('/users/owner/') + .expect(403) + .expect({ + error: { + message: 'Staff tokens are not allowed to access this endpoint', + statusCode: 403 + } + }); + }); + + it('should allow staff tokens to POST to /db/ endpoint', async function () { + await request(app) + .post('/db/') + .expect(200) + .expect({ok: true}); + }); + + it('should allow staff tokens to GET /users/owner/ endpoint', async function () { + await request(app) + .get('/users/owner/') + .expect(200) + .expect({ok: true}); + }); + + it('should allow staff tokens to access endpoints without trailing slash', async function () { + await request(app) + .get('/posts') + .expect(200) + .expect({ok: true}); + }); + + it('should block staff tokens from DELETE /db (without trailing slash)', async function () { + await request(app) + .delete('/db') + .expect(403) + .expect({ + error: { + message: 'Staff tokens are not allowed to access this endpoint', + statusCode: 403 + } + }); + }); + + it('should block staff tokens from PUT /users/owner (without trailing slash)', async function () { + await request(app) + .put('/users/owner') + .expect(403) + .expect({ + error: { + message: 'Staff tokens are not allowed to access this endpoint', + statusCode: 403 + } + }); }); }); describe('Integration Token Authentication', function () { - beforeEach(function () { - // Mock api_key as a Bookshelf model with get() method that returns null for user_id - req.api_key = { - get: sinon.stub().withArgs('user_id').returns(null) - }; - req.user = null; // Integration tokens don't have associated users - }); - - it('should allow integration tokens to access allowlisted endpoints', function () { - req.url = '/posts'; - req.method = 'GET'; - - const notImplemented = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - notImplemented(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); - - it('should block integration tokens from non-allowlisted endpoints', function () { - req.url = '/non-existent'; - req.method = 'GET'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); - assert.equal(error.statusCode, 403); - }); - - it('should allow integration tokens to POST to /db endpoint', function () { - req.url = '/db'; - req.method = 'POST'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); - }); - - it('should block integration tokens from DELETE /db endpoint', function () { - req.url = '/db'; - req.method = 'DELETE'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); - assert.equal(error.statusCode, 403); + const app = createApp({ + apiKey: createApiKey(null) + }); + + it('should allow integration tokens to access allowlisted endpoints', async function () { + await request(app) + .get('/posts') + .expect(200) + .expect({ok: true}); + }); + + it('should block integration tokens from non-allowlisted endpoints', async function () { + await request(app) + .get('/non-existent') + .expect(403) + .expect({ + error: { + message: 'API tokens do not have permission to access this endpoint', + statusCode: 403 + } + }); + }); + + it('should allow integration tokens to POST to /db endpoint', async function () { + await request(app) + .post('/db') + .expect(200) + .expect({ok: true}); + }); + + it('should block integration tokens from DELETE /db endpoint', async function () { + await request(app) + .delete('/db') + .expect(403) + .expect({ + error: { + message: 'API tokens do not have permission to access this endpoint', + statusCode: 403 + } + }); }); }); describe('God Mode', function () { - it('should allow access in development with god_mode query param', function () { - const originalEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'development'; - - req.api_key = { - get: sinon.stub().withArgs('user_id').returns(null) - }; - req.user = null; - req.query.god_mode = 'true'; - req.url = '/non-existent'; - - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); - - sinon.assert.calledOnce(next); - assert.equal(next.firstCall.args.length, 0); + const originalEnv = process.env.NODE_ENV; + afterEach(function () { process.env.NODE_ENV = originalEnv; }); - it('should not allow god mode in production', function () { - const originalEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - - req.api_key = { - get: sinon.stub().withArgs('user_id').returns(null) - }; - req.user = null; - req.query.god_mode = 'true'; - req.url = '/non-existent'; + it('should allow access in development with god_mode query param', async function () { + process.env.NODE_ENV = 'development'; - const tokenPermissionCheck = middleware.authAdminApi[middleware.authAdminApi.length - 1]; - tokenPermissionCheck(req, res, next); + await request(createApp({ + apiKey: createApiKey(null) + })) + .get('/non-existent?god_mode=true') + .expect(200) + .expect({ok: true}); + }); - sinon.assert.calledOnce(next); - const error = next.firstCall.args[0]; - assert.equal(error instanceof errors.NoPermissionError, true); + it('should not allow god mode in production', async function () { + process.env.NODE_ENV = 'production'; - process.env.NODE_ENV = originalEnv; + await request(createApp({ + apiKey: createApiKey(null) + })) + .get('/non-existent?god_mode=true') + .expect(403) + .expect({ + error: { + message: 'API tokens do not have permission to access this endpoint', + statusCode: 403 + } + }); }); }); }); -}); \ No newline at end of file +}); From e4184350216e571719d06d37375752bde7263502 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 18:44:40 -0500 Subject: [PATCH 3/8] Cleaned workspace dependency declarations (#27739) no ref Two related dep-contract hygiene fixes the post-knip-baseline audit surfaced. Both came out of running `pnpm knip --debug` against `main` after #27720 landed and verifying each entry by hand. --- apps/admin-x-settings/package.json | 1 - apps/shade/package.json | 1 - apps/signup-form/package.json | 4 +- apps/stats/package.json | 2 - e2e/package.json | 1 - ghost/core/package.json | 8 +- ghost/i18n/package.json | 1 + pnpm-lock.yaml | 396 ++--------------------------- 8 files changed, 35 insertions(+), 379 deletions(-) diff --git a/apps/admin-x-settings/package.json b/apps/admin-x-settings/package.json index 7ecc453f9a6..1b9383c2495 100644 --- a/apps/admin-x-settings/package.json +++ b/apps/admin-x-settings/package.json @@ -79,7 +79,6 @@ "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.24", "eslint-plugin-tailwindcss": "4.0.0-beta.0", - "stylelint": "15.11.0", "tailwindcss": "^4.2.2", "vite": "5.4.21", "vite-plugin-css-injected-by-js": "3.5.2", diff --git a/apps/shade/package.json b/apps/shade/package.json index 59155d40e19..8bbbff67abc 100644 --- a/apps/shade/package.json +++ b/apps/shade/package.json @@ -75,7 +75,6 @@ "@storybook/addon-links": "10.3.5", "@storybook/react-vite": "10.3.5", "@tailwindcss/postcss": "4.2.1", - "@tailwindcss/vite": "4.2.1", "@testing-library/react": "14.3.1", "@types/node": "22.19.17", "@types/react-world-flags": "1.6.0", diff --git a/apps/signup-form/package.json b/apps/signup-form/package.json index c79ca510263..5e4fe6a23ff 100644 --- a/apps/signup-form/package.json +++ b/apps/signup-form/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/signup-form", - "version": "0.3.20", + "version": "0.3.21", "license": "MIT", "repository": "https://github.com/TryGhost/Ghost", "author": "Ghost Foundation", @@ -54,9 +54,7 @@ "jsdom": "28.1.0", "postcss": "8.5.6", "postcss-import": "16.1.1", - "prop-types": "15.8.1", "storybook": "10.3.5", - "stylelint": "15.11.0", "tailwindcss": "3.4.18", "vite": "5.4.21", "vite-plugin-svgr": "3.3.0", diff --git a/apps/stats/package.json b/apps/stats/package.json index 84ff7e0a63d..5c8aaaeea3a 100644 --- a/apps/stats/package.json +++ b/apps/stats/package.json @@ -42,7 +42,6 @@ "devDependencies": { "@faker-js/faker": "9.9.0", "@playwright/test": "1.59.1", - "@tanstack/react-query": "4.36.1", "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "14.3.1", "@types/jest": "29.5.14", @@ -51,7 +50,6 @@ "@vitest/coverage-v8": "^1.6.1", "@vitejs/plugin-react": "4.7.0", "dotenv": "17.3.1", - "msw": "2.12.14", "tailwindcss": "^4.2.2", "vite": "5.4.21", "vite-plugin-svgr": "4.5.0", diff --git a/e2e/package.json b/e2e/package.json index 7a68ad6b539..60ace32b640 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -36,7 +36,6 @@ "@types/dockerode": "3.3.47", "@types/express": "4.17.25", "busboy": "^1.6.0", - "c8": "10.1.3", "dockerode": "4.0.10", "dotenv": "17.3.1", "eslint": "catalog:", diff --git a/ghost/core/package.json b/ghost/core/package.json index bf5965a5953..aafbee88aa7 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -264,9 +264,12 @@ "@types/on-headers": "1.0.4", "@types/sinon": "17.0.4", "@types/supertest": "6.0.3", + "bunyan": "1.8.15", "c8": "10.1.3", + "chai": "4.5.0", "cli-progress": "3.12.0", "cssnano": "7.1.1", + "esbuild": "0.25.12", "expect": "29.7.0", "form-data": "4.0.5", "html-minifier": "4.0.0", @@ -280,15 +283,16 @@ "mock-knex": "TryGhost/mock-knex#68948e11b0ea4fe63456098dfdc169bea7f62009", "nock": "13.5.6", "nodemon": "3.1.14", - "papaparse": "5.5.3", "postcss": "8.5.6", "postcss-cli": "11.0.1", + "qs": "6.14.2", "rewire": "9.0.1", "sinon": "18.0.1", "supertest": "6.3.4", "tmp": "0.2.5", "tsx": "4.21.0", - "typescript": "5.9.3" + "typescript": "5.9.3", + "validator": "13.12.0" }, "nx": { "tags": [ diff --git a/ghost/i18n/package.json b/ghost/i18n/package.json index 8eb89b65d6e..f6f6594446a 100644 --- a/ghost/i18n/package.json +++ b/ghost/i18n/package.json @@ -32,6 +32,7 @@ ], "devDependencies": { "c8": "10.1.3", + "fs-extra": "11.3.4", "glob": "^13.0.6", "i18next-parser": "9.3.0", "mocha": "11.7.5" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d80bfeb2b73..739d1bab63f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -689,9 +689,6 @@ importers: eslint-plugin-tailwindcss: specifier: 4.0.0-beta.0 version: 4.0.0-beta.0(tailwindcss@4.2.2) - stylelint: - specifier: 15.11.0 - version: 15.11.0(typescript@5.9.3) tailwindcss: specifier: ^4.2.2 version: 4.2.2 @@ -1144,9 +1141,6 @@ importers: '@tailwindcss/postcss': specifier: 4.2.1 version: 4.2.1 - '@tailwindcss/vite': - specifier: 4.2.1 - version: 4.2.1(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) '@testing-library/react': specifier: 14.3.1 version: 14.3.1(@types/react@18.3.28)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -1280,15 +1274,9 @@ importers: postcss-import: specifier: 16.1.1 version: 16.1.1(postcss@8.5.6) - prop-types: - specifier: 15.8.1 - version: 15.8.1 storybook: specifier: 10.3.5 version: 10.3.5(@testing-library/dom@10.4.0)(prettier@2.8.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - stylelint: - specifier: 15.11.0 - version: 15.11.0(typescript@5.9.3) tailwindcss: specifier: 3.4.18 version: 3.4.18(tsx@4.21.0)(yaml@2.8.3) @@ -1393,9 +1381,6 @@ importers: '@playwright/test': specifier: 1.59.1 version: 1.59.1 - '@tanstack/react-query': - specifier: 4.36.1 - version: 4.36.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/jest-dom': specifier: 6.9.1 version: 6.9.1 @@ -1420,9 +1405,6 @@ importers: dotenv: specifier: 17.3.1 version: 17.3.1 - msw: - specifier: 2.12.14 - version: 2.12.14(@types/node@25.6.0)(typescript@5.9.3) tailwindcss: specifier: ^4.2.2 version: 4.2.2 @@ -1462,9 +1444,6 @@ importers: busboy: specifier: ^1.6.0 version: 1.6.0 - c8: - specifier: 10.1.3 - version: 10.1.3 dockerode: specifier: 4.0.10 version: 4.0.10 @@ -2406,15 +2385,24 @@ importers: '@types/supertest': specifier: 6.0.3 version: 6.0.3 + bunyan: + specifier: 1.8.15 + version: 1.8.15 c8: specifier: 10.1.3 version: 10.1.3 + chai: + specifier: 4.5.0 + version: 4.5.0 cli-progress: specifier: 3.12.0 version: 3.12.0 cssnano: specifier: 7.1.1 version: 7.1.1(postcss@8.5.6) + esbuild: + specifier: 0.25.12 + version: 0.25.12 expect: specifier: 29.7.0 version: 29.7.0 @@ -2457,6 +2445,9 @@ importers: postcss-cli: specifier: 11.0.1 version: 11.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0) + qs: + specifier: 6.14.2 + version: 6.14.2 rewire: specifier: 9.0.1 version: 9.0.1(jiti@2.6.1) @@ -2475,6 +2466,9 @@ importers: typescript: specifier: 5.9.3 version: 5.9.3 + validator: + specifier: 13.12.0 + version: 13.12.0 optionalDependencies: '@tryghost/html-to-mobiledoc': specifier: 3.3.1 @@ -2495,6 +2489,9 @@ importers: c8: specifier: 10.1.3 version: 10.1.3 + fs-extra: + specifier: 11.3.4 + version: 11.3.4 glob: specifier: ^13.0.6 version: 13.0.6 @@ -3619,12 +3616,6 @@ packages: '@csstools/css-parser-algorithms': ^4.0.0 '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-parser-algorithms@2.7.1': - resolution: {integrity: sha512-2SJS42gxmACHgikc1WGesXLIT8d/q2l0UFM7TaEeIzdFCE/FPMtTiizcPGGJtlPo2xuQzY09OhrLTzRxqJqwGw==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - '@csstools/css-tokenizer': ^2.4.1 - '@csstools/css-parser-algorithms@4.0.0': resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} engines: {node: '>=20.19.0'} @@ -3647,21 +3638,10 @@ packages: css-tree: optional: true - '@csstools/css-tokenizer@2.4.1': - resolution: {integrity: sha512-eQ9DIktFJBhGjioABJRtUucoWR2mwllurfnM8LuNGAqX3ViZXaUchqk+1s7jjtkFiT9ySdACsFEA3etErkALUg==} - engines: {node: ^14 || ^16 || >=18} - '@csstools/css-tokenizer@4.0.0': resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} engines: {node: '>=20.19.0'} - '@csstools/media-query-list-parser@2.1.13': - resolution: {integrity: sha512-XaHr+16KRU9Gf8XLi3q8kDlI18d5vzKSKCY510Vrtc9iNR0NJzbY9hhTmwhzYZj/ZwGL4VmB3TA9hJW0Um2qFA==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - '@csstools/css-parser-algorithms': ^2.7.1 - '@csstools/css-tokenizer': ^2.4.1 - '@csstools/postcss-cascade-layers@1.1.1': resolution: {integrity: sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==} engines: {node: ^12 || ^14 || >=16} @@ -3752,12 +3732,6 @@ packages: peerDependencies: postcss-selector-parser: ^6.0.10 - '@csstools/selector-specificity@3.1.1': - resolution: {integrity: sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==} - engines: {node: ^14 || ^16 || >=18} - peerDependencies: - postcss-selector-parser: ^6.0.13 - '@distributed-systems/callsite@1.1.1': resolution: {integrity: sha512-YSA3kWjClnLmFKNpdQCZlMQoWI4N6KpR/T4MaREEQczaehcagsVorT3YDV17KR6zuJXDs7f+kkSt1o/D6SufAQ==} @@ -9077,9 +9051,6 @@ packages: resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. - '@types/minimist@1.2.5': - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - '@types/mocha@10.0.10': resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} @@ -10004,10 +9975,6 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} - arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -10452,9 +10419,6 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - balanced-match@2.0.0: - resolution: {integrity: sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==} - balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} @@ -11068,10 +11032,6 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camelcase-keys@7.0.2: - resolution: {integrity: sha512-Rjs1H+A9R+Ig+4E/9oyB66UC5Mj9Xq3N//vcLf2WzgdTi/3gUu3Z9KoqmlrEG4VuuLK8wJHofxzdQXz/knhiYg==} - engines: {node: '>=12'} - camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -12122,10 +12082,6 @@ packages: peerDependencies: postcss: ^8.0.9 - css-functions-list@3.3.3: - resolution: {integrity: sha512-8HFEBPKhOpJPEPu70wJJetjKta86Gw9+CCyCnB3sui2qQfOvRyqBy4IKLKKAwdMpWb2lHXWk9Wb4Z6AmaUT1Pg==} - engines: {node: '>=12'} - css-has-pseudo@3.0.4: resolution: {integrity: sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==} engines: {node: ^12 || ^14 || >=16} @@ -12446,22 +12402,10 @@ packages: supports-color: optional: true - decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - decamelize@4.0.0: resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} engines: {node: '>=10'} - decamelize@5.0.1: - resolution: {integrity: sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==} - engines: {node: '>=10'} - decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} @@ -13983,10 +13927,6 @@ packages: fastboot-transform@0.1.3: resolution: {integrity: sha512-6otygPIJw1ARp1jJb+6KVO56iKBjhO+5x59RSC9qiZTbZRrv+HZAuP00KD3s+nWMvcFDemtdkugki9DNFTTwCQ==} - fastest-levenshtein@1.0.16: - resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} - engines: {node: '>= 4.9.1'} - fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -14035,10 +13975,6 @@ packages: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} - file-entry-cache@7.0.2: - resolution: {integrity: sha512-TfW7/1iI4Cy7Y8L6iqNdZQVvdXn0f8B4QcIXmkIbtTIe/Okm/nSlHb4IwGzRVOd3WfSieCgvf5cMzEfySAIl0g==} - engines: {node: '>=12.0.0'} - file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -14558,18 +14494,10 @@ packages: resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} engines: {node: '>=0.10.0'} - global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} - global-prefix@1.0.2: resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} engines: {node: '>=0.10.0'} - global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -14613,9 +14541,6 @@ packages: resolution: {integrity: sha512-QrJia2qDf5BB/V6HYlDTs0I0lBahyjLzpGQg3KT7FnCdTonAyPy2RtY802m2k4ALx6Dp752f82WsOczEVr3l6Q==} engines: {node: '>=20'} - globjoin@0.1.4: - resolution: {integrity: sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==} - globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -14683,10 +14608,6 @@ packages: engines: {node: '>=6'} deprecated: this library is no longer supported - hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - has-ansi@2.0.0: resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} engines: {node: '>=0.10.0'} @@ -15066,10 +14987,6 @@ packages: resolution: {integrity: sha512-pYkiyXVL2Mf3pozdlDGV6NAObxQx13Ae8knZk1UJRJ6uRW/ZRmTGHlQYtrsSl7ubuE5F8CD1z+s1n4RHNuTtuA==} engines: {node: '>=18'} - import-lazy@4.0.0: - resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} - engines: {node: '>=8'} - import-local@3.2.0: resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} @@ -15086,10 +15003,6 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - index-to-position@1.2.0: resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} engines: {node: '>=18'} @@ -15411,10 +15324,6 @@ packages: resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} engines: {node: '>=12'} - is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -16200,9 +16109,6 @@ packages: engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - known-css-properties@0.29.0: - resolution: {integrity: sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==} - language-subtag-registry@0.3.23: resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} @@ -16759,14 +16665,6 @@ packages: resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} engines: {node: '>=0.10.0'} - map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - - map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - markdown-escapes@1.0.4: resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==} @@ -16881,10 +16779,6 @@ packages: mensch@0.3.4: resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==} - meow@10.1.5: - resolution: {integrity: sha512-/d+PQ4GKmGvM9Bee/DPa8z3mXs/pkvJE2KEThngVNOqtmljC6K7NMPxtc2JeZYTmpWb9k/TmxjeL18ez3h7vCw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -17080,10 +16974,6 @@ packages: resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} - minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - minimist@0.2.4: resolution: {integrity: sha512-Pkrrm8NjyQ8yVt8Am9M+yUt74zE3iokhzbG1bFVNjLB92vwM71hf40RkEsryg98BujhVOncKm/C1xROxZ030LQ==} @@ -17484,10 +17374,6 @@ packages: normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - normalize-package-data@3.0.3: - resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} - engines: {node: '>=10'} - normalize-package-data@8.0.0: resolution: {integrity: sha512-RWk+PI433eESQ7ounYxIp67CYuVsS1uYSonX3kA6ps/3LWfjVQa/ptEg6Y3T6uAMq1mWpX9PQ+qx+QaHpsc7gQ==} engines: {node: ^20.17.0 || >=22.9.0} @@ -18736,15 +18622,6 @@ packages: peerDependencies: postcss: ^8.1.0 - postcss-resolve-nested-selector@0.1.6: - resolution: {integrity: sha512-0sglIs9Wmkzbr8lQwEyIzlDOOC9bGmfVKcJTaxv3vMmd3uo4o4DerC3En0bnmgceeql9BfC8hRkp7cg0fjdVqw==} - - postcss-safe-parser@6.0.0: - resolution: {integrity: sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.3.3 - postcss-selector-not@6.0.1: resolution: {integrity: sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==} engines: {node: ^12 || ^14 || >=16} @@ -19318,10 +19195,6 @@ packages: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} - read-pkg-up@8.0.0: - resolution: {integrity: sha512-snVCqPczksT0HS2EC+SxUndvSzn6LRCwpfSvLrIfR5BKDQQZMaI6jPRC9dYvYFDRAuFEAnkwww8kBBNE/3VvzQ==} - engines: {node: '>=12'} - read-pkg@10.1.0: resolution: {integrity: sha512-I8g2lArQiP78ll51UeMZojewtYgIRCKCWqZEgOO8c/uefTI+XDXvCSXu3+YNUaTNvZzobrL5+SqHjBrByRRTdg==} engines: {node: '>=20'} @@ -19334,10 +19207,6 @@ packages: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} engines: {node: '>=8'} - read-pkg@6.0.0: - resolution: {integrity: sha512-X1Fu3dPuk/8ZLsMhEj5f4wFAF0DWoK7qhGJvgaijocXxBmSToKfbFtqbxMO7bVjNA1dmE5huAzjXj/ey86iw9Q==} - engines: {node: '>=12'} - readable-stream@1.0.34: resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} @@ -19401,10 +19270,6 @@ packages: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} - redent@4.0.0: - resolution: {integrity: sha512-tYkDkVVtYkSVhuQ4zBgfvciymHaeuel+zFKXShfDnFP5SyVEP7qo70Rf1jTOTCx3vGNAbnEi/xFkcfQVMIBWag==} - engines: {node: '>=12'} - redeyed@1.0.1: resolution: {integrity: sha512-8eEWsNCkV2rvwKLS1Cvp5agNjMhwRe2um+y32B2+3LqOzg4C9BBPs6vzAfV16Ivb8B9HPNKIqd8OrdBws8kNlQ==} @@ -20475,9 +20340,6 @@ packages: style-mod@4.1.3: resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} - style-search@0.1.0: - resolution: {integrity: sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==} - styled_string@0.0.1: resolution: {integrity: sha512-DU2KZiB6VbPkO2tGSqQ9n96ZstUPjW7X4sGO6V2m1myIQluX0p1Ol8BrA/l6/EesqhMqXOIXs3cJNOy1UuU2BA==} @@ -20491,11 +20353,6 @@ packages: peerDependencies: postcss: ^8.4.32 - stylelint@15.11.0: - resolution: {integrity: sha512-78O4c6IswZ9TzpcIiQJIN49K3qNoXTM8zEJzhaTE/xRTCZswaovSEVIa/uwbOltZrk16X4jAxjaOhzz/hTm1Kw==} - engines: {node: ^14.13.1 || >=16.0.0} - hasBin: true - stylis@4.2.0: resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==} @@ -20542,10 +20399,6 @@ packages: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - supports-hyperlinks@3.2.0: - resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} - engines: {node: '>=14.18'} - supports-hyperlinks@4.4.0: resolution: {integrity: sha512-UKbpT93hN5Nr9go5UY7bopIB9YQlMz9nm/ct4IXt/irb5YRkn9WaqrOBJGZ5Pwvsd5FQzSVeYlGdXoCAPQZrPg==} engines: {node: '>=20'} @@ -20948,10 +20801,6 @@ packages: resolution: {integrity: sha512-OLWW+Nd99NOM53aZ8ilT/YpEiOo6mXD3F4/wLbARqybSZ3Jb8IxHK5UGVbZaae0wtXAyQshVV+SeqVBik+Fbmw==} engines: {node: '>=8'} - trim-newlines@4.1.1: - resolution: {integrity: sha512-jRKj0n0jXWo6kh62nA5TEh3+4igKDXLvzBJcPpiizP7oOolUrYIxmVBG9TOtHYFHoddUk6YvAkGeGoSVTXfQXQ==} - engines: {node: '>=12'} - trim-right@1.0.1: resolution: {integrity: sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw==} engines: {node: '>=0.10.0'} @@ -21083,10 +20932,6 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} - type-fest@1.4.0: - resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} - engines: {node: '>=10'} - type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -23978,10 +23823,6 @@ snapshots: '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) '@csstools/css-tokenizer': 4.0.0 - '@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1)': - dependencies: - '@csstools/css-tokenizer': 2.4.1 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': dependencies: '@csstools/css-tokenizer': 4.0.0 @@ -23994,15 +23835,8 @@ snapshots: optionalDependencies: css-tree: 3.2.1 - '@csstools/css-tokenizer@2.4.1': {} - '@csstools/css-tokenizer@4.0.0': {} - '@csstools/media-query-list-parser@2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1)': - dependencies: - '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) - '@csstools/css-tokenizer': 2.4.1 - '@csstools/postcss-cascade-layers@1.1.1(postcss@8.5.6)': dependencies: '@csstools/selector-specificity': 2.2.0(postcss-selector-parser@6.1.2) @@ -24081,10 +23915,6 @@ snapshots: dependencies: postcss-selector-parser: 6.1.2 - '@csstools/selector-specificity@3.1.1(postcss-selector-parser@6.1.2)': - dependencies: - postcss-selector-parser: 6.1.2 - '@distributed-systems/callsite@1.1.1': dependencies: ee-log: 3.0.9 @@ -29345,13 +29175,6 @@ snapshots: postcss: 8.5.6 tailwindcss: 4.2.1 - '@tailwindcss/vite@4.2.1(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1))': - dependencies: - '@tailwindcss/node': 4.2.1 - '@tailwindcss/oxide': 4.2.1 - tailwindcss: 4.2.1 - vite: 5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - '@tailwindcss/vite@4.2.1(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.2.1 @@ -30589,8 +30412,6 @@ snapshots: dependencies: minimatch: 3.1.5 - '@types/minimist@1.2.5': {} - '@types/mocha@10.0.10': {} '@types/ms@2.1.0': {} @@ -31873,8 +31694,6 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 - arrify@1.0.1: {} - asap@2.0.6: {} asn1.js@4.10.1: @@ -32645,8 +32464,6 @@ snapshots: balanced-match@1.0.2: {} - balanced-match@2.0.0: {} - balanced-match@4.0.4: {} bare-events@2.8.2: {} @@ -32763,7 +32580,7 @@ snapshots: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.14.2 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 @@ -32795,7 +32612,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.14.2 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -33729,13 +33546,6 @@ snapshots: camelcase-css@2.0.1: {} - camelcase-keys@7.0.2: - dependencies: - camelcase: 6.3.0 - map-obj: 4.3.0 - quick-lru: 5.1.1 - type-fest: 1.4.0 - camelcase@5.3.1: {} camelcase@6.3.0: {} @@ -34572,8 +34382,6 @@ snapshots: dependencies: postcss: 8.5.6 - css-functions-list@3.3.3: {} - css-has-pseudo@3.0.4(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -34944,17 +34752,8 @@ snapshots: optionalDependencies: supports-color: 8.1.1 - decamelize-keys@1.1.1: - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - - decamelize@1.2.0: {} - decamelize@4.0.0: {} - decamelize@5.0.1: {} - decimal.js-light@2.5.1: {} decimal.js@10.6.0: {} @@ -37728,7 +37527,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.15.0 + qs: 6.14.2 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 @@ -37836,8 +37635,6 @@ snapshots: transitivePeerDependencies: - supports-color - fastest-levenshtein@1.0.16: {} - fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -37882,10 +37679,6 @@ snapshots: dependencies: flat-cache: 3.2.0 - file-entry-cache@7.0.2: - dependencies: - flat-cache: 3.2.0 - file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -38156,7 +37949,7 @@ snapshots: '@paralleldrive/cuid2': 2.3.1 dezalgo: 1.0.4 once: 1.4.0 - qs: 6.15.0 + qs: 6.14.2 forwarded-parse@2.1.2: {} @@ -38549,10 +38342,6 @@ snapshots: is-windows: 1.0.2 resolve-dir: 1.0.1 - global-modules@2.0.0: - dependencies: - global-prefix: 3.0.0 - global-prefix@1.0.2: dependencies: expand-tilde: 2.0.2 @@ -38561,12 +38350,6 @@ snapshots: is-windows: 1.0.2 which: 1.3.1 - global-prefix@3.0.0: - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 - globals@13.24.0: dependencies: type-fest: 0.20.2 @@ -38623,8 +38406,6 @@ snapshots: slash: 5.1.0 unicorn-magic: 0.4.0 - globjoin@0.1.4: {} - globrex@0.1.2: {} goober@2.1.18(csstype@3.2.3): @@ -38735,8 +38516,6 @@ snapshots: ajv: 6.14.0 har-schema: 2.0.0 - hard-rejection@2.1.0: {} - has-ansi@2.0.0: dependencies: ansi-regex: 2.1.1 @@ -39187,8 +38966,6 @@ snapshots: cjs-module-lexer: 2.2.0 module-details-from-path: 1.0.4 - import-lazy@4.0.0: {} - import-local@3.2.0: dependencies: pkg-dir: 4.2.0 @@ -39200,8 +38977,6 @@ snapshots: indent-string@4.0.0: {} - indent-string@5.0.0: {} - index-to-position@1.2.0: {} indexes-of@1.0.1: {} @@ -39524,8 +39299,6 @@ snapshots: is-path-inside@4.0.0: {} - is-plain-obj@1.1.0: {} - is-plain-obj@2.1.0: {} is-plain-obj@4.1.0: {} @@ -40775,8 +40548,6 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - known-css-properties@0.29.0: {} - language-subtag-registry@0.3.23: {} language-tags@1.0.9: @@ -41377,10 +41148,6 @@ snapshots: map-cache@0.2.2: {} - map-obj@1.0.1: {} - - map-obj@4.3.0: {} - markdown-escapes@1.0.4: {} markdown-it-footnote@4.0.0: {} @@ -41497,21 +41264,6 @@ snapshots: mensch@0.3.4: {} - meow@10.1.5: - dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 7.0.2 - decamelize: 5.0.1 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 8.0.0 - redent: 4.0.0 - trim-newlines: 4.1.1 - type-fest: 1.4.0 - yargs-parser: 20.2.9 - merge-descriptors@1.0.3: {} merge-descriptors@2.0.0: {} @@ -41735,12 +41487,6 @@ snapshots: dependencies: brace-expansion: 2.0.3 - minimist-options@4.1.0: - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - minimist@0.2.4: {} minimist@1.2.8: {} @@ -42049,7 +41795,7 @@ snapshots: dependencies: jquery-deferred: 0.3.1 lodash: 4.18.1 - qs: 6.15.0 + qs: 6.14.2 named-placeholders@1.1.6: dependencies: @@ -42369,13 +42115,6 @@ snapshots: semver: 5.7.2 validate-npm-package-license: 3.0.4 - normalize-package-data@3.0.3: - dependencies: - hosted-git-info: 4.1.0 - is-core-module: 2.16.1 - semver: 7.7.4 - validate-npm-package-license: 3.0.4 - normalize-package-data@8.0.0: dependencies: hosted-git-info: 9.0.2 @@ -43743,12 +43482,6 @@ snapshots: postcss: 8.5.6 thenby: 1.3.4 - postcss-resolve-nested-selector@0.1.6: {} - - postcss-safe-parser@6.0.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-not@6.0.1(postcss@8.5.6): dependencies: postcss: 8.5.6 @@ -44425,12 +44158,6 @@ snapshots: read-pkg: 5.2.0 type-fest: 0.8.1 - read-pkg-up@8.0.0: - dependencies: - find-up: 5.0.0 - read-pkg: 6.0.0 - type-fest: 1.4.0 - read-pkg@10.1.0: dependencies: '@types/normalize-package-data': 2.4.4 @@ -44452,13 +44179,6 @@ snapshots: parse-json: 5.2.0 type-fest: 0.6.0 - read-pkg@6.0.0: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 3.0.3 - parse-json: 5.2.0 - type-fest: 1.4.0 - readable-stream@1.0.34: dependencies: core-util-is: 1.0.3 @@ -44556,11 +44276,6 @@ snapshots: indent-string: 4.0.0 strip-indent: 3.0.0 - redent@4.0.0: - dependencies: - indent-string: 5.0.0 - strip-indent: 4.1.1 - redeyed@1.0.1: dependencies: esprima: 3.0.0 @@ -44714,7 +44429,7 @@ snapshots: mime-types: 2.1.35 oauth-sign: 0.9.0 performance-now: 2.1.0 - qs: 6.15.0 + qs: 6.14.2 safe-buffer: 5.2.1 tough-cookie: 4.1.4 tunnel-agent: 0.6.0 @@ -45923,8 +45638,6 @@ snapshots: style-mod@4.1.3: {} - style-search@0.1.0: {} - styled_string@0.0.1: {} stylehacks@4.0.3: @@ -45939,52 +45652,6 @@ snapshots: postcss: 8.5.6 postcss-selector-parser: 7.1.1 - stylelint@15.11.0(typescript@5.9.3): - dependencies: - '@csstools/css-parser-algorithms': 2.7.1(@csstools/css-tokenizer@2.4.1) - '@csstools/css-tokenizer': 2.4.1 - '@csstools/media-query-list-parser': 2.1.13(@csstools/css-parser-algorithms@2.7.1(@csstools/css-tokenizer@2.4.1))(@csstools/css-tokenizer@2.4.1) - '@csstools/selector-specificity': 3.1.1(postcss-selector-parser@6.1.2) - balanced-match: 2.0.0 - colord: 2.9.3 - cosmiconfig: 8.3.6(typescript@5.9.3) - css-functions-list: 3.3.3 - css-tree: 2.3.1 - debug: 4.4.3(supports-color@5.5.0) - fast-glob: 3.3.3 - fastest-levenshtein: 1.0.16 - file-entry-cache: 7.0.2 - global-modules: 2.0.0 - globby: 11.1.0 - globjoin: 0.1.4 - html-tags: 3.3.1 - ignore: 5.3.2 - import-lazy: 4.0.0 - imurmurhash: 0.1.4 - is-plain-object: 5.0.0 - known-css-properties: 0.29.0 - mathml-tag-names: 2.1.3 - meow: 10.1.5 - micromatch: 4.0.8 - normalize-path: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-resolve-nested-selector: 0.1.6 - postcss-safe-parser: 6.0.0(postcss@8.5.6) - postcss-selector-parser: 6.1.2 - postcss-value-parser: 4.2.0 - resolve-from: 5.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - style-search: 0.1.0 - supports-hyperlinks: 3.2.0 - svg-tags: 1.0.0 - table: 6.9.0 - write-file-atomic: 5.0.1 - transitivePeerDependencies: - - supports-color - - typescript - stylis@4.2.0: {} sucrase@3.35.1: @@ -46011,7 +45678,7 @@ snapshots: formidable: 2.1.5 methods: 1.1.2 mime: 2.6.0 - qs: 6.15.0 + qs: 6.14.2 semver: 7.7.4 transitivePeerDependencies: - supports-color @@ -46041,11 +45708,6 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-hyperlinks@3.2.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - supports-hyperlinks@4.4.0: dependencies: has-flag: 5.0.1 @@ -46485,7 +46147,7 @@ snapshots: faye-websocket: 0.11.4 livereload-js: 3.4.1 object-assign: 4.1.1 - qs: 6.15.0 + qs: 6.14.2 transitivePeerDependencies: - supports-color @@ -46625,8 +46287,6 @@ snapshots: transitivePeerDependencies: - supports-color - trim-newlines@4.1.1: {} - trim-right@1.0.1: {} trim-trailing-lines@1.1.4: {} @@ -46755,8 +46415,6 @@ snapshots: type-fest@0.8.1: {} - type-fest@1.4.0: {} - type-fest@4.41.0: {} type-fest@5.5.0: @@ -47028,7 +46686,7 @@ snapshots: url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.15.0 + qs: 6.14.2 use-callback-ref@1.3.3(@types/react@18.3.28)(react@18.3.1): dependencies: From 8273f465eaee8eea8f535fcf05551a7df966580c Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 18:49:19 -0500 Subject: [PATCH 4/8] Improved admin-x settings test request waits (#27737) no ref Settings tests were a bit flaky on CI - this is an attempt to resolve some of these. - added a shared `waitForApiRequest` helper for Playwright acceptance tests that inspect mocked API calls - updated flaky-prone admin-x settings specs to wait for route-handler captures before asserting request bodies/URLs - updated design preview assertions to wait for the expected preview header instead of reading the capture synchronously --- apps/admin-x-framework/src/test/acceptance.ts | 6 ++++++ .../test/acceptance/membership/analytics.test.ts | 16 ++++++++++------ .../test/acceptance/membership/stripe.test.ts | 8 +++++--- .../test/acceptance/site/design.test.ts | 14 ++++++++++---- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/apps/admin-x-framework/src/test/acceptance.ts b/apps/admin-x-framework/src/test/acceptance.ts index 1bff7a5ce20..3e6e79994b4 100644 --- a/apps/admin-x-framework/src/test/acceptance.ts +++ b/apps/admin-x-framework/src/test/acceptance.ts @@ -268,6 +268,12 @@ export async function mockApi return {lastApiRequests}; } +export async function waitForApiRequest>(lastApiRequests: {[key in keyof Requests]?: RequestRecord}, requestName: keyof Requests) { + await expect.poll(() => lastApiRequests[requestName]).toBeTruthy(); + + return lastApiRequests[requestName]!; +} + export function updatedSettingsResponse(newSettings: Array<{ key: string, value: string | boolean | null, is_read_only?: boolean }>) { return { ...responseFixtures.settings, diff --git a/apps/admin-x-settings/test/acceptance/membership/analytics.test.ts b/apps/admin-x-settings/test/acceptance/membership/analytics.test.ts index eff5529df6d..621bf289fcd 100644 --- a/apps/admin-x-settings/test/acceptance/membership/analytics.test.ts +++ b/apps/admin-x-settings/test/acceptance/membership/analytics.test.ts @@ -1,5 +1,5 @@ import {expect, test} from '@playwright/test'; -import {globalDataRequests, mockApi, responseFixtures, updatedSettingsResponse} from '@tryghost/admin-x-framework/test/acceptance'; +import {globalDataRequests, mockApi, responseFixtures, updatedSettingsResponse, waitForApiRequest} from '@tryghost/admin-x-framework/test/acceptance'; // Helper functions to reduce mockApi boilerplate const createConfigWithFeatureFlags = (limits?: any) => ({ @@ -97,8 +97,9 @@ test.describe('Analytics settings', async () => { await section.getByRole('button', {name: 'Save'}).click(); - const body = lastApiRequests.editSettings?.body as {settings: Array<{key: string, value: boolean}>} | undefined; - const actualSettings = body?.settings || []; + const editSettings = await waitForApiRequest(lastApiRequests, 'editSettings'); + const body = editSettings.body as {settings: Array<{key: string, value: boolean}>}; + const actualSettings = body.settings || []; const expectedSettings = [ {key: 'web_analytics', value: false}, {key: 'members_track_sources', value: false}, @@ -129,7 +130,8 @@ test.describe('Analytics settings', async () => { await section.getByRole('button', {name: 'Post analytics'}).click(); - const hasDownloadUrl = lastApiRequests.postsExport?.url?.includes('/posts/export/?limit=1000'); + const postsExport = await waitForApiRequest(lastApiRequests, 'postsExport'); + const hasDownloadUrl = postsExport.url?.includes('/posts/export/?limit=1000'); expect(hasDownloadUrl).toBe(true); }); @@ -211,7 +213,8 @@ test.describe('Analytics settings', async () => { await webAnalyticsToggle.uncheck(); await section.getByRole('button', {name: 'Save'}).click(); - expect(lastApiRequests.editSettings?.body).toEqual({ + const editSettings = await waitForApiRequest(lastApiRequests, 'editSettings'); + expect(editSettings.body).toEqual({ settings: [ {key: 'web_analytics', value: false} ] @@ -270,7 +273,8 @@ test.describe('Analytics settings', async () => { await webAnalyticsToggle.check(); await section.getByRole('button', {name: 'Save'}).click(); - expect(lastApiRequests.editSettings?.body).toEqual({ + const editSettings = await waitForApiRequest(lastApiRequests, 'editSettings'); + expect(editSettings.body).toEqual({ settings: [ {key: 'web_analytics', value: true} ] diff --git a/apps/admin-x-settings/test/acceptance/membership/stripe.test.ts b/apps/admin-x-settings/test/acceptance/membership/stripe.test.ts index a82d954b840..e344d4fa3ef 100644 --- a/apps/admin-x-settings/test/acceptance/membership/stripe.test.ts +++ b/apps/admin-x-settings/test/acceptance/membership/stripe.test.ts @@ -1,5 +1,5 @@ import {expect, test} from '@playwright/test'; -import {globalDataRequests, mockApi, responseFixtures, updatedSettingsResponse} from '@tryghost/admin-x-framework/test/acceptance'; +import {globalDataRequests, mockApi, responseFixtures, updatedSettingsResponse, waitForApiRequest} from '@tryghost/admin-x-framework/test/acceptance'; test.describe('Stripe settings', async () => { test('Supports the Stripe Connect flow', async ({page}) => { @@ -39,7 +39,8 @@ test.describe('Stripe settings', async () => { await expect(section.getByText('Connected to Stripe')).toHaveCount(2); // We actually do two settings update requests here, this just checks the last one - expect(lastApiRequests.editSettings?.body).toEqual({ + const editSettings = await waitForApiRequest(lastApiRequests, 'editSettings'); + expect(editSettings.body).toEqual({ settings: [{ key: 'portal_plans', value: '["free","monthly","yearly"]' @@ -78,7 +79,8 @@ test.describe('Stripe settings', async () => { // There's a mobile version of the same button in the DOM await expect(section.getByText('Connected to Stripe')).toHaveCount(2); - expect(lastApiRequests.editSettings?.body).toEqual({ + const editSettings = await waitForApiRequest(lastApiRequests, 'editSettings'); + expect(editSettings.body).toEqual({ settings: [{ key: 'stripe_secret_key', value: 'sk_test_123' diff --git a/apps/admin-x-settings/test/acceptance/site/design.test.ts b/apps/admin-x-settings/test/acceptance/site/design.test.ts index 861dff1da4c..283fd846ed3 100644 --- a/apps/admin-x-settings/test/acceptance/site/design.test.ts +++ b/apps/admin-x-settings/test/acceptance/site/design.test.ts @@ -4,7 +4,8 @@ import { mockApi, mockSitePreview, responseFixtures, - updatedSettingsResponse + updatedSettingsResponse, + waitForApiRequest } from '@tryghost/admin-x-framework/test/acceptance'; import {expect, test} from '@playwright/test'; @@ -140,7 +141,8 @@ test.describe('Design settings', async () => { await expect(modal.getByTestId('toggle-unsplash-button')).toBeVisible(); await modal.getByRole('button', {name: 'Save'}).click(); - expect(lastApiRequests.editSettings?.body).toEqual({ + const editSettings = await waitForApiRequest(lastApiRequests, 'editSettings'); + expect(editSettings.body).toEqual({ settings: [ {key: 'accent_color', value: '#cd5786'} ] @@ -186,12 +188,14 @@ test.describe('Design settings', async () => { const expectedSettings = {navigation_layout: 'Logo in the middle'}; const expectedEncoded = new URLSearchParams([['custom', JSON.stringify(expectedSettings)]]).toString(); + await expect.poll(() => previewRequests.find(header => new RegExp(`&${expectedEncoded.replace(/\+/g, '\\+')}`).test(header))).toBeTruthy(); const matchingHeader = previewRequests.find(header => new RegExp(`&${expectedEncoded.replace(/\+/g, '\\+')}`).test(header)); expect(matchingHeader).toBeDefined(); await modal.getByRole('button', {name: 'Save'}).click(); - expect(lastApiRequests.editCustomThemeSettings?.body).toMatchObject({ + const editCustomThemeSettings = await waitForApiRequest(lastApiRequests, 'editCustomThemeSettings'); + expect(editCustomThemeSettings.body).toMatchObject({ custom_theme_settings: [ {key: 'navigation_layout', value: 'Logo in the middle'} ] @@ -289,6 +293,7 @@ test.describe('Design settings', async () => { const expectedSettings = {navigation_layout: 'Logo in the middle', show_featured_posts: null}; const expectedEncoded = new URLSearchParams([['custom', JSON.stringify(expectedSettings)]]).toString(); + await expect.poll(() => previewRequests.find(header => header.includes(expectedEncoded))).toBeTruthy(); const matchingHeader = previewRequests.find(header => header.includes(expectedEncoded)); expect(matchingHeader).toBeDefined(); @@ -296,7 +301,8 @@ test.describe('Design settings', async () => { await modal.getByRole('button', {name: 'Save'}).click(); - expect(lastApiRequests.editCustomThemeSettings?.body).toMatchObject({ + const editCustomThemeSettings = await waitForApiRequest(lastApiRequests, 'editCustomThemeSettings'); + expect(editCustomThemeSettings.body).toMatchObject({ custom_theme_settings: [ {key: 'navigation_layout', value: 'Logo in the middle'}, {key: 'show_featured_posts', value: 'false'} From 10fad0ec1f5cd5d68928275cc7ea66aafb80f942 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 19:28:41 -0500 Subject: [PATCH 5/8] Added eslint declarations to workspaces missing them (#27749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no ref Eight workspaces invoke `eslint` from their `lint` scripts but don't declare `eslint` in `package.json`. Under pnpm strict isolation that means no workspace-local `node_modules/.bin/eslint`, and the binary resolves to whatever pnpm hoists at root level — currently `apps/admin`'s `catalog:eslint9` (9.37.0). Their legacy `.eslintrc.cjs` configs aren't compatible with ESLint 9, so `pnpm --filter lint` from the repo root fails locally with `ESLint couldn't find an eslint.config.js file`. This PR adds `"eslint": "catalog:"` (resolves to `8.57.1`) to each affected workspace's devDeps so the local `.bin/eslint` shim is correct. --- apps/activitypub/package.json | 3 ++- apps/announcement-bar/package.json | 3 ++- apps/posts/package.json | 1 + apps/sodo-search/package.json | 3 ++- apps/stats/package.json | 1 + ghost/core/package.json | 1 + ghost/i18n/package.json | 1 + ghost/parse-email-address/package.json | 1 + pnpm-lock.yaml | 25 +++++++++++++++++++++++++ 9 files changed, 36 insertions(+), 3 deletions(-) diff --git a/apps/activitypub/package.json b/apps/activitypub/package.json index 3ec8667791c..001813bba0a 100644 --- a/apps/activitypub/package.json +++ b/apps/activitypub/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/activitypub", - "version": "3.1.16", + "version": "3.1.18", "license": "MIT", "repository": { "type": "git", @@ -42,6 +42,7 @@ "@types/jest": "29.5.14", "@types/react": "18.3.28", "@types/react-dom": "18.3.7", + "eslint": "catalog:", "jest": "29.7.0", "tailwindcss": "^4.2.2", "vite": "5.4.21", diff --git a/apps/announcement-bar/package.json b/apps/announcement-bar/package.json index 5f15ee6a83d..c86e9edc2d1 100644 --- a/apps/announcement-bar/package.json +++ b/apps/announcement-bar/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/announcement-bar", - "version": "1.1.19", + "version": "1.1.20", "license": "MIT", "repository": "https://github.com/TryGhost/Ghost", "author": "Ghost Foundation", @@ -83,6 +83,7 @@ "@vitest/coverage-v8": "~3.2.4", "concurrently": "8.2.2", "cross-fetch": "4.1.0", + "eslint": "catalog:", "jsdom": "28.1.0", "vite": "5.4.21", "vite-plugin-svgr": "3.3.0", diff --git a/apps/posts/package.json b/apps/posts/package.json index 189b4788942..33fb600420c 100644 --- a/apps/posts/package.json +++ b/apps/posts/package.json @@ -45,6 +45,7 @@ "@types/jest": "29.5.14", "@types/react": "18.3.28", "@vitest/coverage-v8": "^1.6.1", + "eslint": "catalog:", "msw": "2.12.14", "tailwindcss": "^4.2.2", "vite": "5.4.21", diff --git a/apps/sodo-search/package.json b/apps/sodo-search/package.json index 1afdc6cdc85..c525815246e 100644 --- a/apps/sodo-search/package.json +++ b/apps/sodo-search/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/sodo-search", - "version": "1.8.16", + "version": "1.8.17", "license": "MIT", "repository": "https://github.com/TryGhost/Ghost", "author": "Ghost Foundation", @@ -101,6 +101,7 @@ "@vitest/coverage-v8": "~3.2.4", "concurrently": "8.2.2", "cross-fetch": "4.1.0", + "eslint": "catalog:", "jsdom": "28.1.0", "nock": "13.5.6", "tailwindcss": "3.4.18", diff --git a/apps/stats/package.json b/apps/stats/package.json index 5c8aaaeea3a..7bbadbc524a 100644 --- a/apps/stats/package.json +++ b/apps/stats/package.json @@ -50,6 +50,7 @@ "@vitest/coverage-v8": "^1.6.1", "@vitejs/plugin-react": "4.7.0", "dotenv": "17.3.1", + "eslint": "catalog:", "tailwindcss": "^4.2.2", "vite": "5.4.21", "vite-plugin-svgr": "4.5.0", diff --git a/ghost/core/package.json b/ghost/core/package.json index aafbee88aa7..e152cc0364c 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -270,6 +270,7 @@ "cli-progress": "3.12.0", "cssnano": "7.1.1", "esbuild": "0.25.12", + "eslint": "catalog:", "expect": "29.7.0", "form-data": "4.0.5", "html-minifier": "4.0.0", diff --git a/ghost/i18n/package.json b/ghost/i18n/package.json index f6f6594446a..e1a5a19b023 100644 --- a/ghost/i18n/package.json +++ b/ghost/i18n/package.json @@ -32,6 +32,7 @@ ], "devDependencies": { "c8": "10.1.3", + "eslint": "catalog:", "fs-extra": "11.3.4", "glob": "^13.0.6", "i18next-parser": "9.3.0", diff --git a/ghost/parse-email-address/package.json b/ghost/parse-email-address/package.json index ba7c8e16403..afa79a9e8ff 100644 --- a/ghost/parse-email-address/package.json +++ b/ghost/parse-email-address/package.json @@ -27,6 +27,7 @@ "devDependencies": { "@types/node": "25.6.0", "c8": "10.1.3", + "eslint": "catalog:", "mocha": "11.7.5", "tsx": "4.21.0", "typescript": "5.9.3" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 739d1bab63f..d97f9094ef2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -187,6 +187,9 @@ importers: '@types/react-dom': specifier: 18.3.7 version: 18.3.7(@types/react@18.3.28) + eslint: + specifier: 'catalog:' + version: 8.57.1 jest: specifier: 29.7.0 version: 29.7.0(@types/node@25.6.0)(babel-plugin-macros@3.1.0)(node-notifier@10.0.1)(ts-node@10.9.2(@swc/core@1.15.21(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@5.9.3)) @@ -726,6 +729,9 @@ importers: cross-fetch: specifier: 4.1.0 version: 4.1.0(encoding@0.1.13) + eslint: + specifier: 'catalog:' + version: 8.57.1 jsdom: specifier: 28.1.0 version: 28.1.0(@noble/hashes@1.8.0) @@ -996,6 +1002,9 @@ importers: '@vitest/coverage-v8': specifier: ^1.6.1 version: 1.6.1(vitest@1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + eslint: + specifier: 'catalog:' + version: 8.57.1 msw: specifier: 2.12.14 version: 2.12.14(@types/node@25.6.0)(typescript@5.9.3) @@ -1326,6 +1335,9 @@ importers: cross-fetch: specifier: 4.1.0 version: 4.1.0(encoding@0.1.13) + eslint: + specifier: 'catalog:' + version: 8.57.1 jsdom: specifier: 28.1.0 version: 28.1.0(@noble/hashes@1.8.0) @@ -1405,6 +1417,9 @@ importers: dotenv: specifier: 17.3.1 version: 17.3.1 + eslint: + specifier: 'catalog:' + version: 8.57.1 tailwindcss: specifier: ^4.2.2 version: 4.2.2 @@ -2403,6 +2418,9 @@ importers: esbuild: specifier: 0.25.12 version: 0.25.12 + eslint: + specifier: 'catalog:' + version: 8.57.1 expect: specifier: 29.7.0 version: 29.7.0 @@ -2489,6 +2507,9 @@ importers: c8: specifier: 10.1.3 version: 10.1.3 + eslint: + specifier: 'catalog:' + version: 8.57.1 fs-extra: specifier: 11.3.4 version: 11.3.4 @@ -2514,6 +2535,9 @@ importers: c8: specifier: 10.1.3 version: 10.1.3 + eslint: + specifier: 'catalog:' + version: 8.57.1 mocha: specifier: 11.7.5 version: 11.7.5 @@ -9388,6 +9412,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@vitejs/plugin-react-swc@4.1.0': resolution: {integrity: sha512-Ff690TUck0Anlh7wdIcnsVMhofeEVgm44Y4OYdeeEEPSKyZHzDI9gfVBvySEhDfXtBp8tLCbfsVKPWEMEjq8/g==} From f2d13ab508801db788c220498da4dfde9471eae7 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 19:57:13 -0500 Subject: [PATCH 6/8] Added eslint plugin direct declarations (#27753) no ref Follow-up to #27749 (`eslint` binary declarations). The same strict-isolation principle applies to **eslint plugins and parsers** referenced by `.eslintrc.cjs`/`.eslintrc.js` configs but not declared in the consumer workspace's `package.json`. They currently resolve through `eslint-plugin-ghost`'s transitive deps, which works today but violates the same dep-contract Ghost is enforcing elsewhere. This PR makes each workspace declare what it uses. It's part of cleanup related to `pnpm knip` output. --- apps/activitypub/package.json | 5 +- apps/admin-x-design-system/package.json | 1 + apps/admin-x-framework/package.json | 1 + apps/portal/package.json | 4 +- apps/posts/package.json | 3 + apps/shade/package.json | 1 + apps/stats/package.json | 3 + ghost/core/package.json | 1 + ghost/parse-email-address/package.json | 1 + pnpm-lock.yaml | 103 ++++++++++++++++++++---- 10 files changed, 106 insertions(+), 17 deletions(-) diff --git a/apps/activitypub/package.json b/apps/activitypub/package.json index 001813bba0a..a9a42a3bd42 100644 --- a/apps/activitypub/package.json +++ b/apps/activitypub/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/activitypub", - "version": "3.1.18", + "version": "3.1.19", "license": "MIT", "repository": { "type": "git", @@ -43,6 +43,9 @@ "@types/react": "18.3.28", "@types/react-dom": "18.3.7", "eslint": "catalog:", + "eslint-plugin-react-hooks": "4.6.2", + "eslint-plugin-react-refresh": "0.4.24", + "eslint-plugin-tailwindcss": "4.0.0-beta.0", "jest": "29.7.0", "tailwindcss": "^4.2.2", "vite": "5.4.21", diff --git a/apps/admin-x-design-system/package.json b/apps/admin-x-design-system/package.json index 96757407195..5a7a9b5bc5d 100644 --- a/apps/admin-x-design-system/package.json +++ b/apps/admin-x-design-system/package.json @@ -38,6 +38,7 @@ "@types/react": "18.3.28", "@types/react-dom": "18.3.7", "@types/validator": "13.15.10", + "@typescript-eslint/parser": "8.49.0", "@vitejs/plugin-react": "4.7.0", "autoprefixer": "10.4.21", "c8": "10.1.3", diff --git a/apps/admin-x-framework/package.json b/apps/admin-x-framework/package.json index 4b08fc47de8..b5b439073f7 100644 --- a/apps/admin-x-framework/package.json +++ b/apps/admin-x-framework/package.json @@ -85,6 +85,7 @@ "eslint": "catalog:", "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.24", + "eslint-plugin-tailwindcss": "4.0.0-beta.0", "glob": "^10.5.0", "jsdom": "28.1.0", "msw": "2.12.14", diff --git a/apps/portal/package.json b/apps/portal/package.json index aec4a02e471..1e64028dff4 100644 --- a/apps/portal/package.json +++ b/apps/portal/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/portal", - "version": "2.68.30", + "version": "2.68.31", "license": "MIT", "repository": "https://github.com/TryGhost/Ghost", "author": "Ghost Foundation", @@ -115,6 +115,8 @@ "@testing-library/react": "12.1.5", "@testing-library/user-event": "14.6.1", "@tryghost/i18n": "workspace:*", + "@typescript-eslint/eslint-plugin": "8.49.0", + "@typescript-eslint/parser": "8.49.0", "@vitejs/plugin-react": "4.7.0", "@vitest/coverage-v8": "3.2.4", "@vitest/ui": "3.2.4", diff --git a/apps/posts/package.json b/apps/posts/package.json index 33fb600420c..182d1425f85 100644 --- a/apps/posts/package.json +++ b/apps/posts/package.json @@ -46,6 +46,9 @@ "@types/react": "18.3.28", "@vitest/coverage-v8": "^1.6.1", "eslint": "catalog:", + "eslint-plugin-react-hooks": "4.6.2", + "eslint-plugin-react-refresh": "0.4.24", + "eslint-plugin-tailwindcss": "4.0.0-beta.0", "msw": "2.12.14", "tailwindcss": "^4.2.2", "vite": "5.4.21", diff --git a/apps/shade/package.json b/apps/shade/package.json index 8bbbff67abc..ffbc10d6f73 100644 --- a/apps/shade/package.json +++ b/apps/shade/package.json @@ -78,6 +78,7 @@ "@testing-library/react": "14.3.1", "@types/node": "22.19.17", "@types/react-world-flags": "1.6.0", + "@typescript-eslint/parser": "8.49.0", "@vitejs/plugin-react": "4.7.0", "@vitest/coverage-v8": "^1.6.1", "c8": "10.1.3", diff --git a/apps/stats/package.json b/apps/stats/package.json index 7bbadbc524a..24517d26b4e 100644 --- a/apps/stats/package.json +++ b/apps/stats/package.json @@ -51,6 +51,9 @@ "@vitejs/plugin-react": "4.7.0", "dotenv": "17.3.1", "eslint": "catalog:", + "eslint-plugin-react-hooks": "4.6.2", + "eslint-plugin-react-refresh": "0.4.24", + "eslint-plugin-tailwindcss": "4.0.0-beta.0", "tailwindcss": "^4.2.2", "vite": "5.4.21", "vite-plugin-svgr": "4.5.0", diff --git a/ghost/core/package.json b/ghost/core/package.json index e152cc0364c..05078acef31 100644 --- a/ghost/core/package.json +++ b/ghost/core/package.json @@ -264,6 +264,7 @@ "@types/on-headers": "1.0.4", "@types/sinon": "17.0.4", "@types/supertest": "6.0.3", + "@typescript-eslint/parser": "8.49.0", "bunyan": "1.8.15", "c8": "10.1.3", "chai": "4.5.0", diff --git a/ghost/parse-email-address/package.json b/ghost/parse-email-address/package.json index afa79a9e8ff..de16db44ecf 100644 --- a/ghost/parse-email-address/package.json +++ b/ghost/parse-email-address/package.json @@ -26,6 +26,7 @@ }, "devDependencies": { "@types/node": "25.6.0", + "@typescript-eslint/parser": "8.49.0", "c8": "10.1.3", "eslint": "catalog:", "mocha": "11.7.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d97f9094ef2..c7130ae6c94 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -190,6 +190,15 @@ importers: eslint: specifier: 'catalog:' version: 8.57.1 + eslint-plugin-react-hooks: + specifier: 4.6.2 + version: 4.6.2(eslint@8.57.1) + eslint-plugin-react-refresh: + specifier: 0.4.24 + version: 0.4.24(eslint@8.57.1) + eslint-plugin-tailwindcss: + specifier: 4.0.0-beta.0 + version: 4.0.0-beta.0(tailwindcss@4.2.2) jest: specifier: 29.7.0 version: 29.7.0(@types/node@25.6.0)(babel-plugin-macros@3.1.0)(node-notifier@10.0.1)(ts-node@10.9.2(@swc/core@1.15.21(@swc/helpers@0.5.21))(@types/node@25.6.0)(typescript@5.9.3)) @@ -414,6 +423,9 @@ importers: '@types/validator': specifier: 13.15.10 version: 13.15.10 + '@typescript-eslint/parser': + specifier: 8.49.0 + version: 8.49.0(eslint@8.57.1)(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.7.0 version: 4.7.0(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) @@ -553,6 +565,9 @@ importers: eslint-plugin-react-refresh: specifier: 0.4.24 version: 0.4.24(eslint@8.57.1) + eslint-plugin-tailwindcss: + specifier: 4.0.0-beta.0 + version: 4.0.0-beta.0(tailwindcss@4.2.2) glob: specifier: ^10.5.0 version: 10.5.0 @@ -890,6 +905,12 @@ importers: '@tryghost/i18n': specifier: workspace:* version: link:../../ghost/i18n + '@typescript-eslint/eslint-plugin': + specifier: 8.49.0 + version: 8.49.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: 8.49.0 + version: 8.49.0(eslint@8.57.1)(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.7.0 version: 4.7.0(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) @@ -1005,6 +1026,15 @@ importers: eslint: specifier: 'catalog:' version: 8.57.1 + eslint-plugin-react-hooks: + specifier: 4.6.2 + version: 4.6.2(eslint@8.57.1) + eslint-plugin-react-refresh: + specifier: 0.4.24 + version: 0.4.24(eslint@8.57.1) + eslint-plugin-tailwindcss: + specifier: 4.0.0-beta.0 + version: 4.0.0-beta.0(tailwindcss@4.2.2) msw: specifier: 2.12.14 version: 2.12.14(@types/node@25.6.0)(typescript@5.9.3) @@ -1159,6 +1189,9 @@ importers: '@types/react-world-flags': specifier: 1.6.0 version: 1.6.0 + '@typescript-eslint/parser': + specifier: 8.49.0 + version: 8.49.0(eslint@8.57.1)(typescript@5.9.3) '@vitejs/plugin-react': specifier: 4.7.0 version: 4.7.0(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) @@ -1420,6 +1453,15 @@ importers: eslint: specifier: 'catalog:' version: 8.57.1 + eslint-plugin-react-hooks: + specifier: 4.6.2 + version: 4.6.2(eslint@8.57.1) + eslint-plugin-react-refresh: + specifier: 0.4.24 + version: 0.4.24(eslint@8.57.1) + eslint-plugin-tailwindcss: + specifier: 4.0.0-beta.0 + version: 4.0.0-beta.0(tailwindcss@4.2.2) tailwindcss: specifier: ^4.2.2 version: 4.2.2 @@ -2400,6 +2442,9 @@ importers: '@types/supertest': specifier: 6.0.3 version: 6.0.3 + '@typescript-eslint/parser': + specifier: 8.49.0 + version: 8.49.0(eslint@8.57.1)(typescript@5.9.3) bunyan: specifier: 1.8.15 version: 1.8.15 @@ -2532,6 +2577,9 @@ importers: '@types/node': specifier: 25.6.0 version: 25.6.0 + '@typescript-eslint/parser': + specifier: 8.49.0 + version: 8.49.0(eslint@8.57.1)(typescript@5.9.3) c8: specifier: 10.1.3 version: 10.1.3 @@ -9250,6 +9298,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' + '@typescript-eslint/parser@8.49.0': + resolution: {integrity: sha512-N9lBGA9o9aqb1hVMc9hzySbhKibHmB+N3IpoShyV6HyQYRGIhlrO5rQgttypi+yEeKsKI4idxC8Jw6gXKD4THA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser@8.56.1': resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9306,12 +9361,6 @@ packages: peerDependencies: typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.57.2': - resolution: {integrity: sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/tsconfig-utils@8.58.0': resolution: {integrity: sha512-doNSZEVJsWEu4htiVC+PR6NpM+pa+a4ClH9INRWOWCUzMst/VA9c4gXq92F8GUD1rwhNvRLkgjfYtFXegXQF7A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -30615,6 +30664,22 @@ snapshots: '@types/node': 25.6.0 optional: true + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.49.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/type-utils': 8.49.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/utils': 8.49.0(eslint@8.57.1)(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.49.0 + eslint: 8.57.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/eslint-plugin@8.49.0(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3))(eslint@8.57.1)(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -30663,6 +30728,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.49.0(eslint@8.57.1)(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.49.0 + '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/typescript-estree': 8.49.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.49.0 + debug: 4.4.3(supports-color@5.5.0) + eslint: 8.57.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.56.1 @@ -30701,8 +30778,8 @@ snapshots: '@typescript-eslint/project-service@8.49.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) + '@typescript-eslint/types': 8.58.0 debug: 4.4.3(supports-color@5.5.0) typescript: 5.9.3 transitivePeerDependencies: @@ -30710,8 +30787,8 @@ snapshots: '@typescript-eslint/project-service@8.56.1(typescript@5.9.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) - '@typescript-eslint/types': 8.56.1 + '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) + '@typescript-eslint/types': 8.58.0 debug: 4.4.3(supports-color@5.5.0) typescript: 5.9.3 transitivePeerDependencies: @@ -30749,10 +30826,6 @@ snapshots: dependencies: typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.57.2(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - '@typescript-eslint/tsconfig-utils@8.58.0(typescript@5.9.3)': dependencies: typescript: 5.9.3 @@ -36054,7 +36127,7 @@ snapshots: '@babel/core': 7.29.0 '@babel/eslint-parser': 7.28.4(@babel/core@7.29.0)(eslint@8.57.1) '@glimmer/syntax': 0.95.0 - '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.58.0(typescript@5.9.3) content-tag: 2.0.3 eslint-scope: 7.2.2 html-tags: 3.3.1 From 26148fbe33fcdaa3c49823667c66950298b778a9 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 20:30:48 -0500 Subject: [PATCH 7/8] Bumped vite and vitest in admin-x-framework, admin-x-settings, activitypub (#27731) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no ref Three workspaces — `apps/admin-x-framework` (the shared vite config) plus its two audit-flagged consumers `apps/admin-x-settings` and `apps/activitypub` — move from `vite@5.4.21 + vitest@1.6.1` to `vite@7.3.2 + vitest@4.1.2`, matching what `apps/admin` already runs. --- apps/activitypub/package.json | 4 +- .../hooks/use-activity-pub-queries.test.ts | 8 +- .../test/unit/utils/screenshot.test.ts | 2 +- apps/admin-x-framework/package.json | 8 +- .../test/unit/utils/helpers.test.ts | 32 +- .../test/utils/mock-fetch.ts | 16 +- apps/admin-x-settings/package.json | 6 +- apps/posts/package.json | 6 +- apps/stats/package.json | 7 +- apps/stats/test/unit/app.test.tsx | 2 +- .../test/unit/utils/content-helpers.test.ts | 8 +- .../stats/test/unit/utils/url-helpers.test.ts | 4 +- apps/stats/tsconfig.json | 2 +- pnpm-lock.yaml | 447 ++++++++++++------ 14 files changed, 356 insertions(+), 196 deletions(-) diff --git a/apps/activitypub/package.json b/apps/activitypub/package.json index a9a42a3bd42..20c31b4df6f 100644 --- a/apps/activitypub/package.json +++ b/apps/activitypub/package.json @@ -48,8 +48,8 @@ "eslint-plugin-tailwindcss": "4.0.0-beta.0", "jest": "29.7.0", "tailwindcss": "^4.2.2", - "vite": "5.4.21", - "vitest": "1.6.1" + "vite": "7.3.2", + "vitest": "4.1.2" }, "nx": { "targets": { diff --git a/apps/activitypub/src/hooks/use-activity-pub-queries.test.ts b/apps/activitypub/src/hooks/use-activity-pub-queries.test.ts index 502714d6618..bc65f980554 100644 --- a/apps/activitypub/src/hooks/use-activity-pub-queries.test.ts +++ b/apps/activitypub/src/hooks/use-activity-pub-queries.test.ts @@ -5,7 +5,7 @@ import {beforeEach, describe, expect, it, vi} from 'vitest'; import {renderHook, waitFor} from '@testing-library/react'; import {useReplyChainForUser} from './use-activity-pub-queries'; -global.fetch = vi.fn().mockResolvedValue({ +globalThis.fetch = vi.fn().mockResolvedValue({ json: vi.fn().mockResolvedValue({ site: {url: 'https://test.com'} }) @@ -39,7 +39,7 @@ describe('useReplyChainForUser', () => { beforeEach(() => { vi.clearAllMocks(); - (global.fetch as ReturnType).mockResolvedValue({ + (globalThis.fetch as ReturnType).mockResolvedValue({ json: vi.fn().mockResolvedValue({ site: {url: 'https://test.com'} }) @@ -50,7 +50,9 @@ describe('useReplyChainForUser', () => { getPost: vi.fn() }; - (ActivityPubAPI as ReturnType).mockImplementation(() => mockApi); + (ActivityPubAPI as ReturnType).mockImplementation(function () { + return mockApi; + }); (isApiError as unknown as ReturnType).mockReturnValue(true); }); diff --git a/apps/activitypub/test/unit/utils/screenshot.test.ts b/apps/activitypub/test/unit/utils/screenshot.test.ts index e89a8930658..418d5fc1762 100644 --- a/apps/activitypub/test/unit/utils/screenshot.test.ts +++ b/apps/activitypub/test/unit/utils/screenshot.test.ts @@ -61,7 +61,7 @@ describe('takeScreenshot', function () { }); afterEach(function () { - vi.clearAllMocks(); + vi.restoreAllMocks(); }); it('calls html2canvas with correct default options', async function () { diff --git a/apps/admin-x-framework/package.json b/apps/admin-x-framework/package.json index b5b439073f7..e4195f01077 100644 --- a/apps/admin-x-framework/package.json +++ b/apps/admin-x-framework/package.json @@ -80,7 +80,7 @@ "@types/react": "18.3.28", "@types/react-dom": "18.3.7", "@vitejs/plugin-react": "4.7.0", - "@vitest/coverage-v8": "^1.6.1", + "@vitest/coverage-v8": "^4.1.2", "c8": "10.1.3", "eslint": "catalog:", "eslint-plugin-react-hooks": "4.6.2", @@ -90,10 +90,10 @@ "jsdom": "28.1.0", "msw": "2.12.14", "typescript": "5.9.3", - "vite": "5.4.21", + "vite": "7.3.2", "vite-plugin-css-injected-by-js": "3.5.2", - "vite-plugin-svgr": "3.3.0", - "vitest": "1.6.1" + "vite-plugin-svgr": "4.5.0", + "vitest": "4.1.2" }, "dependencies": { "@ebay/nice-modal-react": "1.2.13", diff --git a/apps/admin-x-framework/test/unit/utils/helpers.test.ts b/apps/admin-x-framework/test/unit/utils/helpers.test.ts index ea2f529b635..cb8f852604f 100644 --- a/apps/admin-x-framework/test/unit/utils/helpers.test.ts +++ b/apps/admin-x-framework/test/unit/utils/helpers.test.ts @@ -138,15 +138,15 @@ describe('helpers utils', () => { }); describe('blobDownload', () => { - let originalFetch: typeof global.fetch; + let originalFetch: typeof globalThis.fetch; let originalCreateObjectURL: typeof URL.createObjectURL; let originalRevokeObjectURL: typeof URL.revokeObjectURL; - let appendChildSpy: MockInstance<[node: Node], Node>; + let appendChildSpy: MockInstance<(node: Node) => Node>; let removeElementSpy: ReturnType; let clickSpy: ReturnType; beforeEach(() => { - originalFetch = global.fetch; + originalFetch = globalThis.fetch; originalCreateObjectURL = URL.createObjectURL; originalRevokeObjectURL = URL.revokeObjectURL; @@ -168,7 +168,7 @@ describe('helpers utils', () => { }); afterEach(() => { - global.fetch = originalFetch; + globalThis.fetch = originalFetch; URL.createObjectURL = originalCreateObjectURL; URL.revokeObjectURL = originalRevokeObjectURL; appendChildSpy.mockRestore(); @@ -177,14 +177,14 @@ describe('helpers utils', () => { it('fetches the URL and triggers a download', async () => { const mockBlob = new Blob(['test,data'], {type: 'text/csv'}); - global.fetch = vi.fn().mockResolvedValue({ + globalThis.fetch = vi.fn().mockResolvedValue({ ok: true, blob: () => Promise.resolve(mockBlob) }); await blobDownload('https://example.com/export.csv', 'members.csv'); - expect(global.fetch).toHaveBeenCalledWith('https://example.com/export.csv', {method: 'GET'}); + expect(globalThis.fetch).toHaveBeenCalledWith('https://example.com/export.csv', {method: 'GET'}); expect(URL.createObjectURL).toHaveBeenCalledWith(mockBlob); expect(clickSpy).toHaveBeenCalled(); expect(removeElementSpy).toHaveBeenCalled(); @@ -193,7 +193,7 @@ describe('helpers utils', () => { it('sets the correct filename on the download link', async () => { const mockBlob = new Blob(['test'], {type: 'text/csv'}); - global.fetch = vi.fn().mockResolvedValue({ + globalThis.fetch = vi.fn().mockResolvedValue({ ok: true, blob: () => Promise.resolve(mockBlob) }); @@ -215,7 +215,7 @@ describe('helpers utils', () => { }); it('throws on non-ok response', async () => { - global.fetch = vi.fn().mockResolvedValue({ + globalThis.fetch = vi.fn().mockResolvedValue({ ok: false, status: 500, statusText: 'Internal Server Error' @@ -226,7 +226,7 @@ describe('helpers utils', () => { }); it('propagates fetch network errors', async () => { - global.fetch = vi.fn().mockRejectedValue(new Error('Network error')); + globalThis.fetch = vi.fn().mockRejectedValue(new Error('Network error')); await expect(blobDownload('https://example.com/fail', 'test.csv')) .rejects.toThrow('Network error'); @@ -234,12 +234,12 @@ describe('helpers utils', () => { }); describe('blobDownloadFromEndpoint', () => { - let originalFetch: typeof global.fetch; + let originalFetch: typeof globalThis.fetch; let originalCreateObjectURL: typeof URL.createObjectURL; let originalRevokeObjectURL: typeof URL.revokeObjectURL; beforeEach(() => { - originalFetch = global.fetch; + originalFetch = globalThis.fetch; originalCreateObjectURL = URL.createObjectURL; originalRevokeObjectURL = URL.revokeObjectURL; window.location.pathname = '/ghost/settings/'; @@ -258,7 +258,7 @@ describe('helpers utils', () => { }); afterEach(() => { - global.fetch = originalFetch; + globalThis.fetch = originalFetch; URL.createObjectURL = originalCreateObjectURL; URL.revokeObjectURL = originalRevokeObjectURL; vi.restoreAllMocks(); @@ -266,14 +266,14 @@ describe('helpers utils', () => { it('constructs the full URL from apiRoot and path', async () => { const mockBlob = new Blob(['data'], {type: 'text/csv'}); - global.fetch = vi.fn().mockResolvedValue({ + globalThis.fetch = vi.fn().mockResolvedValue({ ok: true, blob: () => Promise.resolve(mockBlob) }); await blobDownloadFromEndpoint('/members/upload/?limit=all', 'members.csv'); - expect(global.fetch).toHaveBeenCalledWith( + expect(globalThis.fetch).toHaveBeenCalledWith( '/ghost/api/admin/members/upload/?limit=all', {method: 'GET'} ); @@ -282,14 +282,14 @@ describe('helpers utils', () => { it('includes subdirectory in the URL', async () => { window.location.pathname = '/blog/ghost/settings/'; const mockBlob = new Blob(['data'], {type: 'text/csv'}); - global.fetch = vi.fn().mockResolvedValue({ + globalThis.fetch = vi.fn().mockResolvedValue({ ok: true, blob: () => Promise.resolve(mockBlob) }); await blobDownloadFromEndpoint('/members/upload/?limit=all', 'members.csv'); - expect(global.fetch).toHaveBeenCalledWith( + expect(globalThis.fetch).toHaveBeenCalledWith( '/blog/ghost/api/admin/members/upload/?limit=all', {method: 'GET'} ); diff --git a/apps/admin-x-framework/test/utils/mock-fetch.ts b/apps/admin-x-framework/test/utils/mock-fetch.ts index 99e3275b14a..58b299fb7a7 100644 --- a/apps/admin-x-framework/test/utils/mock-fetch.ts +++ b/apps/admin-x-framework/test/utils/mock-fetch.ts @@ -1,23 +1,23 @@ /// -const originalFetch = global.fetch; - -type FetchArgs = Parameters; +const originalFetch = globalThis.fetch; export const withMockFetch = async ( {json = {}, headers = {}, status = 200, ok = true}: {json?: unknown; headers?: Record; status?: number; ok?: boolean}, callback: (mock: any) => void | Promise ) => { - const mockFetch = vi.fn>(() => Promise.resolve({ + const mockFetch = vi.fn(() => Promise.resolve({ json: () => Promise.resolve(json), headers: new Headers(headers), status, ok } as Response)); - global.fetch = mockFetch as any; // eslint-disable-line @typescript-eslint/no-explicit-any - - await callback(mockFetch.mock); + globalThis.fetch = mockFetch as any; // eslint-disable-line @typescript-eslint/no-explicit-any - global.fetch = originalFetch; + try { + await callback(mockFetch.mock); + } finally { + globalThis.fetch = originalFetch; + } }; diff --git a/apps/admin-x-settings/package.json b/apps/admin-x-settings/package.json index 1b9383c2495..ab0f432fb37 100644 --- a/apps/admin-x-settings/package.json +++ b/apps/admin-x-settings/package.json @@ -80,10 +80,10 @@ "eslint-plugin-react-refresh": "0.4.24", "eslint-plugin-tailwindcss": "4.0.0-beta.0", "tailwindcss": "^4.2.2", - "vite": "5.4.21", + "vite": "7.3.2", "vite-plugin-css-injected-by-js": "3.5.2", - "vite-plugin-svgr": "3.3.0", - "vitest": "1.6.1" + "vite-plugin-svgr": "4.5.0", + "vitest": "4.1.2" }, "nx": { "targets": { diff --git a/apps/posts/package.json b/apps/posts/package.json index 182d1425f85..e7034da65b6 100644 --- a/apps/posts/package.json +++ b/apps/posts/package.json @@ -44,15 +44,15 @@ "@testing-library/react": "14.3.1", "@types/jest": "29.5.14", "@types/react": "18.3.28", - "@vitest/coverage-v8": "^1.6.1", + "@vitest/coverage-v8": "^4.1.2", "eslint": "catalog:", "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.24", "eslint-plugin-tailwindcss": "4.0.0-beta.0", "msw": "2.12.14", "tailwindcss": "^4.2.2", - "vite": "5.4.21", - "vitest": "1.6.1" + "vite": "7.3.2", + "vitest": "4.1.2" }, "dependencies": { "@tryghost/admin-x-framework": "workspace:*", diff --git a/apps/stats/package.json b/apps/stats/package.json index 24517d26b4e..e049b45ef40 100644 --- a/apps/stats/package.json +++ b/apps/stats/package.json @@ -45,9 +45,10 @@ "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "14.3.1", "@types/jest": "29.5.14", + "@types/node": "22.19.17", "@types/react": "18.3.28", "@types/react-svg-map": "2.1.4", - "@vitest/coverage-v8": "^1.6.1", + "@vitest/coverage-v8": "^4.1.2", "@vitejs/plugin-react": "4.7.0", "dotenv": "17.3.1", "eslint": "catalog:", @@ -55,9 +56,9 @@ "eslint-plugin-react-refresh": "0.4.24", "eslint-plugin-tailwindcss": "4.0.0-beta.0", "tailwindcss": "^4.2.2", - "vite": "5.4.21", + "vite": "7.3.2", "vite-plugin-svgr": "4.5.0", - "vitest": "1.6.1" + "vitest": "4.1.2" }, "dependencies": { "@svg-maps/world": "1.0.1", diff --git a/apps/stats/test/unit/app.test.tsx b/apps/stats/test/unit/app.test.tsx index c2989c18350..3e1aa91be86 100644 --- a/apps/stats/test/unit/app.test.tsx +++ b/apps/stats/test/unit/app.test.tsx @@ -19,7 +19,7 @@ vi.mock('@tryghost/admin-x-framework', () => ({ RouterProvider: ({children}: {children: React.ReactNode}) =>
{children}
, AppProvider: ({children}: {children: React.ReactNode}) =>
{children}
, Outlet: () =>
Outlet content
, - lazyComponent: (fn: () => Promise<{default: React.ComponentType}>) => fn().then(({default: Component}) => ({Component})) + lazyComponent: () => () => Promise.resolve({Component: () => null}) })); vi.mock('@tryghost/shade/app', () => ({ diff --git a/apps/stats/test/unit/utils/content-helpers.test.ts b/apps/stats/test/unit/utils/content-helpers.test.ts index cba4aa44d83..3028a9dd5d7 100644 --- a/apps/stats/test/unit/utils/content-helpers.test.ts +++ b/apps/stats/test/unit/utils/content-helpers.test.ts @@ -53,10 +53,10 @@ describe('content-helpers', () => { }); describe('getContentDescription', () => { - let mockGetPeriodText: ReturnType>; + let mockGetPeriodText: ReturnType string>>; beforeEach(function () { - mockGetPeriodText = vi.fn<[number], string>(); + mockGetPeriodText = vi.fn<(range: number) => string>(); }); it('returns correct description for posts', () => { @@ -109,10 +109,10 @@ describe('content-helpers', () => { }); describe('getGrowthContentDescription', () => { - let mockGetPeriodText: ReturnType>; + let mockGetPeriodText: ReturnType string>>; beforeEach(function () { - mockGetPeriodText = vi.fn<[number], string>(); + mockGetPeriodText = vi.fn<(range: number) => string>(); }); it('returns correct growth description for posts', () => { diff --git a/apps/stats/test/unit/utils/url-helpers.test.ts b/apps/stats/test/unit/utils/url-helpers.test.ts index 9382cbcf27a..87a30373177 100644 --- a/apps/stats/test/unit/utils/url-helpers.test.ts +++ b/apps/stats/test/unit/utils/url-helpers.test.ts @@ -223,10 +223,10 @@ describe('url-helpers', () => { }); describe('getClickHandler', () => { - let mockNavigate: ReturnType; + let mockNavigate: ReturnType void>>; beforeEach(() => { - mockNavigate = vi.fn(); + mockNavigate = vi.fn<(path: string, options?: {crossApp?: boolean}) => void>(); mockWindowOpen.mockClear(); }); diff --git a/apps/stats/tsconfig.json b/apps/stats/tsconfig.json index 192ef77a0d8..c166c6e7d16 100644 --- a/apps/stats/tsconfig.json +++ b/apps/stats/tsconfig.json @@ -4,7 +4,7 @@ "lib": ["DOM", "DOM.Iterable", "ESNext"], "module": "ESNext", "skipLibCheck": true, - "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom/vitest"], + "types": ["vite/client", "vitest/globals", "@testing-library/jest-dom/vitest", "node"], /* Bundler mode */ "moduleResolution": "bundler", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7130ae6c94..0c5f1bfdf22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -206,11 +206,11 @@ importers: specifier: ^4.2.2 version: 4.2.2 vite: - specifier: 5.4.21 - version: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vitest: - specifier: 1.6.1 - version: 1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 4.1.2 + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) apps/admin: dependencies: @@ -549,10 +549,10 @@ importers: version: 18.3.7(@types/react@18.3.28) '@vitejs/plugin-react': specifier: 4.7.0 - version: 4.7.0(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + version: 4.7.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/coverage-v8': - specifier: ^1.6.1 - version: 1.6.1(vitest@1.6.1(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + specifier: ^4.1.2 + version: 4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) c8: specifier: 10.1.3 version: 10.1.3 @@ -581,17 +581,17 @@ importers: specifier: 5.9.3 version: 5.9.3 vite: - specifier: 5.4.21 - version: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-plugin-css-injected-by-js: specifier: 3.5.2 - version: 3.5.2(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + version: 3.5.2(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plugin-svgr: - specifier: 3.3.0 - version: 3.3.0(rollup@4.60.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + specifier: 4.5.0 + version: 4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: - specifier: 1.6.1 - version: 1.6.1(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 4.1.2 + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) apps/admin-x-settings: dependencies: @@ -694,7 +694,7 @@ importers: version: 13.15.10 '@vitejs/plugin-react': specifier: 4.7.0 - version: 4.7.0(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + version: 4.7.0(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) eslint: specifier: 'catalog:' version: 8.57.1 @@ -711,17 +711,17 @@ importers: specifier: ^4.2.2 version: 4.2.2 vite: - specifier: 5.4.21 - version: 5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 7.3.2 + version: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-plugin-css-injected-by-js: specifier: 3.5.2 - version: 3.5.2(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + version: 3.5.2(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plugin-svgr: - specifier: 3.3.0 - version: 3.3.0(rollup@4.60.0)(typescript@5.9.3)(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + specifier: 4.5.0 + version: 4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: - specifier: 1.6.1 - version: 1.6.1(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 4.1.2 + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) apps/announcement-bar: dependencies: @@ -1021,8 +1021,8 @@ importers: specifier: 18.3.28 version: 18.3.28 '@vitest/coverage-v8': - specifier: ^1.6.1 - version: 1.6.1(vitest@1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + specifier: ^4.1.2 + version: 4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) eslint: specifier: 'catalog:' version: 8.57.1 @@ -1042,11 +1042,11 @@ importers: specifier: ^4.2.2 version: 4.2.2 vite: - specifier: 5.4.21 - version: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 7.3.2 + version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vitest: - specifier: 1.6.1 - version: 1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 4.1.2 + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) apps/shade: dependencies: @@ -1435,6 +1435,9 @@ importers: '@types/jest': specifier: 29.5.14 version: 29.5.14 + '@types/node': + specifier: 22.19.17 + version: 22.19.17 '@types/react': specifier: 18.3.28 version: 18.3.28 @@ -1443,10 +1446,10 @@ importers: version: 2.1.4 '@vitejs/plugin-react': specifier: 4.7.0 - version: 4.7.0(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + version: 4.7.0(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/coverage-v8': - specifier: ^1.6.1 - version: 1.6.1(vitest@1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + specifier: ^4.1.2 + version: 4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) dotenv: specifier: 17.3.1 version: 17.3.1 @@ -1466,14 +1469,14 @@ importers: specifier: ^4.2.2 version: 4.2.2 vite: - specifier: 5.4.21 - version: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 7.3.2 + version: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) vite-plugin-svgr: specifier: 4.5.0 - version: 4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) + version: 4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: - specifier: 1.6.1 - version: 1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + specifier: 4.1.2 + version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) e2e: devDependencies: @@ -9494,6 +9497,15 @@ packages: '@vitest/browser': optional: true + '@vitest/coverage-v8@4.1.5': + resolution: {integrity: sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==} + peerDependencies: + '@vitest/browser': 4.1.5 + vitest: 4.1.5 + peerDependenciesMeta: + '@vitest/browser': + optional: true + '@vitest/expect@1.6.1': resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} @@ -9531,6 +9543,9 @@ packages: '@vitest/pretty-format@4.1.2': resolution: {integrity: sha512-dwQga8aejqeuB+TvXCMzSQemvV9hNEtDDpgUKDzOmNQayl2OG241PSWeJwKRH3CiC+sESrmoFd49rfnq7T4RnA==} + '@vitest/pretty-format@4.1.5': + resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} + '@vitest/runner@1.6.1': resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} @@ -9572,6 +9587,9 @@ packages: '@vitest/utils@4.1.2': resolution: {integrity: sha512-xw2/TiX82lQHA06cgbqRKFb5lCAy3axQ4H4SoUFhUsg+wztiet+co86IAMDtF6Vm1hc7J6j09oh/rgDn+JdKIQ==} + '@vitest/utils@4.1.5': + resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} + '@webassemblyjs/ast@1.14.1': resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} @@ -10089,6 +10107,9 @@ packages: ast-v8-to-istanbul@0.3.12: resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + ast-v8-to-istanbul@1.0.0: + resolution: {integrity: sha512-1fSfIwuDICFA4LKkCzRPO7F0hzFf0B7+Xqrl27ynQaa+Rh0e1Es0v6kWHPott3lU10AyAr7oKHa65OppjLn3Rg==} + astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -16695,6 +16716,9 @@ packages: magicast@0.3.5: resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + magicast@0.5.2: + resolution: {integrity: sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==} + mailgun.js@10.4.0: resolution: {integrity: sha512-YrdaZEAJwwjXGBTfZTNQ1LM7tmkdUaz2NpZEu7+zULcG4Wrlhd7cWSNZW0bxT3bP48k5N0mZWz8C2f9gc2+Geg==} engines: {node: '>=18.0.0'} @@ -25236,6 +25260,14 @@ snapshots: '@inquirer/ansi@1.0.2': {} + '@inquirer/confirm@5.1.21(@types/node@22.19.17)': + dependencies: + '@inquirer/core': 10.3.2(@types/node@22.19.17) + '@inquirer/type': 3.0.10(@types/node@22.19.17) + optionalDependencies: + '@types/node': 22.19.17 + optional: true + '@inquirer/confirm@5.1.21(@types/node@25.6.0)': dependencies: '@inquirer/core': 10.3.2(@types/node@25.6.0) @@ -25243,6 +25275,20 @@ snapshots: optionalDependencies: '@types/node': 25.6.0 + '@inquirer/core@10.3.2(@types/node@22.19.17)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@22.19.17) + cli-width: 4.1.0 + mute-stream: 2.0.0 + signal-exit: 4.1.0 + wrap-ansi: 6.2.0 + yoctocolors-cjs: 2.1.3 + optionalDependencies: + '@types/node': 22.19.17 + optional: true + '@inquirer/core@10.3.2(@types/node@25.6.0)': dependencies: '@inquirer/ansi': 1.0.2 @@ -25265,6 +25311,11 @@ snapshots: '@inquirer/figures@1.0.15': {} + '@inquirer/type@3.0.10(@types/node@22.19.17)': + optionalDependencies: + '@types/node': 22.19.17 + optional: true + '@inquirer/type@3.0.10(@types/node@25.6.0)': optionalDependencies: '@types/node': 25.6.0 @@ -31026,6 +31077,30 @@ snapshots: transitivePeerDependencies: - supports-color + '@vitejs/plugin-react@4.7.0(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-react@4.7.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - supports-color + '@vitest/coverage-v8@0.34.6(vitest@1.6.1(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1))': dependencies: '@ampproject/remapping': 2.3.0 @@ -31062,10 +31137,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@1.6.1(vitest@1.6.1(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1))': + '@vitest/coverage-v8@3.2.4(vitest@3.2.4)': dependencies: '@ampproject/remapping': 2.3.0 - '@bcoe/v8-coverage': 0.2.3 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.12 debug: 4.4.3(supports-color@5.5.0) istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 @@ -31073,51 +31149,54 @@ snapshots: istanbul-reports: 3.2.0 magic-string: 0.30.21 magicast: 0.3.5 - picocolors: 1.1.1 std-env: 3.10.0 - strip-literal: 2.1.1 - test-exclude: 6.0.0 - vitest: 1.6.1(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + test-exclude: 7.0.2 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/node@25.6.0)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - '@vitest/coverage-v8@1.6.1(vitest@1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1))': + '@vitest/coverage-v8@4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: - '@ampproject/remapping': 2.3.0 - '@bcoe/v8-coverage': 0.2.3 - debug: 4.4.3(supports-color@5.5.0) + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.5 + ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - magic-string: 0.30.21 - magicast: 0.3.5 - picocolors: 1.1.1 - std-env: 3.10.0 - strip-literal: 2.1.1 - test-exclude: 6.0.0 - vitest: 1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - transitivePeerDependencies: - - supports-color + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - '@vitest/coverage-v8@3.2.4(vitest@3.2.4)': + '@vitest/coverage-v8@4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)))': dependencies: - '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 - ast-v8-to-istanbul: 0.3.12 - debug: 4.4.3(supports-color@5.5.0) + '@vitest/utils': 4.1.5 + ast-v8-to-istanbul: 1.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 istanbul-reports: 3.2.0 - magic-string: 0.30.21 - magicast: 0.3.5 - std-env: 3.10.0 - test-exclude: 7.0.2 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@25.6.0)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + + '@vitest/coverage-v8@4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)))': + dependencies: + '@bcoe/v8-coverage': 1.0.2 + '@vitest/utils': 4.1.5 + ast-v8-to-istanbul: 1.0.0 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-reports: 3.2.0 + magicast: 0.5.2 + obug: 2.1.1 + std-env: 4.0.0 + tinyrainbow: 3.1.0 + vitest: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/expect@1.6.1': dependencies: @@ -31151,6 +31230,15 @@ snapshots: msw: 2.12.14(@types/node@25.6.0)(typescript@5.9.3) vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + '@vitest/mocker@4.1.2(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': + dependencies: + '@vitest/spy': 4.1.2 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + msw: 2.12.14(@types/node@22.19.17)(typescript@5.9.3) + vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + '@vitest/mocker@4.1.2(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@vitest/spy': 4.1.2 @@ -31168,6 +31256,10 @@ snapshots: dependencies: tinyrainbow: 3.1.0 + '@vitest/pretty-format@4.1.5': + dependencies: + tinyrainbow: 3.1.0 + '@vitest/runner@1.6.1': dependencies: '@vitest/utils': 1.6.1 @@ -31244,6 +31336,12 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 + '@vitest/utils@4.1.5': + dependencies: + '@vitest/pretty-format': 4.1.5 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + '@webassemblyjs/ast@1.14.1': dependencies: '@webassemblyjs/helper-numbers': 1.13.2 @@ -31836,6 +31934,12 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 + ast-v8-to-istanbul@1.0.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + astral-regex@2.0.0: {} async-disk-cache@1.3.5: @@ -41162,6 +41266,12 @@ snapshots: '@babel/types': 7.29.0 source-map-js: 1.2.1 + magicast@0.5.2: + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + source-map-js: 1.2.1 + mailgun.js@10.4.0: dependencies: axios: 1.16.0 @@ -41798,6 +41908,32 @@ snapshots: ms@2.1.3: {} + msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3): + dependencies: + '@inquirer/confirm': 5.1.21(@types/node@22.19.17) + '@mswjs/interceptors': 0.41.3 + '@open-draft/deferred-promise': 2.2.0 + '@types/statuses': 2.0.6 + cookie: 1.1.1 + graphql: 16.13.2 + headers-polyfill: 4.0.3 + is-node-process: 1.2.0 + outvariant: 1.4.3 + path-to-regexp: 6.3.0 + picocolors: 1.1.1 + rettime: 0.10.1 + statuses: 2.0.2 + strict-event-emitter: 0.5.1 + tough-cookie: 6.0.1 + type-fest: 5.5.0 + until-async: 3.0.2 + yargs: 17.7.2 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + optional: true + msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3): dependencies: '@inquirer/confirm': 5.1.21(@types/node@25.6.0) @@ -47049,14 +47185,18 @@ snapshots: - tsx - yaml - vite-plugin-css-injected-by-js@3.5.2(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)): - dependencies: - vite: 5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - vite-plugin-css-injected-by-js@3.5.2(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)): dependencies: vite: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + vite-plugin-css-injected-by-js@3.5.2(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + + vite-plugin-css-injected-by-js@3.5.2(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + vite-plugin-svgr@3.3.0(rollup@4.60.0)(typescript@5.9.3)(vite@5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.0) @@ -47079,12 +47219,23 @@ snapshots: - supports-color - typescript - vite-plugin-svgr@4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)): + vite-plugin-svgr@4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.0) '@svgr/core': 8.1.0(typescript@5.9.3) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) - vite: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) + vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + transitivePeerDependencies: + - rollup + - supports-color + - typescript + + vite-plugin-svgr@4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) + '@svgr/core': 8.1.0(typescript@5.9.3) + '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.3)) + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - rollup - supports-color @@ -47125,6 +47276,24 @@ snapshots: lightningcss: 1.31.1 terser: 5.46.1 + vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): + dependencies: + esbuild: 0.27.4 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + postcss: 8.5.6 + rollup: 4.60.0 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.19.17 + fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.6.4 + lightningcss: 1.31.1 + terser: 5.46.1 + tsx: 4.21.0 + yaml: 2.8.3 + vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: esbuild: 0.27.4 @@ -47178,41 +47347,6 @@ snapshots: - supports-color - terser - vitest@1.6.1(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1): - dependencies: - '@vitest/expect': 1.6.1 - '@vitest/runner': 1.6.1 - '@vitest/snapshot': 1.6.1 - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 - acorn-walk: 8.3.5 - chai: 4.5.0 - debug: 4.4.3(supports-color@5.5.0) - execa: 8.0.1 - local-pkg: 0.5.1 - magic-string: 0.30.21 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.10.0 - strip-literal: 2.1.1 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.21(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - vite-node: 1.6.1(@types/node@22.19.17)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 22.19.17 - jsdom: 29.0.2(@noble/hashes@1.8.0) - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - vitest@1.6.1(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1): dependencies: '@vitest/expect': 1.6.1 @@ -47248,41 +47382,6 @@ snapshots: - supports-color - terser - vitest@1.6.1(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1): - dependencies: - '@vitest/expect': 1.6.1 - '@vitest/runner': 1.6.1 - '@vitest/snapshot': 1.6.1 - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 - acorn-walk: 8.3.5 - chai: 4.5.0 - debug: 4.4.3(supports-color@5.5.0) - execa: 8.0.1 - local-pkg: 0.5.1 - magic-string: 0.30.21 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.10.0 - strip-literal: 2.1.1 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - vite-node: 1.6.1(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.6.0 - jsdom: 29.0.2(@noble/hashes@1.8.0) - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - vitest@3.2.4(@types/node@25.6.0)(@vitest/ui@3.2.4)(jiti@2.6.1)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.6.4)(lightningcss@1.31.1)(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: '@types/chai': 5.2.3 @@ -47326,6 +47425,35 @@ snapshots: - tsx - yaml + vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.1.1 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 22.19.17 + jsdom: 29.0.2(@noble/hashes@1.8.0) + transitivePeerDependencies: + - msw + vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@28.1.0(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.2 @@ -47355,6 +47483,35 @@ snapshots: transitivePeerDependencies: - msw + vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): + dependencies: + '@vitest/expect': 4.1.2 + '@vitest/mocker': 4.1.2(msw@2.12.14(@types/node@25.6.0)(typescript@5.9.3))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.2 + '@vitest/runner': 4.1.2 + '@vitest/snapshot': 4.1.2 + '@vitest/spy': 4.1.2 + '@vitest/utils': 4.1.2 + es-module-lexer: 2.0.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.1.1 + tinyglobby: 0.2.15 + tinyrainbow: 3.1.0 + vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 25.6.0 + jsdom: 29.0.2(@noble/hashes@1.8.0) + transitivePeerDependencies: + - msw + vm-browserify@1.1.2: {} w3c-hr-time@1.0.2: From 0009ffbbc4eac6e5239fff0906148055c6a8d186 Mon Sep 17 00:00:00 2001 From: Steve Larson <9larsons@gmail.com> Date: Wed, 6 May 2026 21:02:01 -0500 Subject: [PATCH 8/8] Removed redundant vite plugin declarations from admin-x consumers (#27754) no ref Five vite-plugin declarations in three workspaces were redundant. Each consumer's `vite.config.*` either delegates to `@tryghost/admin-x-framework/vite` (which already imports the plugins itself) or doesn't import the plugin at all. Removing the duplicate `package.json` entries makes the dep contract honest and removes ~25 lines from the lockfile. --- apps/admin-x-settings/package.json | 3 --- apps/comments-ui/package.json | 3 +-- apps/stats/package.json | 1 - pnpm-lock.yaml | 31 ------------------------------ 4 files changed, 1 insertion(+), 37 deletions(-) diff --git a/apps/admin-x-settings/package.json b/apps/admin-x-settings/package.json index ab0f432fb37..3f930a0496e 100644 --- a/apps/admin-x-settings/package.json +++ b/apps/admin-x-settings/package.json @@ -74,15 +74,12 @@ "@types/react": "18.3.28", "@types/react-dom": "18.3.7", "@types/validator": "13.15.10", - "@vitejs/plugin-react": "4.7.0", "eslint": "catalog:", "eslint-plugin-react-hooks": "4.6.2", "eslint-plugin-react-refresh": "0.4.24", "eslint-plugin-tailwindcss": "4.0.0-beta.0", "tailwindcss": "^4.2.2", "vite": "7.3.2", - "vite-plugin-css-injected-by-js": "3.5.2", - "vite-plugin-svgr": "4.5.0", "vitest": "4.1.2" }, "nx": { diff --git a/apps/comments-ui/package.json b/apps/comments-ui/package.json index 6d9689ce034..c3303ce8cc9 100644 --- a/apps/comments-ui/package.json +++ b/apps/comments-ui/package.json @@ -1,6 +1,6 @@ { "name": "@tryghost/comments-ui", - "version": "1.4.11", + "version": "1.4.12", "license": "MIT", "repository": "https://github.com/TryGhost/Ghost", "author": "Ghost Foundation", @@ -81,7 +81,6 @@ "sinon": "^21.1.1", "tailwindcss": "3.4.18", "vite": "5.4.21", - "vite-plugin-css-injected-by-js": "3.5.2", "vite-plugin-svgr": "3.3.0", "vitest": "1.6.1" }, diff --git a/apps/stats/package.json b/apps/stats/package.json index e049b45ef40..572ebe06646 100644 --- a/apps/stats/package.json +++ b/apps/stats/package.json @@ -49,7 +49,6 @@ "@types/react": "18.3.28", "@types/react-svg-map": "2.1.4", "@vitest/coverage-v8": "^4.1.2", - "@vitejs/plugin-react": "4.7.0", "dotenv": "17.3.1", "eslint": "catalog:", "eslint-plugin-react-hooks": "4.6.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c5f1bfdf22..21bf22799e8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -692,9 +692,6 @@ importers: '@types/validator': specifier: 13.15.10 version: 13.15.10 - '@vitejs/plugin-react': - specifier: 4.7.0 - version: 4.7.0(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) eslint: specifier: 'catalog:' version: 8.57.1 @@ -713,12 +710,6 @@ importers: vite: specifier: 7.3.2 version: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-css-injected-by-js: - specifier: 3.5.2 - version: 3.5.2(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) - vite-plugin-svgr: - specifier: 4.5.0 - version: 4.5.0(rollup@4.60.0)(typescript@5.9.3)(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) vitest: specifier: 4.1.2 version: 4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) @@ -871,9 +862,6 @@ importers: vite: specifier: 5.4.21 version: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - vite-plugin-css-injected-by-js: - specifier: 3.5.2 - version: 3.5.2(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) vite-plugin-svgr: specifier: 3.3.0 version: 3.3.0(rollup@4.60.0)(typescript@5.9.3)(vite@5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)) @@ -1444,9 +1432,6 @@ importers: '@types/react-svg-map': specifier: 2.1.4 version: 2.1.4 - '@vitejs/plugin-react': - specifier: 4.7.0 - version: 4.7.0(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/coverage-v8': specifier: ^4.1.2 version: 4.1.5(vitest@4.1.2(@opentelemetry/api@1.9.1)(@types/node@22.19.17)(jsdom@29.0.2(@noble/hashes@1.8.0))(msw@2.12.14(@types/node@22.19.17)(typescript@5.9.3))(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))) @@ -31077,18 +31062,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@vitejs/plugin-react@4.7.0(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - transitivePeerDependencies: - - supports-color - '@vitejs/plugin-react@4.7.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@babel/core': 7.29.0 @@ -47189,10 +47162,6 @@ snapshots: dependencies: vite: 5.4.21(@types/node@25.6.0)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1) - vite-plugin-css-injected-by-js@3.5.2(vite@7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): - dependencies: - vite: 7.3.2(@types/node@22.19.17)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-css-injected-by-js@3.5.2(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(less@4.6.4)(lightningcss@1.31.1)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3)