From 6d54370f01f712dfad9e531935bfdfc205f13e1d Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 16:20:08 +0900 Subject: [PATCH 01/87] chore(deps): update [misskey-js] update dependencies (major) (#16177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * chore(deps): update [misskey-js] update dependencies * enhance(misskey-js): テストスイートをVitestに置き換え (#16340) * enhance(misskey-js): テストスイートをVitestに置き換え * fix: 変なものが混入 * fix test, lint --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com> --- packages/misskey-js/.swcrc | 23 -- packages/misskey-js/eslint.config.js | 2 +- packages/misskey-js/generator/package.json | 2 +- packages/misskey-js/jest.config.cjs | 207 --------------- packages/misskey-js/package.json | 19 +- packages/misskey-js/test-d/api.ts | 1 + packages/misskey-js/test-d/streaming.ts | 1 + packages/misskey-js/test/api.ts | 266 ++++++++++--------- packages/misskey-js/test/streaming.ts | 3 +- packages/misskey-js/vitest.config.ts | 17 ++ pnpm-lock.yaml | 287 +++++---------------- 11 files changed, 233 insertions(+), 595 deletions(-) delete mode 100644 packages/misskey-js/.swcrc delete mode 100644 packages/misskey-js/jest.config.cjs create mode 100644 packages/misskey-js/vitest.config.ts diff --git a/packages/misskey-js/.swcrc b/packages/misskey-js/.swcrc deleted file mode 100644 index 6fd7486370..0000000000 --- a/packages/misskey-js/.swcrc +++ /dev/null @@ -1,23 +0,0 @@ -{ - "$schema": "https://swc.rs/schema.json", - "jsc": { - "parser": { - "syntax": "typescript", - "dynamicImport": true, - "decorators": true - }, - "transform": { - "legacyDecorator": true, - "decoratorMetadata": true - }, - "experimental": { - "keepImportAssertions": true - }, - "baseUrl": "src", - "paths": { - "@/*": ["*"] - }, - "target": "es2022" - }, - "minify": false -} diff --git a/packages/misskey-js/eslint.config.js b/packages/misskey-js/eslint.config.js index 496892d897..5a1d4315b5 100644 --- a/packages/misskey-js/eslint.config.js +++ b/packages/misskey-js/eslint.config.js @@ -9,7 +9,7 @@ export default [ '**/node_modules', 'built', 'coverage', - 'jest.config.ts', + 'vitest.config.ts', 'test', 'test-d', 'generator', diff --git a/packages/misskey-js/generator/package.json b/packages/misskey-js/generator/package.json index f566d6dc21..02cbe56b3d 100644 --- a/packages/misskey-js/generator/package.json +++ b/packages/misskey-js/generator/package.json @@ -7,7 +7,7 @@ "generate": "tsx src/generator.ts && eslint ./built/**/*.ts --fix" }, "devDependencies": { - "@readme/openapi-parser": "2.7.0", + "@readme/openapi-parser": "5.0.0", "@types/node": "22.16.4", "@typescript-eslint/eslint-plugin": "8.37.0", "@typescript-eslint/parser": "8.37.0", diff --git a/packages/misskey-js/jest.config.cjs b/packages/misskey-js/jest.config.cjs deleted file mode 100644 index 1230a4b5e2..0000000000 --- a/packages/misskey-js/jest.config.cjs +++ /dev/null @@ -1,207 +0,0 @@ -/* -* For a detailed explanation regarding each configuration property and type check, visit: -* https://jestjs.io/docs/en/configuration.html -*/ - -module.exports = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "C:\\Users\\ai\\AppData\\Local\\Temp\\jest", - - // Automatically clear mock calls and instances between every test - // clearMocks: false, - - // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: "v8", - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "json", - // "jsx", - // "ts", - // "tsx", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - moduleNameMapper: { - // Do not resolve .wasm.js to .wasm by the rule below - '^(.+)\\.wasm\\.js$': '$1.wasm.js', - // SWC converts @/foo/bar.js to `../../src/foo/bar.js`, and then this rule - // converts it again to `../../src/foo/bar` which then can be resolved to - // `.ts` files. - // See https://github.com/swc-project/jest/issues/64#issuecomment-1029753225 - // TODO: Use `--allowImportingTsExtensions` on TypeScript 5.0 so that we can - // directly import `.ts` files without this hack. - '^((?:\\.{1,2}|[A-Z:])*/.*)\\.js$': '$1', - }, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - roots: [ - "" - ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - testMatch: [ - "**/__tests__/**/*.[jt]s?(x)", - "**/?(*.)+(spec|test).[tj]s?(x)", - "/test/**/*" - ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jasmine2", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - transform: { - "^.+\\.(t|j)sx?$": ["@swc/jest"], - }, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "\\\\node_modules\\\\", - // "\\.pnp\\.[^\\\\]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 8ba836942f..ad4bfa24c6 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -25,8 +25,8 @@ "eslint": "eslint './**/*.{js,jsx,ts,tsx}'", "typecheck": "tsc --noEmit", "lint": "pnpm typecheck && pnpm eslint", - "jest": "jest --coverage --detectOpenHandles", - "test": "pnpm jest && pnpm tsd", + "vitest": "vitest run --coverage", + "test": "pnpm vitest && pnpm tsd", "update-autogen-code": "pnpm --filter misskey-js-type-generator generate && ncp generator/built/autogen src/autogen" }, "repository": { @@ -36,22 +36,19 @@ }, "devDependencies": { "@microsoft/api-extractor": "7.52.8", - "@swc/jest": "0.2.39", - "@types/jest": "29.5.14", "@types/node": "22.16.4", "@typescript-eslint/eslint-plugin": "8.37.0", "@typescript-eslint/parser": "8.37.0", - "jest": "29.7.0", - "jest-fetch-mock": "3.0.3", - "jest-websocket-mock": "2.5.0", - "mock-socket": "9.3.1", + "@vitest/coverage-v8": "3.2.4", + "esbuild": "0.25.6", + "execa": "9.6.0", + "glob": "11.0.3", "ncp": "2.0.0", "nodemon": "3.1.10", - "execa": "8.0.1", "tsd": "0.32.0", "typescript": "5.8.3", - "esbuild": "0.25.6", - "glob": "11.0.3" + "vitest": "3.2.4", + "vitest-websocket-mock": "0.5.0" }, "files": [ "built" diff --git a/packages/misskey-js/test-d/api.ts b/packages/misskey-js/test-d/api.ts index ca6d8dcb88..e71a3e2b8b 100644 --- a/packages/misskey-js/test-d/api.ts +++ b/packages/misskey-js/test-d/api.ts @@ -1,3 +1,4 @@ +import { describe, test } from 'vitest'; import { expectType } from 'tsd'; import * as Misskey from '../src/index.js'; diff --git a/packages/misskey-js/test-d/streaming.ts b/packages/misskey-js/test-d/streaming.ts index b46b06e4df..7ce737261d 100644 --- a/packages/misskey-js/test-d/streaming.ts +++ b/packages/misskey-js/test-d/streaming.ts @@ -1,3 +1,4 @@ +import { describe, test } from 'vitest'; import { expectType } from 'tsd'; import * as Misskey from '../src/index.js'; diff --git a/packages/misskey-js/test/api.ts b/packages/misskey-js/test/api.ts index b8ad2225c8..c0f3a47f77 100644 --- a/packages/misskey-js/test/api.ts +++ b/packages/misskey-js/test/api.ts @@ -1,41 +1,24 @@ -import { enableFetchMocks } from 'jest-fetch-mock'; +import { vi, describe, test, expect } from 'vitest'; import { APIClient, isAPIError } from '../src/api.js'; -enableFetchMocks(); - -function getFetchCall(call: any[]) { - const { body, method } = call[1]; - const contentType = call[1].headers['Content-Type']; - if ( - body == null || - (contentType === 'application/json' && typeof body !== 'string') || - (contentType === 'multipart/form-data' && !(body instanceof FormData)) - ) { - throw new Error('invalid body'); - } - return { - url: call[0], - method: method, - contentType: contentType, - body: body instanceof FormData ? Object.fromEntries(body.entries()) : JSON.parse(body), - }; -} - describe('API', () => { test('success', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - const body = await req.json(); - if (req.method == 'POST' && req.url == 'https://misskey.test/api/i') { - if (body.i === 'TOKEN') { - return JSON.stringify({ id: 'foo' }); - } else { - return { status: 400 }; + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async (url, options) => { + if (url === 'https://misskey.test/api/i' && options?.method === 'POST') { + if (options.body) { + const body = JSON.parse(options.body as string); + if (body.i === 'TOKEN') { + return new Response(JSON.stringify({ id: 'foo' }), { status: 200 }); + } + } + + return new Response(null, { status: 400 }); } - } else { - return { status: 404 }; - } - }); + + return new Response(null, { status: 404 }); + }); const cli = new APIClient({ origin: 'https://misskey.test', @@ -48,28 +31,38 @@ describe('API', () => { id: 'foo' }); - expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ - url: 'https://misskey.test/api/i', + fetch('https://misskey.test/api/i', { method: 'POST', - contentType: 'application/json', - body: { i: 'TOKEN' } + }) + + expect(fetchMock).toHaveBeenCalledWith('https://misskey.test/api/i', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'omit', + cache: 'no-cache', + body: JSON.stringify({ i: 'TOKEN' }), }); + + fetchMock.mockRestore(); }); test('with params', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - const body = await req.json(); - if (req.method == 'POST' && req.url == 'https://misskey.test/api/notes/show') { - if (body.i === 'TOKEN' && body.noteId === 'aaaaa') { - return JSON.stringify({ id: 'foo' }); - } else { - return { status: 400 }; + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async (url, options) => { + if (url === 'https://misskey.test/api/notes/show' && options?.method === 'POST') { + if (options.body) { + const body = JSON.parse(options.body as string); + if (body.i === 'TOKEN' && body.noteId === 'aaaaa') { + return new Response(JSON.stringify({ id: 'foo' }), { status: 200 }); + } + } + return new Response(null, { status: 400 }); } - } else { - return { status: 404 }; - } - }); + return new Response(null, { status: 404 }); + }); const cli = new APIClient({ origin: 'https://misskey.test', @@ -82,23 +75,34 @@ describe('API', () => { id: 'foo' }); - expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ - url: 'https://misskey.test/api/notes/show', + expect(fetchMock).toHaveBeenCalledWith('https://misskey.test/api/notes/show', { method: 'POST', - contentType: 'application/json', - body: { i: 'TOKEN', noteId: 'aaaaa' } + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'omit', + cache: 'no-cache', + body: JSON.stringify({ noteId: 'aaaaa', i: 'TOKEN' }), }); + + fetchMock.mockRestore(); }); test('multipart/form-data', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - if (req.method == 'POST' && req.url == 'https://misskey.test/api/drive/files/create') { - return JSON.stringify({ id: 'foo' }); - } else { - return { status: 404 }; - } - }); + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async (url, options) => { + if (url === 'https://misskey.test/api/drive/files/create' && options?.method === 'POST') { + if (options.body instanceof FormData) { + const file = options.body.get('file'); + if (file instanceof File && file.name === 'foo.txt') { + return new Response(JSON.stringify({ id: 'foo' }), { status: 200 }); + } + } + return new Response(null, { status: 400 }); + } + return new Response(null, { status: 404 }); + }); const cli = new APIClient({ origin: 'https://misskey.test', @@ -116,26 +120,26 @@ describe('API', () => { id: 'foo' }); - expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ - url: 'https://misskey.test/api/drive/files/create', + expect(fetchMock).toHaveBeenCalledWith('https://misskey.test/api/drive/files/create', { method: 'POST', - contentType: undefined, - body: { - i: 'TOKEN', - file: testFile, - } + body: expect.any(FormData), + headers: {}, + credentials: 'omit', + cache: 'no-cache', }); + + fetchMock.mockRestore(); }); test('204 No Content で null が返る', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - if (req.method == 'POST' && req.url == 'https://misskey.test/api/reset-password') { - return { status: 204 }; - } else { - return { status: 404 }; - } - }); + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async (url, options) => { + if (url === 'https://misskey.test/api/reset-password' && options?.method === 'POST') { + return new Response(null, { status: 204 }); + } + return new Response(null, { status: 404 }); + }); const cli = new APIClient({ origin: 'https://misskey.test', @@ -146,37 +150,42 @@ describe('API', () => { expect(res).toEqual(null); - expect(getFetchCall(fetchMock.mock.calls[0])).toEqual({ - url: 'https://misskey.test/api/reset-password', + expect(fetchMock).toHaveBeenCalledWith('https://misskey.test/api/reset-password', { method: 'POST', - contentType: 'application/json', - body: { i: 'TOKEN', token: 'aaa', password: 'aaa' } + headers: { + 'Content-Type': 'application/json', + }, + credentials: 'omit', + cache: 'no-cache', + body: JSON.stringify({ token: 'aaa', password: 'aaa', i: 'TOKEN' }), }); + + fetchMock.mockRestore(); }); test('インスタンスの credential が指定されていても引数で credential が null ならば null としてリクエストされる', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - const body = await req.json(); - if (req.method == 'POST' && req.url == 'https://misskey.test/api/i') { - if (typeof body.i === 'string') { - return JSON.stringify({ id: 'foo' }); - } else { - return { - status: 401, - body: JSON.stringify({ - error: { - message: 'Credential required.', - code: 'CREDENTIAL_REQUIRED', - id: '1384574d-a912-4b81-8601-c7b1c4085df1', - } - }) - }; + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async (url, options) => { + if (url === 'https://misskey.test/api/i' && options?.method === 'POST') { + if (options.body) { + const body = JSON.parse(options.body as string); + if (typeof body.i === 'string') { + return new Response(JSON.stringify({ id: 'foo' }), { status: 200 }); + } else { + return new Response(JSON.stringify({ + error: { + message: 'Credential required.', + code: 'CREDENTIAL_REQUIRED', + id: '1384574d-a912-4b81-8601-c7b1c4085df1', + } + }), { status: 401 }); + } + } + return new Response(null, { status: 400 }); } - } else { - return { status: 404 }; - } - }); + return new Response(null, { status: 404 }); + }); try { const cli = new APIClient({ @@ -187,24 +196,24 @@ describe('API', () => { await cli.request('i', {}, null); } catch (e) { expect(isAPIError(e)).toEqual(true); + } finally { + fetchMock.mockRestore(); } }); test('api error', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - return { - status: 500, - body: JSON.stringify({ + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async () => { + return new Response(JSON.stringify({ error: { message: 'Internal error occurred. Please contact us if the error persists.', code: 'INTERNAL_ERROR', id: '5d37dbcb-891e-41ca-a3d6-e690c97775ac', kind: 'server', }, - }) - }; - }); + }), { status: 500 }); + }); try { const cli = new APIClient({ @@ -216,12 +225,17 @@ describe('API', () => { } catch (e: any) { expect(isAPIError(e)).toEqual(true); expect(e.id).toEqual('5d37dbcb-891e-41ca-a3d6-e690c97775ac'); + } finally { + fetchMock.mockRestore(); } }); test('network error', async () => { - fetchMock.resetMocks(); - fetchMock.mockAbort(); + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async () => { + throw new Error('Network error'); + }); try { const cli = new APIClient({ @@ -232,17 +246,17 @@ describe('API', () => { await cli.request('i'); } catch (e) { expect(isAPIError(e)).toEqual(false); + } finally { + fetchMock.mockRestore(); } }); test('json parse error', async () => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async (req) => { - return { - status: 500, - body: 'I AM NOT JSON' - }; - }); + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async () => { + return new Response('I AM NOT JSON', { status: 500 }); + }); try { const cli = new APIClient({ @@ -253,18 +267,18 @@ describe('API', () => { await cli.request('i'); } catch (e) { expect(isAPIError(e)).toEqual(false); + } finally { + fetchMock.mockRestore(); } }); test('admin/roles/create の型が合う', async() => { - fetchMock.resetMocks(); - fetchMock.mockResponse(async () => { - return { + const fetchMock = vi + .spyOn(globalThis, 'fetch') + .mockImplementation(async () => { // 本来返すべき値は`Role`型だが、テストなのでお茶を濁す - status: 200, - body: '{}' - }; - }); + return new Response('{}', { status: 200 }); + }); const cli = new APIClient({ origin: 'https://misskey.test', @@ -292,5 +306,7 @@ describe('API', () => { }, target: 'manual', }); + + fetchMock.mockRestore(); }) }); diff --git a/packages/misskey-js/test/streaming.ts b/packages/misskey-js/test/streaming.ts index 7e784cd20c..c42cbced88 100644 --- a/packages/misskey-js/test/streaming.ts +++ b/packages/misskey-js/test/streaming.ts @@ -1,4 +1,5 @@ -import WS from 'jest-websocket-mock'; +import { describe, test, expect } from 'vitest'; +import WS from 'vitest-websocket-mock'; import Stream from '../src/streaming.js'; describe('Streaming', () => { diff --git a/packages/misskey-js/vitest.config.ts b/packages/misskey-js/vitest.config.ts new file mode 100644 index 0000000000..e6b15b621b --- /dev/null +++ b/packages/misskey-js/vitest.config.ts @@ -0,0 +1,17 @@ +import { defineConfig, configDefaults } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ['test/**/*.ts'], + coverage: { + exclude: [ + ...configDefaults.coverage.exclude!, + 'src/autogen/**/*', + 'generator/**/*', + 'built/**/*', + 'test-d/**/*', + 'build.js', + ], + } + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2a446cbdfb..570ab04a39 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1372,12 +1372,6 @@ importers: '@microsoft/api-extractor': specifier: 7.52.8 version: 7.52.8(@types/node@22.16.4) - '@swc/jest': - specifier: 0.2.39 - version: 0.2.39(@swc/core@1.12.0) - '@types/jest': - specifier: 29.5.14 - version: 29.5.14 '@types/node': specifier: 22.16.4 version: 22.16.4 @@ -1387,27 +1381,18 @@ importers: '@typescript-eslint/parser': specifier: 8.37.0 version: 8.37.0(eslint@9.31.0)(typescript@5.8.3) + '@vitest/coverage-v8': + specifier: 3.2.4 + version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)) esbuild: specifier: 0.25.6 version: 0.25.6 execa: - specifier: 8.0.1 - version: 8.0.1 + specifier: 9.6.0 + version: 9.6.0 glob: specifier: 11.0.3 version: 11.0.3 - jest: - specifier: 29.7.0 - version: 29.7.0(@types/node@22.16.4) - jest-fetch-mock: - specifier: 3.0.3 - version: 3.0.3(encoding@0.1.13) - jest-websocket-mock: - specifier: 2.5.0 - version: 2.5.0 - mock-socket: - specifier: 9.3.1 - version: 9.3.1 ncp: specifier: 2.0.0 version: 2.0.0 @@ -1420,12 +1405,18 @@ importers: typescript: specifier: 5.8.3 version: 5.8.3 + vitest: + specifier: 3.2.4 + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3) + vitest-websocket-mock: + specifier: 0.5.0 + version: 0.5.0(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)) packages/misskey-js/generator: devDependencies: '@readme/openapi-parser': - specifier: 2.7.0 - version: 2.7.0(openapi-types@12.1.3) + specifier: 5.0.0 + version: 5.0.0(openapi-types@12.1.3) '@types/node': specifier: 22.16.4 version: 22.16.4 @@ -1543,8 +1534,9 @@ packages: '@analytics/type-utils@0.6.2': resolution: {integrity: sha512-TD+xbmsBLyYy/IxFimW/YL/9L2IEnM7/EoV9Aeh56U64Ify8o27HJcKjo38XY9Tcn0uOq1AX3thkKgvtWvwFQg==} - '@apidevtools/swagger-methods@3.0.2': - resolution: {integrity: sha512-QAkD5kK2b1WfjDS/UQn/qQkbwF31uqRjPTrsCs5ZG9BQGAkjwvqGFjjPqAuzac/IYzpPtRzjCP1WrTuAIjMrXg==} + '@apidevtools/json-schema-ref-parser@14.1.1': + resolution: {integrity: sha512-uGF1YGOzzD50L7HLNWclXmsEhQflw8/zZHIz0/AzkJrKL5r9PceUipZxR/cp/8veTk4TVfdDJLyIwXLjaP5ePg==} + engines: {node: '>= 20'} '@asamuzakjp/css-color@2.8.3': resolution: {integrity: sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==} @@ -2567,10 +2559,6 @@ packages: resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/create-cache-key-function@30.0.2': - resolution: {integrity: sha512-AwlDAHwEHDi+etw9vKWx9HeIApVos8GD/sSTpHtDkqhm9OWuEUPKKPP6EaS17yv0GSzBB3TeeJFLyJ5LPjRqWg==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/environment@29.7.0': resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2591,10 +2579,6 @@ packages: resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/pattern@30.0.1': - resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/reporters@29.7.0': resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2608,10 +2592,6 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/schemas@30.0.1': - resolution: {integrity: sha512-+g/1TKjFuGrf1Hh0QPCv0gISwBxJ+MQSNXmG9zjHy7BmFhtoJ9fdNhWJp3qUKRi93AOZHXtdxZgJ1vAtz6z65w==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@jest/source-map@29.6.3': resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2632,10 +2612,6 @@ packages: resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@jest/types@30.0.1': - resolution: {integrity: sha512-HGwoYRVF0QSKJu1ZQX0o5ZrUrrhj0aOOFA8hXrumD7SIzjouevhawbTjmXdwOmURdGluU9DM/XvGm3NyFoiQjw==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0': resolution: {integrity: sha512-qYDdL7fPwLRI+bJNurVcis+tNgJmvWjH4YTBGXTA8xMuxFrnAz6E5o35iyzyKbq5J5Lr8mJGfrR5GXl+WGwhgQ==} peerDependencies: @@ -2645,29 +2621,21 @@ packages: typescript: optional: true - '@jridgewell/gen-mapping@0.3.5': - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.12': + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} '@jridgewell/resolve-uri@3.1.0': resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} - '@jridgewell/set-array@1.2.1': - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.6': resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} - '@jridgewell/trace-mapping@0.3.25': - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - - '@jsdevtools/ono@7.1.3': - resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + '@jridgewell/trace-mapping@0.3.29': + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} '@kurkle/color@0.3.2': resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==} @@ -3255,19 +3223,15 @@ packages: '@prisma/instrumentation@5.22.0': resolution: {integrity: sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q==} - '@readme/better-ajv-errors@2.2.2': - resolution: {integrity: sha512-YBWor3QZhavGHqTEHJfYfk2e0UczQaImc0MIIJ5JNJrns4HKm94pwUdjkPVZO2eZJBt/Rzs/D8ZrdvFFwRh0zQ==} + '@readme/better-ajv-errors@2.3.2': + resolution: {integrity: sha512-T4GGnRAlY3C339NhoUpgJJFsMYko9vIgFAlhgV+/vEGFw66qEY4a4TRJIAZBcX/qT1pq5DvXSme+SQODHOoBrw==} engines: {node: '>=18'} peerDependencies: ajv: 4.11.8 - 8 - '@readme/json-schema-ref-parser@1.2.0': - resolution: {integrity: sha512-Bt3QVovFSua4QmHa65EHUmh2xS0XJ3rgTEUPH998f4OW4VVJke3BuS16f+kM0ZLOGdvIrzrPRqwihuv5BAjtrA==} - deprecated: This package is no longer maintained. Please use `@apidevtools/json-schema-ref-parser` instead. - - '@readme/openapi-parser@2.7.0': - resolution: {integrity: sha512-P8WSr8WTOxilnT89tcCRKWYsG/II4sAwt1a/DIWub8xTtkrG9cCBBy/IUcvc5X8oGWN82MwcTA3uEkDrXZd/7A==} - engines: {node: '>=18'} + '@readme/openapi-parser@5.0.0': + resolution: {integrity: sha512-dO3yReohn5lqsJQ4tyXpc6grjab4a4fybUY2yxkqOmWP++2QP3Q7wIj2BwABsdU72KMCfNCRyV6VTuxxnKKuMA==} + engines: {node: '>=20'} peerDependencies: openapi-types: '>=7' @@ -3572,9 +3536,6 @@ packages: '@sinclair/typebox@0.27.8': resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - '@sinclair/typebox@0.34.37': - resolution: {integrity: sha512-2TRuQVgQYfy+EzHRTIvkhv2ADEouJ2xNS/Vq+W5EuuewBdOrvATvljZTxHWZSTYr2sTjTHpGvucaGAt67S2akw==} - '@sindresorhus/is@5.6.0': resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} engines: {node: '>=14.16'} @@ -4166,12 +4127,6 @@ packages: peerDependencies: '@swc/core': '*' - '@swc/jest@0.2.39': - resolution: {integrity: sha512-eyokjOwYd0Q8RnMHri+8/FS1HIrIUKK/sRrFp8c1dThUOfNeCWbLmBP1P5VsKdvmkd25JaH+OKYwEYiAYg9YAA==} - engines: {npm: '>= 7.0.0'} - peerDependencies: - '@swc/core': '*' - '@swc/types@0.1.22': resolution: {integrity: sha512-D13mY/ZA4PPEFSy6acki9eBT/3WgjMoRqNcdpIvjaYLQ44Xk5BdaL7UkDxAh6Z9UOe7tCCp67BVmZCojYp9owg==} @@ -5407,9 +5362,6 @@ packages: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - call-me-maybe@1.0.2: - resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} - callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -5797,9 +5749,6 @@ packages: engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} hasBin: true - cross-fetch@3.1.6: - resolution: {integrity: sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==} - cross-fetch@4.1.0: resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} @@ -7477,9 +7426,6 @@ packages: resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-fetch-mock@3.0.3: - resolution: {integrity: sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==} - jest-get-type@29.6.3: resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7517,10 +7463,6 @@ packages: resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-regex-util@30.0.1: - resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} - engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - jest-resolve-dependencies@29.7.0: resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -7553,9 +7495,6 @@ packages: resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - jest-websocket-mock@2.5.0: - resolution: {integrity: sha512-a+UJGfowNIWvtIKIQBHoEWIUqRxxQHFx4CXT+R5KxxKBtEQ5rS3pPOV/5299sHzqbmeCzxxY5qE4+yfXePePig==} - jest-worker@29.7.0: resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -9088,9 +9027,6 @@ packages: promise-limit@2.7.0: resolution: {integrity: sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw==} - promise-polyfill@8.3.0: - resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==} - promise-retry@2.0.1: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} @@ -10041,6 +9977,7 @@ packages: supertest@7.1.1: resolution: {integrity: sha512-aI59HBTlG9e2wTjxGJV+DygfNLgnWbGdZxiA/sgrnNNikIW8lbDvCtF6RnhZoJ82nU7qv7ZLjrvWqCEm52fAmw==} engines: {node: '>=14.18.0'} + deprecated: Please upgrade to supertest v7.1.3+, see release notes at https://github.com/forwardemail/supertest/releases/tag/v7.1.3 - maintenance is supported by Forward Email @ https://forwardemail.net supports-color@10.0.0: resolution: {integrity: sha512-HRVVSbCCMbj7/kdWF9Q+bbckjBHLtHMEoJWlkmYzzdwhYMkjkOwubLM6t7NbWKjgKamGDrWL1++KrjUO1t9oAQ==} @@ -10645,6 +10582,11 @@ packages: peerDependencies: vitest: '>=2.0.0' + vitest-websocket-mock@0.5.0: + resolution: {integrity: sha512-vzBWeuF/kD/OCOFzB7WAclb7PxfI105qPkZtdOkPMwZdilBskQjJL4l319JtPtmeovDU7ZVhO3hTfGPjM4txQQ==} + peerDependencies: + vitest: '>=3' + vitest@3.2.4: resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -11019,8 +10961,8 @@ snapshots: '@ampproject/remapping@2.3.0': dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 '@analytics/cookie-utils@0.2.12': dependencies: @@ -11058,7 +11000,10 @@ snapshots: '@analytics/type-utils@0.6.2': {} - '@apidevtools/swagger-methods@3.0.2': {} + '@apidevtools/json-schema-ref-parser@14.1.1': + dependencies: + '@types/json-schema': 7.0.15 + js-yaml: 4.1.0 '@asamuzakjp/css-color@2.8.3': dependencies: @@ -11573,8 +11518,8 @@ snapshots: '@babel/generator@7.24.7': dependencies: '@babel/types': 7.28.1 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 jsesc: 2.5.2 '@babel/helper-compilation-targets@7.24.7': @@ -12430,10 +12375,6 @@ snapshots: dependencies: '@jest/types': 29.6.3 - '@jest/create-cache-key-function@30.0.2': - dependencies: - '@jest/types': 30.0.1 - '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 @@ -12470,11 +12411,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@jest/pattern@30.0.1': - dependencies: - '@types/node': 22.16.4 - jest-regex-util: 30.0.1 - '@jest/reporters@29.7.0': dependencies: '@bcoe/v8-coverage': 0.2.3 @@ -12482,7 +12418,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@types/node': 22.16.4 chalk: 4.1.2 collect-v8-coverage: 1.0.1 @@ -12508,13 +12444,9 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 - '@jest/schemas@30.0.1': - dependencies: - '@sinclair/typebox': 0.34.37 - '@jest/source-map@29.6.3': dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 callsites: 3.1.0 graceful-fs: 4.2.11 @@ -12536,7 +12468,7 @@ snapshots: dependencies: '@babel/core': 7.24.7 '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 @@ -12561,16 +12493,6 @@ snapshots: '@types/yargs': 17.0.33 chalk: 4.1.2 - '@jest/types@30.0.1': - dependencies: - '@jest/pattern': 30.0.1 - '@jest/schemas': 30.0.1 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 22.16.4 - '@types/yargs': 17.0.33 - chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.8.3)(vite@6.3.5(@types/node@22.16.4)(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3))': dependencies: glob: 10.4.5 @@ -12580,30 +12502,25 @@ snapshots: optionalDependencies: typescript: 5.8.3 - '@jridgewell/gen-mapping@0.3.5': + '@jridgewell/gen-mapping@0.3.12': dependencies: - '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@jridgewell/resolve-uri@3.1.0': {} - '@jridgewell/set-array@1.2.1': {} - '@jridgewell/source-map@0.3.6': dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/trace-mapping@0.3.25': + '@jridgewell/trace-mapping@0.3.29': dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.5.0 - '@jsdevtools/ono@7.1.3': {} - '@kurkle/color@0.3.2': {} '@levischuck/tiny-cbor@0.2.2': {} @@ -13279,7 +13196,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@readme/better-ajv-errors@2.2.2(ajv@8.17.1)': + '@readme/better-ajv-errors@2.3.2(ajv@8.17.1)': dependencies: '@babel/code-frame': 7.27.1 '@babel/runtime': 7.27.0 @@ -13289,23 +13206,14 @@ snapshots: leven: 3.1.0 picocolors: 1.1.1 - '@readme/json-schema-ref-parser@1.2.0': + '@readme/openapi-parser@5.0.0(openapi-types@12.1.3)': dependencies: - '@jsdevtools/ono': 7.1.3 - '@types/json-schema': 7.0.15 - call-me-maybe: 1.0.2 - js-yaml: 4.1.0 - - '@readme/openapi-parser@2.7.0(openapi-types@12.1.3)': - dependencies: - '@apidevtools/swagger-methods': 3.0.2 - '@jsdevtools/ono': 7.1.3 - '@readme/better-ajv-errors': 2.2.2(ajv@8.17.1) - '@readme/json-schema-ref-parser': 1.2.0 + '@apidevtools/json-schema-ref-parser': 14.1.1 + '@readme/better-ajv-errors': 2.3.2(ajv@8.17.1) '@readme/openapi-schemas': 3.1.0 + '@types/json-schema': 7.0.15 ajv: 8.17.1 ajv-draft-04: 1.0.0(ajv@8.17.1) - call-me-maybe: 1.0.2 openapi-types: 12.1.3 '@readme/openapi-schemas@3.1.0': {} @@ -13640,8 +13548,6 @@ snapshots: '@sinclair/typebox@0.27.8': {} - '@sinclair/typebox@0.34.37': {} - '@sindresorhus/is@5.6.0': {} '@sindresorhus/is@7.0.1': {} @@ -14418,13 +14324,6 @@ snapshots: '@swc/counter': 0.1.3 jsonc-parser: 3.2.0 - '@swc/jest@0.2.39(@swc/core@1.12.0)': - dependencies: - '@jest/create-cache-key-function': 30.0.2 - '@swc/core': 1.12.0 - '@swc/counter': 0.1.3 - jsonc-parser: 3.2.0 - '@swc/types@0.1.22': dependencies: '@swc/counter': 0.1.3 @@ -15699,7 +15598,7 @@ snapshots: ast-v8-to-istanbul@0.3.3: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 estree-walker: 3.0.3 js-tokens: 9.0.1 @@ -16016,8 +15915,6 @@ snapshots: call-bind-apply-helpers: 1.0.2 get-intrinsic: 1.3.0 - call-me-maybe@1.0.2: {} - callsites@3.1.0: {} camelcase-keys@6.2.2: @@ -16376,21 +16273,6 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.16.4): - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@22.16.4) - jest-util: 29.7.0 - prompts: 2.4.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - cron-parser@4.9.0: dependencies: luxon: 3.3.0 @@ -16404,12 +16286,6 @@ snapshots: dependencies: cross-spawn: 7.0.6 - cross-fetch@3.1.6(encoding@0.1.13): - dependencies: - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - cross-fetch@4.1.0(encoding@0.1.13): dependencies: node-fetch: 2.7.0(encoding@0.1.13) @@ -18372,7 +18248,7 @@ snapshots: istanbul-lib-source-maps@5.0.6: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 debug: 4.4.1(supports-color@10.0.0) istanbul-lib-coverage: 3.2.2 transitivePeerDependencies: @@ -18446,25 +18322,6 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.16.4): - dependencies: - '@jest/core': 29.7.0 - '@jest/test-result': 29.7.0 - '@jest/types': 29.6.3 - chalk: 4.1.2 - create-jest: 29.7.0(@types/node@22.16.4) - exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@22.16.4) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jest-config@29.7.0(@types/node@22.15.31): dependencies: '@babel/core': 7.24.7 @@ -18553,13 +18410,6 @@ snapshots: jest-mock: 29.7.0 jest-util: 29.7.0 - jest-fetch-mock@3.0.3(encoding@0.1.13): - dependencies: - cross-fetch: 3.1.6(encoding@0.1.13) - promise-polyfill: 8.3.0 - transitivePeerDependencies: - - encoding - jest-get-type@29.6.3: {} jest-haste-map@29.7.0: @@ -18614,8 +18464,6 @@ snapshots: jest-regex-util@29.6.3: {} - jest-regex-util@30.0.1: {} - jest-resolve-dependencies@29.7.0: dependencies: jest-regex-util: 29.6.3 @@ -18742,11 +18590,6 @@ snapshots: jest-util: 29.7.0 string-length: 4.0.2 - jest-websocket-mock@2.5.0: - dependencies: - jest-diff: 29.7.0 - mock-socket: 9.3.1 - jest-worker@29.7.0: dependencies: '@types/node': 22.16.4 @@ -18766,18 +18609,6 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.16.4): - dependencies: - '@jest/core': 29.7.0 - '@jest/types': 29.6.3 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@22.16.4) - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - supports-color - - ts-node - jju@1.4.0: {} joi@17.13.3: @@ -20465,8 +20296,6 @@ snapshots: promise-limit@2.7.0: {} - promise-polyfill@8.3.0: {} - promise-retry@2.0.1: dependencies: err-code: 2.0.3 @@ -22105,7 +21934,7 @@ snapshots: v8-to-istanbul@9.2.0: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.29 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 @@ -22177,6 +22006,12 @@ snapshots: dependencies: vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3) + vitest-websocket-mock@0.5.0(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)): + dependencies: + '@vitest/utils': 3.2.4 + mock-socket: 9.3.1 + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3) + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.4)(happy-dom@17.6.3)(jsdom@26.1.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.10.4(@types/node@22.16.4)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3): dependencies: '@types/chai': 5.2.2 From 2da20bf3e8c4f32eb2f53bb242da312f353115cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:16:24 +0900 Subject: [PATCH 02/87] fix(misskey-js): fix misskey-js autogen (#16345) --- packages/misskey-js/generator/src/generator.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/misskey-js/generator/src/generator.ts b/packages/misskey-js/generator/src/generator.ts index a95fc962a8..55f2ea9443 100644 --- a/packages/misskey-js/generator/src/generator.ts +++ b/packages/misskey-js/generator/src/generator.ts @@ -2,7 +2,7 @@ import assert from 'assert'; import { mkdir, readFile, writeFile } from 'fs/promises'; import type { OpenAPIV3_1 } from 'openapi-types'; import { toPascal } from 'ts-case-convert'; -import OpenAPIParser from '@readme/openapi-parser'; +import { parse } from '@readme/openapi-parser'; import openapiTS, { astToString } from 'openapi-typescript'; import type { OpenAPI3, OperationObject, PathItemObject } from 'openapi-typescript'; import ts from 'typescript'; @@ -401,7 +401,7 @@ async function main() { await mkdir(generatePath, { recursive: true }); const openApiJsonPath = './api.json'; - const openApiDocs = await OpenAPIParser.parse(openApiJsonPath) as OpenAPIV3_1.Document; + const openApiDocs = await parse(openApiJsonPath) as OpenAPIV3_1.Document; const typeFileName = './built/autogen/types.ts'; await generateBaseTypes(openApiDocs, openApiJsonPath, typeFileName); From 7c1f4c9037b3abd791ebc0cffebbcb40c69b5522 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 3 Aug 2025 10:01:25 +0900 Subject: [PATCH 03/87] perf(frontend): tweak css performance --- packages/frontend/src/style.scss | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index d9565841f2..c98b0a4953 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -37,11 +37,6 @@ html { color: var(--MI_THEME-fg); accent-color: var(--MI_THEME-accent); - &, * { - scrollbar-color: var(--MI_THEME-scrollbarHandle) transparent; - scrollbar-width: thin; - } - &.f-1 { font-size: 15px; } @@ -91,7 +86,11 @@ html::selection { 100% { opacity: 0; } +} +html, body, main, div { + scrollbar-color: var(--MI_THEME-scrollbarHandle) transparent; + scrollbar-width: thin; } html, From 6f3cc2cdf7e47a2dd4dd6d7478579746e2af652c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 3 Aug 2025 11:02:20 +0900 Subject: [PATCH 04/87] =?UTF-8?q?=E3=82=B3=E3=83=B3=E3=83=88=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=83=AB=E3=83=91=E3=83=8D=E3=83=AB=E3=81=AE=E6=A4=9C?= =?UTF-8?q?=E7=B4=A2=20(#16343)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update settings.vue * Update settings.vue * Update settings.vue * Update settings.vue * Update settings.vue * Update performance.vue * Update performance.vue * Update performance.vue * Update external-services.vue * wip * wip * Update security.vue * Update settings.vue * Update CHANGELOG.md * wip * Update moderation.vue * wip * Update branding.vue * wip * Update email-settings.vue * Update system-webhook.vue * Update MkSuperMenu.vue * Update index.vue --- CHANGELOG.md | 1 + .../lib/vite-plugin-create-search-index.ts | 36 +- .../frontend/src/components/MkSuperMenu.vue | 32 +- .../src/components/global/SearchText.vue | 14 + packages/frontend/src/components/index.ts | 6 +- .../src/pages/admin/bot-protection.vue | 280 ++++---- .../frontend/src/pages/admin/branding.vue | 211 +++--- .../src/pages/admin/email-settings.vue | 115 ++-- .../src/pages/admin/external-services.vue | 78 ++- packages/frontend/src/pages/admin/index.vue | 11 +- .../frontend/src/pages/admin/moderation.vue | 267 ++++---- .../src/pages/admin/object-storage.vue | 161 ++--- .../frontend/src/pages/admin/performance.vue | 264 ++++---- packages/frontend/src/pages/admin/relays.vue | 22 +- .../frontend/src/pages/admin/security.vue | 222 ++++--- .../frontend/src/pages/admin/server-rules.vue | 23 +- .../frontend/src/pages/admin/settings.vue | 623 ++++++++++-------- .../src/pages/admin/system-webhook.vue | 24 +- packages/frontend/src/pages/settings/2fa.vue | 4 +- .../src/pages/settings/account-data.vue | 2 +- .../frontend/src/pages/settings/connect.vue | 2 +- .../frontend/src/pages/settings/drive.vue | 6 +- .../frontend/src/pages/settings/index.vue | 6 +- .../src/pages/settings/mute-block.vue | 2 +- .../src/pages/settings/notifications.vue | 2 +- .../frontend/src/pages/settings/other.vue | 2 +- .../frontend/src/pages/settings/plugin.vue | 2 +- .../src/pages/settings/preferences.vue | 22 +- .../frontend/src/pages/settings/privacy.vue | 18 +- .../frontend/src/pages/settings/profile.vue | 2 +- .../frontend/src/pages/settings/security.vue | 50 +- .../frontend/src/pages/settings/sounds.vue | 2 +- packages/frontend/src/router.definition.ts | 4 - packages/frontend/src/utility/inapp-search.ts | 37 ++ .../src/utility/settings-search-index.ts | 36 - packages/frontend/src/utility/virtual.d.ts | 31 +- packages/frontend/vite.config.ts | 5 + 37 files changed, 1434 insertions(+), 1191 deletions(-) create mode 100644 packages/frontend/src/components/global/SearchText.vue create mode 100644 packages/frontend/src/utility/inapp-search.ts delete mode 100644 packages/frontend/src/utility/settings-search-index.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index f9e6b0ed21..f17964f285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - `g` キーを連打する - URLに`?safemode=true`を付ける - PWAのショートカットで Safemode を選択して起動する +- Enhance: コントロールパネルを検索できるように - Fix: 一部の設定検索結果が存在しないパスになる問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171) - Fix: テーマエディタが動作しない問題を修正 diff --git a/packages/frontend/lib/vite-plugin-create-search-index.ts b/packages/frontend/lib/vite-plugin-create-search-index.ts index 97f4e589a3..4e20828909 100644 --- a/packages/frontend/lib/vite-plugin-create-search-index.ts +++ b/packages/frontend/lib/vite-plugin-create-search-index.ts @@ -39,6 +39,7 @@ export interface SearchIndexItem { path?: string; label: string; keywords: string[]; + texts: string[]; icon?: string; inlining?: string[]; } @@ -227,14 +228,14 @@ function extractElementText2Inner(node: TemplateChildNode, processingNodeName: s // region extractUsageInfoFromTemplateAst /** - * SearchLabel/SearchKeyword/SearchIconを探して抽出する関数 + * SearchLabel/SearchText/SearchIconを探して抽出する関数 */ -function extractSugarTags(nodes: TemplateChildNode[], id: string): { label: string | null, keywords: string[], icon: string | null } { +function extractSugarTags(nodes: TemplateChildNode[], id: string): { label: string | null; texts: string[]; icon: string | null; } { let label: string | null | undefined = undefined; let icon: string | null | undefined = undefined; - const keywords: string[] = []; + const texts: string[] = []; - logger.info(`Extracting labels and keywords from ${nodes.length} nodes`); + logger.info(`Extracting labels and texts from ${nodes.length} nodes`); walkVueElements(nodes, null, (node) => { switch (node.tag) { @@ -248,10 +249,10 @@ function extractSugarTags(nodes: TemplateChildNode[], id: string): { label: stri label = extractElementText(node, id); return; - case 'SearchKeyword': + case 'SearchText': const content = extractElementText(node, id); if (content) { - keywords.push(content); + texts.push(content); } return; case 'SearchIcon': @@ -278,8 +279,8 @@ function extractSugarTags(nodes: TemplateChildNode[], id: string): { label: stri }); // デバッグ情報 - logger.info(`Extraction completed: label=${label}, keywords=[${keywords.join(', ')}, icon=${icon}]`); - return { label: label ?? null, keywords, icon: icon ?? null }; + logger.info(`Extraction completed: label=${label}, text=[${texts.join(', ')}, icon=${icon}]`); + return { label: label ?? null, texts, icon: icon ?? null }; } function getStringProp(attr: AttributeNode | DirectiveNode | null, id: string): string | null { @@ -351,33 +352,36 @@ function extractUsageInfoFromTemplateAst( parentId: parentId ?? undefined, label: '', // デフォルト値 keywords: [], + texts: [], }; // バインドプロパティを取得 - const path = getStringProp(findAttribute(node.props, 'path'), id) - const icon = getStringProp(findAttribute(node.props, 'icon'), id) - const label = getStringProp(findAttribute(node.props, 'label'), id) - const inlining = getStringArrayProp(findAttribute(node.props, 'inlining'), id) - const keywords = getStringArrayProp(findAttribute(node.props, 'keywords'), id) + const path = getStringProp(findAttribute(node.props, 'path'), id); + const icon = getStringProp(findAttribute(node.props, 'icon'), id); + const label = getStringProp(findAttribute(node.props, 'label'), id); + const inlining = getStringArrayProp(findAttribute(node.props, 'inlining'), id); + const keywords = getStringArrayProp(findAttribute(node.props, 'keywords'), id); + const texts = getStringArrayProp(findAttribute(node.props, 'texts'), id); if (path) markerInfo.path = path; if (icon) markerInfo.icon = icon; if (label) markerInfo.label = label; if (inlining) markerInfo.inlining = inlining; if (keywords) markerInfo.keywords = keywords; + if (texts) markerInfo.texts = texts; - //pathがない場合はファイルパスを設定 + // pathがない場合はファイルパスを設定 if (markerInfo.path == null && parentId == null) { markerInfo.path = id.match(/.*(\/(admin|settings)\/[^\/]+)\.vue$/)?.[1]; } - // SearchLabelとSearchKeywordを抽出 (AST全体を探索) + // SearchLabelとSearchTextを抽出 (AST全体を探索) { const extracted = extractSugarTags(node.children, id); if (extracted.label && markerInfo.label) logger.warn(`Duplicate label found for ${markerId} at ${id}:${node.loc.start.line}`); if (extracted.icon && markerInfo.icon) logger.warn(`Duplicate icon found for ${markerId} at ${id}:${node.loc.start.line}`); markerInfo.label = extracted.label ?? markerInfo.label ?? ''; - markerInfo.keywords = [...extracted.keywords, ...markerInfo.keywords]; + markerInfo.texts = [...extracted.texts, ...markerInfo.texts]; markerInfo.icon = extracted.icon ?? markerInfo.icon ?? undefined; } diff --git a/packages/frontend/src/components/MkSuperMenu.vue b/packages/frontend/src/components/MkSuperMenu.vue index 5c89a6530d..dbc673333c 100644 --- a/packages/frontend/src/components/MkSuperMenu.vue +++ b/packages/frontend/src/components/MkSuperMenu.vue @@ -52,9 +52,9 @@ SPDX-License-Identifier: AGPL-3.0-only {{ item.label }} @@ -95,7 +95,7 @@ export type SuperMenuDef = { + + diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 19766e8575..6b1b80695f 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -31,7 +31,7 @@ import PageWithHeader from './global/PageWithHeader.vue'; import PageWithAnimBg from './global/PageWithAnimBg.vue'; import SearchMarker from './global/SearchMarker.vue'; import SearchLabel from './global/SearchLabel.vue'; -import SearchKeyword from './global/SearchKeyword.vue'; +import SearchText from './global/SearchText.vue'; import SearchIcon from './global/SearchIcon.vue'; import type { App } from 'vue'; @@ -71,7 +71,7 @@ export const components = { PageWithAnimBg: PageWithAnimBg, SearchMarker: SearchMarker, SearchLabel: SearchLabel, - SearchKeyword: SearchKeyword, + SearchText: SearchText, SearchIcon: SearchIcon, }; @@ -105,7 +105,7 @@ declare module '@vue/runtime-core' { PageWithAnimBg: typeof PageWithAnimBg; SearchMarker: typeof SearchMarker; SearchLabel: typeof SearchLabel; - SearchKeyword: typeof SearchKeyword; + SearchText: typeof SearchText; SearchIcon: typeof SearchIcon; } } diff --git a/packages/frontend/src/pages/admin/bot-protection.vue b/packages/frontend/src/pages/admin/bot-protection.vue index 6c580f87f1..bd919146f8 100644 --- a/packages/frontend/src/pages/admin/bot-protection.vue +++ b/packages/frontend/src/pages/admin/bot-protection.vue @@ -4,158 +4,161 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/components/global/PageWithHeader.vue b/packages/frontend/src/components/global/PageWithHeader.vue index d90afb652e..d368dee88a 100644 --- a/packages/frontend/src/components/global/PageWithHeader.vue +++ b/packages/frontend/src/components/global/PageWithHeader.vue @@ -6,14 +6,22 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -26,6 +34,7 @@ import { useScrollPositionKeeper } from '@/composables/use-scroll-position-keepe import MkSwiper from '@/components/MkSwiper.vue'; import { useRouter } from '@/router.js'; import { prefer } from '@/preferences.js'; +import MkTabs from '@/components/MkTabs.vue'; const props = withDefaults(defineProps { return rest; }); +const pageHeaderPropsWithoutTabs = computed(() => { + const { reversed, tabs, ...rest } = props; + return rest; +}); + const tab = defineModel('tab'); const rootEl = useTemplateRef('rootEl'); @@ -68,4 +82,11 @@ defineExpose({ .body, .swiper { min-height: calc(100cqh - (var(--MI-stickyTop, 0px) + var(--MI-stickyBottom, 0px))); } + +.footerTabs { + background: color(from var(--MI_THEME-pageHeaderBg) srgb r g b / 0.75); + -webkit-backdrop-filter: var(--MI-blur, blur(15px)); + backdrop-filter: var(--MI-blur, blur(15px)); + border-top: solid 0.5px var(--MI_THEME-divider); +} diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index 7ee5f151fa..ed4f36c0e5 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -477,6 +477,14 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + + @@ -866,6 +874,7 @@ const animatedMfm = prefer.model('animatedMfm'); const disableShowingAnimatedImages = prefer.model('disableShowingAnimatedImages'); const keepScreenOn = prefer.model('keepScreenOn'); const enableHorizontalSwipe = prefer.model('enableHorizontalSwipe'); +const showPageTabBarBottom = prefer.model('showPageTabBarBottom'); const enablePullToRefresh = prefer.model('enablePullToRefresh'); const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPlayer'); const contextMenu = prefer.model('contextMenu'); @@ -925,6 +934,7 @@ watch([ useSystemFont, makeEveryTextElementsSelectable, enableHorizontalSwipe, + showPageTabBarBottom, enablePullToRefresh, reduceAnimation, showAvailableReactionsFirstInNote, diff --git a/packages/frontend/src/preferences/def.ts b/packages/frontend/src/preferences/def.ts index a83a3153d0..f6370c8c78 100644 --- a/packages/frontend/src/preferences/def.ts +++ b/packages/frontend/src/preferences/def.ts @@ -381,6 +381,9 @@ export const PREF_DEF = definePreferences({ showAvailableReactionsFirstInNote: { default: false, }, + showPageTabBarBottom: { + default: false, + }, plugins: { default: [] as Plugin[], mergeStrategy: (a, b) => { diff --git a/packages/frontend/src/ui/_common_/mobile-footer-menu.vue b/packages/frontend/src/ui/_common_/mobile-footer-menu.vue index e2993230be..7ab8a45f51 100644 --- a/packages/frontend/src/ui/_common_/mobile-footer-menu.vue +++ b/packages/frontend/src/ui/_common_/mobile-footer-menu.vue @@ -86,7 +86,7 @@ watch(rootEl, () => { box-sizing: border-box; background: var(--MI_THEME-navBg); color: var(--MI_THEME-navFg); - box-shadow: 0px 0px 6px 6px #0000000f; + border-top: solid 0.5px var(--MI_THEME-divider); } .item { From d979cd2c07d24270d03be29f8f1c5b6a3351798d Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:15:02 +0900 Subject: [PATCH 15/87] =?UTF-8?q?fix(frontend):=20=E6=8A=95=E7=A8=BF?= =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=BC=E3=83=A0=E3=81=A7=E3=83=95=E3=82=A1?= =?UTF-8?q?=E3=82=A4=E3=83=AB=E3=81=AE=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=8C=E4=B8=AD=E6=AD=A2=E3=81=BE=E3=81=9F?= =?UTF-8?q?=E3=81=AF=E5=A4=B1=E6=95=97=E3=81=97=E3=81=9F=E9=9A=9B=E3=81=AE?= =?UTF-8?q?=E3=83=8F=E3=83=B3=E3=83=89=E3=83=AA=E3=83=B3=E3=82=B0=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + packages/frontend/src/components/MkPostForm.vue | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8fcb60a39..b0b23ed891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - Feat: ページのタブバーを下部に表示できるように - Enhance: コントロールパネルを検索できるように - Enhance: トルコ語 (tr-TR) に対応 +- Fix: 投稿フォームでファイルのアップロードが中止または失敗した際のハンドリングを修正 - Fix: 一部の設定検索結果が存在しないパスになる問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171) - Fix: テーマエディタが動作しない問題を修正 diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 174a73e0fd..f1fa870991 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -907,6 +907,11 @@ async function post(ev?: MouseEvent) { if (uploader.items.value.some(x => x.uploaded == null)) { await uploadFiles(); + + // アップロード失敗したものがあったら中止 + if (uploader.items.value.some(x => x.uploaded == null)) { + return; + } } let postData = { From b4a0fdfaa14ea67e78be5ba1488ccbfd6edaaf73 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:35:42 +0900 Subject: [PATCH 16/87] fix type errors --- packages/frontend/src/pages/timeline.vue | 25 ++++++------------------ 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index b783f7ee0b..b8c3ebadd9 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -107,7 +107,7 @@ const withSensitive = computed({ async function chooseList(ev: MouseEvent): Promise { const lists = await userListsCache.fetch(); - const items: MenuItem[] = [ + const items: (MenuItem | undefined)[] = [ ...lists.map(list => ({ type: 'link' as const, text: list.name, @@ -121,12 +121,12 @@ async function chooseList(ev: MouseEvent): Promise { to: '/my/lists', }, ]; - os.popupMenu(items, ev.currentTarget ?? ev.target); + os.popupMenu(items.filter(i => i != null), ev.currentTarget ?? ev.target); } async function chooseAntenna(ev: MouseEvent): Promise { const antennas = await antennasCache.fetch(); - const items: MenuItem[] = [ + const items: (MenuItem | undefined)[] = [ ...antennas.map(antenna => ({ type: 'link' as const, text: antenna.name, @@ -141,12 +141,12 @@ async function chooseAntenna(ev: MouseEvent): Promise { to: '/my/antennas', }, ]; - os.popupMenu(items, ev.currentTarget ?? ev.target); + os.popupMenu(items.filter(i => i != null), ev.currentTarget ?? ev.target); } async function chooseChannel(ev: MouseEvent): Promise { const channels = await favoritedChannelsCache.fetch(); - const items: MenuItem[] = [ + const items: (MenuItem | undefined)[] = [ ...channels.map(channel => { const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null; const hasUnreadNote = (lastReadedAt && channel.lastNotedAt) ? Date.parse(channel.lastNotedAt) > lastReadedAt : !!(!lastReadedAt && channel.lastNotedAt); @@ -166,7 +166,7 @@ async function chooseChannel(ev: MouseEvent): Promise { to: '/channels', }, ]; - os.popupMenu(items, ev.currentTarget ?? ev.target); + os.popupMenu(items.filter(i => i != null), ev.currentTarget ?? ev.target); } function saveSrc(newSrc: TimelinePageSrc): void { @@ -190,19 +190,6 @@ function saveTlFilter(key: keyof typeof store.s.tl.filter, newValue: boolean) { } } -async function timetravel(): Promise { - const { canceled, result: date } = await os.inputDate({ - title: i18n.ts.date, - }); - if (canceled) return; - - tlComponent.value.timetravel(date); -} - -function focus(): void { - tlComponent.value.focus(); -} - function switchTlIfNeeded() { if (isBasicTimeline(src.value) && !isAvailableBasicTimeline(src.value)) { src.value = availableBasicTimelines()[0]; From 9931fff35ba13f1ed5d7d949d29e0da5e29a050f Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:44:59 +0900 Subject: [PATCH 17/87] =?UTF-8?q?=F0=9F=8E=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/global/MkPageHeader.vue | 3 ++- packages/frontend/src/pages/timeline.vue | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 542c3d8d12..2f4de840db 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -52,6 +52,7 @@ export type PageHeaderProps = { actions?: PageHeaderItem[] | null; thin?: boolean; hideTitle?: boolean; + canOmitTitle?: boolean; displayMyAvatar?: boolean; }; @@ -77,7 +78,7 @@ const emit = defineEmits<{ const injectedPageMetadata = inject(DI.pageMetadata, ref(null)); const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value); -const hideTitle = computed(() => inject('shouldOmitHeaderTitle', false) || props.hideTitle); +const hideTitle = computed(() => inject('shouldOmitHeaderTitle', false) || props.hideTitle || (props.canOmitTitle && props.tabs.length > 0)); const thin_ = props.thin || inject('shouldHeaderThin', false); const el = useTemplateRef('el'); diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index b8c3ebadd9..3fe48b4d72 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only -->