From 2b6638e1607e5c44eb6f6dc987e9e893927f1829 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Feb 2025 20:51:23 +0900 Subject: [PATCH 001/649] feat: google analytics (#15451) * wip backend * wip frontend * build misskey-js * implement control panel * fix * introduce analytics wrapper * spdx * Update analytics.ts * Update common.ts * wip * wip * wip * wip * wip * Update CHANGELOG.md --------- Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com> --- CHANGELOG.md | 1 + .../1739006797620-GoogleAnalytics.js | 16 +++ .../src/core/entities/MetaEntityService.ts | 1 + packages/backend/src/models/Meta.ts | 6 + .../backend/src/models/json-schema/meta.ts | 4 + .../src/server/api/endpoints/admin/meta.ts | 5 + .../server/api/endpoints/admin/update-meta.ts | 7 ++ packages/frontend/package.json | 2 + packages/frontend/src/analytics.ts | 107 ++++++++++++++++++ packages/frontend/src/boot/common.ts | 16 ++- .../frontend/src/components/MkPageWindow.vue | 16 ++- .../src/pages/admin/external-services.vue | 53 ++++++--- packages/frontend/src/router/main.ts | 9 ++ packages/misskey-js/src/autogen/types.ts | 3 + pnpm-lock.yaml | 97 ++++++++++++++++ 15 files changed, 327 insertions(+), 16 deletions(-) create mode 100644 packages/backend/migration/1739006797620-GoogleAnalytics.js create mode 100644 packages/frontend/src/analytics.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d29e3db0d4..2399ce8a52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### General - Feat: アクセストークン発行時に通知するように +- Feat: 実験的なGoogleAnalyticsサポートを追加 - 依存関係の更新 ### Client diff --git a/packages/backend/migration/1739006797620-GoogleAnalytics.js b/packages/backend/migration/1739006797620-GoogleAnalytics.js new file mode 100644 index 0000000000..5871bf098a --- /dev/null +++ b/packages/backend/migration/1739006797620-GoogleAnalytics.js @@ -0,0 +1,16 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class GoogleAnalytics1739006797620 { + name = 'GoogleAnalytics1739006797620' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "googleAnalyticsMeasurementId" character varying(64)`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "googleAnalyticsMeasurementId"`); + } +} diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index ec0b5360f4..7ad6071ceb 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -97,6 +97,7 @@ export class MetaEntityService { enableTurnstile: instance.enableTurnstile, turnstileSiteKey: instance.turnstileSiteKey, enableTestcaptcha: instance.enableTestcaptcha, + googleAnalyticsMeasurementId: instance.googleAnalyticsMeasurementId, swPublickey: instance.swPublicKey, themeColor: instance.themeColor, mascotImageUrl: instance.mascotImageUrl ?? '/assets/ai.png', diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index ad5e31ad6f..9df2f74984 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -658,4 +658,10 @@ export class MiMeta { default: '{}', }) public federationHosts: string[]; + + @Column('varchar', { + length: 64, + nullable: true, + }) + public googleAnalyticsMeasurementId: string | null; } diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts index e7ae2ee8e5..1e25c355ca 100644 --- a/packages/backend/src/models/json-schema/meta.ts +++ b/packages/backend/src/models/json-schema/meta.ts @@ -119,6 +119,10 @@ export const packedMetaLiteSchema = { type: 'boolean', optional: false, nullable: false, }, + googleAnalyticsMeasurementId: { + type: 'string', + optional: false, nullable: true, + }, swPublickey: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 912c8defbe..9d5691a427 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -73,6 +73,10 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, + googleAnalyticsMeasurementId: { + type: 'string', + optional: false, nullable: true, + }, swPublickey: { type: 'string', optional: false, nullable: true, @@ -572,6 +576,7 @@ export default class extends Endpoint { // eslint- enableTurnstile: instance.enableTurnstile, turnstileSiteKey: instance.turnstileSiteKey, enableTestcaptcha: instance.enableTestcaptcha, + googleAnalyticsMeasurementId: instance.googleAnalyticsMeasurementId, swPublickey: instance.swPublicKey, themeColor: instance.themeColor, mascotImageUrl: instance.mascotImageUrl, diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 38ef0d1de8..1cfa9cffa6 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -84,6 +84,7 @@ export const paramDef = { turnstileSiteKey: { type: 'string', nullable: true }, turnstileSecretKey: { type: 'string', nullable: true }, enableTestcaptcha: { type: 'boolean' }, + googleAnalyticsMeasurementId: { type: 'string', nullable: true }, sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] }, sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] }, setSensitiveFlagAutomatically: { type: 'boolean' }, @@ -371,6 +372,12 @@ export default class extends Endpoint { // eslint- set.enableTestcaptcha = ps.enableTestcaptcha; } + if (ps.googleAnalyticsMeasurementId !== undefined) { + // 空文字列をnullにしたいので??は使わない + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + set.googleAnalyticsMeasurementId = ps.googleAnalyticsMeasurementId || null; + } + if (ps.sensitiveMediaDetection !== undefined) { set.sensitiveMediaDetection = ps.sensitiveMediaDetection; } diff --git a/packages/frontend/package.json b/packages/frontend/package.json index b2bc47ec83..10fbc58cf0 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -16,6 +16,7 @@ "lint": "pnpm typecheck && pnpm eslint" }, "dependencies": { + "@analytics/google-analytics": "1.1.0", "@discordapp/twemoji": "15.1.0", "@github/webauthn-json": "2.1.1", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", @@ -29,6 +30,7 @@ "@vitejs/plugin-vue": "5.2.1", "@vue/compiler-sfc": "3.5.13", "aiscript-vscode": "github:aiscript-dev/aiscript-vscode#v0.1.15", + "analytics": "0.8.16", "astring": "1.9.0", "broadcast-channel": "7.0.0", "buraha": "0.0.1", diff --git a/packages/frontend/src/analytics.ts b/packages/frontend/src/analytics.ts new file mode 100644 index 0000000000..e07a4e9258 --- /dev/null +++ b/packages/frontend/src/analytics.ts @@ -0,0 +1,107 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import * as Misskey from 'misskey-js'; +import type { AnalyticsInstance, AnalyticsPlugin } from 'analytics'; + +/** + * analytics moduleを読み込まなくても動作するようにするためのラッパー + */ +class AnalyticsProxy implements AnalyticsInstance { + private analytics?: AnalyticsInstance; + + constructor(analytics?: AnalyticsInstance) { + if (analytics) { + this.analytics = analytics; + } + } + + public setAnalytics(analytics: AnalyticsInstance) { + if (this.analytics) { + throw new Error('Analytics instance already exists.'); + } + this.analytics = analytics; + } + + public identify(...args: Parameters) { + return this.analytics?.identify(...args) ?? Promise.resolve(); + } + + public track(...args: Parameters) { + return this.analytics?.track(...args) ?? Promise.resolve(); + } + + public page(...args: Parameters) { + return this.analytics?.page(...args) ?? Promise.resolve(); + } + + public user(...args: Parameters) { + return this.analytics?.user(...args) ?? Promise.resolve(); + } + + public reset(...args: Parameters) { + return this.analytics?.reset(...args) ?? Promise.resolve(); + } + + public ready(...args: Parameters) { + return this.analytics?.ready(...args) ?? function () { void 0; }; + } + + public on(...args: Parameters) { + return this.analytics?.on(...args) ?? function () { void 0; }; + } + + public once(...args: Parameters) { + return this.analytics?.once(...args) ?? function () { void 0; }; + } + + public getState(...args: Parameters) { + return this.analytics?.getState(...args) ?? Promise.resolve(); + } + + public get storage() { + return this.analytics?.storage ?? { + getItem: () => null, + setItem: () => void 0, + removeItem: () => void 0, + }; + } + + public get plugins() { + return this.analytics?.plugins ?? { + enable: (p, c) => Promise.resolve(c ? c() : void 0), + disable: (p, c) => Promise.resolve(c ? c() : void 0), + }; + } +} + +export const analytics = new AnalyticsProxy(); + +export async function initAnalytics(instance: Misskey.entities.MetaDetailed) { + // アナリティクスプロバイダに関する設定がひとつもない場合は、アナリティクスモジュールを読み込まない + if (!instance.googleAnalyticsMeasurementId) { + return; + } + + const { default: Analytics } = await import('analytics'); + const plugins: AnalyticsPlugin[] = []; + + // Google Analytics + if (instance.googleAnalyticsMeasurementId) { + const { default: googleAnalytics } = await import('@analytics/google-analytics'); + + plugins.push(googleAnalytics({ + measurementIds: [instance.googleAnalyticsMeasurementId], + debug: _DEV_, + })); + } + + analytics.setAnalytics(Analytics({ + app: 'misskey', + version: _VERSION_, + debug: _DEV_, + plugins, + })); +} diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index 1d8e40a12d..d09b98efe0 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -4,9 +4,9 @@ */ import { computed, watch, version as vueVersion } from 'vue'; -import type { App } from 'vue'; import { compareVersions } from 'compare-versions'; import { version, lang, updateLocale, locale } from '@@/js/config.js'; +import type { App } from 'vue'; import widgets from '@/widgets/index.js'; import directives from '@/directives/index.js'; import components from '@/components/index.js'; @@ -21,6 +21,7 @@ import { reloadChannel } from '@/scripts/unison-reload.js'; import { getUrlWithoutLoginId } from '@/scripts/login-id.js'; import { getAccountFromId } from '@/scripts/get-account-from-id.js'; import { deckStore } from '@/ui/deck/deck-store.js'; +import { analytics, initAnalytics } from '@/analytics.js'; import { miLocalStorage } from '@/local-storage.js'; import { fetchCustomEmojis } from '@/custom-emojis.js'; import { setupRouter } from '@/router/main.js'; @@ -241,6 +242,19 @@ export async function common(createVue: () => App) { await fetchCustomEmojis(); } catch (err) { /* empty */ } + // analytics + fetchInstanceMetaPromise.then(async () => { + await initAnalytics(instance); + + if ($i) { + analytics.identify($i.id); + } + + analytics.page({ + path: window.location.pathname, + }); + }); + const app = createVue(); setupRouter(app, createMainRouter); diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index 1420b9c26f..e725d2a15d 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -32,6 +32,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, onMounted, onUnmounted, provide, ref, shallowRef } from 'vue'; import { url } from '@@/js/config.js'; import { getScrollContainer } from '@@/js/scroll.js'; +import type { PageMetadata } from '@/scripts/page-metadata.js'; import RouterView from '@/components/global/RouterView.vue'; import MkWindow from '@/components/MkWindow.vue'; import { popout as _popout } from '@/scripts/popout.js'; @@ -39,11 +40,11 @@ import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { useScrollPositionManager } from '@/nirax.js'; import { i18n } from '@/i18n.js'; import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js'; -import type { PageMetadata } from '@/scripts/page-metadata.js'; import { openingWindowsCount } from '@/os.js'; import { claimAchievement } from '@/scripts/achievements.js'; import { useRouterFactory } from '@/router/supplier.js'; import { mainRouter } from '@/router/main.js'; +import { analytics } from '@/analytics.js'; const props = defineProps<{ initialPath: string; @@ -99,6 +100,14 @@ windowRouter.addListener('replace', ctx => { history.value.push({ path: ctx.path, key: ctx.key }); }); +windowRouter.addListener('change', ctx => { + console.log('windowRouter: change', ctx.path); + analytics.page({ + path: ctx.path, + title: ctx.path, + }); +}); + windowRouter.init(); provide('router', windowRouter); @@ -160,6 +169,11 @@ function popout() { useScrollPositionManager(() => getScrollContainer(contents.value), windowRouter); onMounted(() => { + analytics.page({ + path: props.initialPath, + title: props.initialPath, + }); + openingWindowsCount.value++; if (openingWindowsCount.value >= 3) { claimAchievement('open3windows'); diff --git a/packages/frontend/src/pages/admin/external-services.vue b/packages/frontend/src/pages/admin/external-services.vue index 91f41166e9..a312ecce12 100644 --- a/packages/frontend/src/pages/admin/external-services.vue +++ b/packages/frontend/src/pages/admin/external-services.vue @@ -8,20 +8,34 @@ SPDX-License-Identifier: AGPL-3.0-only - - +
+ + -
- - - - - - - - Save -
-
+
+ + + + + Save +
+ + + + + +
+ + + + + + + + Save +
+
+
@@ -44,10 +58,13 @@ import MkFolder from '@/components/MkFolder.vue'; const deeplAuthKey = ref(''); const deeplIsPro = ref(false); +const googleAnalyticsMeasurementId = ref(''); + async function init() { const meta = await misskeyApi('admin/meta'); - deeplAuthKey.value = meta.deeplAuthKey; + deeplAuthKey.value = meta.deeplAuthKey ?? ''; deeplIsPro.value = meta.deeplIsPro; + googleAnalyticsMeasurementId.value = meta.googleAnalyticsMeasurementId ?? ''; } function save_deepl() { @@ -59,6 +76,14 @@ function save_deepl() { }); } +function save_googleAnalytics() { + os.apiWithDialog('admin/update-meta', { + googleAnalyticsMeasurementId: googleAnalyticsMeasurementId.value, + }).then(() => { + fetchInstance(true); + }); +} + const headerActions = computed(() => []); const headerTabs = computed(() => []); diff --git a/packages/frontend/src/router/main.ts b/packages/frontend/src/router/main.ts index 4379b6a316..3932a8bac8 100644 --- a/packages/frontend/src/router/main.ts +++ b/packages/frontend/src/router/main.ts @@ -7,6 +7,7 @@ import { EventEmitter } from 'eventemitter3'; import type { IRouter, Resolved, RouteDef, RouterEvent, RouterFlag } from '@/nirax.js'; import type { App, ShallowRef } from 'vue'; +import { analytics } from '@/analytics.js'; /** * {@link Router}による画面遷移を可能とするために{@link mainRouter}をセットアップする。 @@ -29,6 +30,14 @@ export function setupRouter(app: App, routerFactory: ((path: string) => IRouter) window.history.replaceState({ key: ctx.key }, '', ctx.path); }); + mainRouter.addListener('change', ctx => { + console.log('mainRouter: change', ctx.path); + analytics.page({ + path: ctx.path, + title: ctx.path, + }); + }); + mainRouter.init(); setMainRouter(mainRouter); diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index c7485c6c3d..ae7a8c7440 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -5042,6 +5042,7 @@ export type components = { enableTurnstile: boolean; turnstileSiteKey: string | null; enableTestcaptcha: boolean; + googleAnalyticsMeasurementId: string | null; swPublickey: string | null; /** @default /assets/ai.png */ mascotImageUrl: string; @@ -8251,6 +8252,7 @@ export type operations = { enableTurnstile: boolean; turnstileSiteKey: string | null; enableTestcaptcha: boolean; + googleAnalyticsMeasurementId: string | null; swPublickey: string | null; /** @default /assets/ai.png */ mascotImageUrl: string | null; @@ -10617,6 +10619,7 @@ export type operations = { turnstileSiteKey?: string | null; turnstileSecretKey?: string | null; enableTestcaptcha?: boolean; + googleAnalyticsMeasurementId?: string | null; /** @enum {string} */ sensitiveMediaDetection?: 'none' | 'all' | 'local' | 'remote'; /** @enum {string} */ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dd5391a218..45f28ac7bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -685,6 +685,9 @@ importers: packages/frontend: dependencies: + '@analytics/google-analytics': + specifier: 1.1.0 + version: 1.1.0 '@discordapp/twemoji': specifier: 15.1.0 version: 15.1.0 @@ -724,6 +727,9 @@ importers: aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.15 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/c3cde89e79a41d93540cf8a48cd619c3f2dcb1b7 + analytics: + specifier: 0.8.16 + version: 0.8.16(@types/dlv@1.1.5) astring: specifier: 1.9.0 version: 1.9.0 @@ -1448,6 +1454,30 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@analytics/cookie-utils@0.2.12': + resolution: {integrity: sha512-2h/yuIu3kmu+ZJlKmlT6GoRvUEY2k1BbQBezEv5kGhnn9KpmzPz715Y3GmM2i+m7Y0QmBdVUoA260dQZkofs2A==} + + '@analytics/core@0.12.17': + resolution: {integrity: sha512-GMxRm5Dp3Wam/w5NNvqNKMO6zWecozbVv21Kn4WhftCx6OjJI7zMlVtiLpjGjxa0RRZfVG80YhupF0Qh9XL2gw==} + + '@analytics/global-storage-utils@0.1.7': + resolution: {integrity: sha512-V+spzGLZYm4biZT4uefaylm80SrLXf8WOTv9hCgA46cLcyxx3LD4GCpssp1lj+RcWLl/uXJQBRO4Mnn/o1x6Gw==} + + '@analytics/google-analytics@1.1.0': + resolution: {integrity: sha512-i8uGyELMtwEUAf3GNWNLNBzhRvReDn1RUxvMdMhjUA7+GNGxPOM4kkzFfv3giQXKNxTEjfsh75kqNcscbJsuaA==} + + '@analytics/localstorage-utils@0.1.10': + resolution: {integrity: sha512-uJS+Jp1yLG5VFCgA5T82ZODYBS0xuDQx0NtAZrgbqt9j51BX3TcgmOez5LVkrUNu/lpbxjCLq35I4TKj78VmOQ==} + + '@analytics/session-storage-utils@0.0.7': + resolution: {integrity: sha512-PSv40UxG96HVcjY15e3zOqU2n8IqXnH8XvTkg1X43uXNTKVSebiI2kUjA3Q7ESFbw5DPwcLbJhV7GforpuBLDw==} + + '@analytics/storage-utils@0.4.2': + resolution: {integrity: sha512-AXObwyVQw9h2uJh1t2hUgabtVxzYpW+7uKVbdHQK80vr3Td5rrmCxrCxarh7HUuAgSDZ0bZWqmYxVgmwKceaLg==} + + '@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==} @@ -4226,6 +4256,9 @@ packages: '@types/disposable-email-domains@1.0.2': resolution: {integrity: sha512-SDKwyYTjk3y5aZBxxc38yRecpJPjsqn57STz1bNxYYlv4k11bBe7QB8w4llXDTmQXKT1mFvgGmJv+8Zdu3YmJw==} + '@types/dlv@1.1.5': + resolution: {integrity: sha512-JHOWNfiWepAhfwlSw17kiWrWrk6od2dEQgHltJw9AS0JPFoLZJBge5+Dnil2NfdjAvJ/+vGSX60/BRW20PpUXw==} + '@types/doctrine@0.0.9': resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} @@ -4864,6 +4897,14 @@ packages: alien-signals@1.0.3: resolution: {integrity: sha512-zQOh3wAYK5ujENxvBBR3CFGF/b6afaSzZ/c9yNhJ1ENrGHETvpUuKQsa93Qrclp0+PzTF93MaZ7scVp1uUozhA==} + analytics-utils@1.0.14: + resolution: {integrity: sha512-9v0kPd8v0GuBvfQcg5BO48AElaEAr9IXMAfJWXYMAhrD3QprgozEIUgMp/de0vS136PUOBB+10XQH9eBgBmfMw==} + peerDependencies: + '@types/dlv': ^1.0.0 + + analytics@0.8.16: + resolution: {integrity: sha512-LEFQ47G9V1zVp9WIh2xhnbmSFEJq+WEzSv6voJ5uba88lefiIIYeG2nq87gFu83ocz1qtb9u7XgeaKKVBbbgWA==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -5947,6 +5988,9 @@ packages: disposable-email-domains@1.0.62: resolution: {integrity: sha512-LBQvhRw7mznQTPoyZbsmYeNOZt1pN5aCsx4BAU/3siVFuiM9f2oyKzUaB8v1jbxFjE3aYqYiMo63kAL4pHgfWQ==} + dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} @@ -10953,6 +10997,42 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 + '@analytics/cookie-utils@0.2.12': + dependencies: + '@analytics/global-storage-utils': 0.1.7 + + '@analytics/core@0.12.17(@types/dlv@1.1.5)': + dependencies: + '@analytics/global-storage-utils': 0.1.7 + '@analytics/type-utils': 0.6.2 + analytics-utils: 1.0.14(@types/dlv@1.1.5) + transitivePeerDependencies: + - '@types/dlv' + + '@analytics/global-storage-utils@0.1.7': + dependencies: + '@analytics/type-utils': 0.6.2 + + '@analytics/google-analytics@1.1.0': {} + + '@analytics/localstorage-utils@0.1.10': + dependencies: + '@analytics/global-storage-utils': 0.1.7 + + '@analytics/session-storage-utils@0.0.7': + dependencies: + '@analytics/global-storage-utils': 0.1.7 + + '@analytics/storage-utils@0.4.2': + dependencies: + '@analytics/cookie-utils': 0.2.12 + '@analytics/global-storage-utils': 0.1.7 + '@analytics/localstorage-utils': 0.1.10 + '@analytics/session-storage-utils': 0.0.7 + '@analytics/type-utils': 0.6.2 + + '@analytics/type-utils@0.6.2': {} + '@apidevtools/swagger-methods@3.0.2': {} '@asamuzakjp/css-color@2.8.3': @@ -14499,6 +14579,8 @@ snapshots: '@types/disposable-email-domains@1.0.2': {} + '@types/dlv@1.1.5': {} + '@types/doctrine@0.0.9': {} '@types/eslint@7.29.0': @@ -15312,6 +15394,19 @@ snapshots: alien-signals@1.0.3: {} + analytics-utils@1.0.14(@types/dlv@1.1.5): + dependencies: + '@analytics/type-utils': 0.6.2 + '@types/dlv': 1.1.5 + dlv: 1.1.3 + + analytics@0.8.16(@types/dlv@1.1.5): + dependencies: + '@analytics/core': 0.12.17(@types/dlv@1.1.5) + '@analytics/storage-utils': 0.4.2 + transitivePeerDependencies: + - '@types/dlv' + ansi-colors@4.1.3: {} ansi-escapes@4.3.2: @@ -16547,6 +16642,8 @@ snapshots: disposable-email-domains@1.0.62: {} + dlv@1.1.3: {} + doctrine@2.1.0: dependencies: esutils: 2.0.3 From 389ec6350be1b5f980eb19db4c98ba2ebf22ca38 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Wed, 26 Feb 2025 09:29:12 +0900 Subject: [PATCH 002/649] fix(backend): send Delete activity of a note to users who renoted or replied to it (#15554) * fix(backend): send Delete activity of a note to users who renoted or replied to it * Update CHANGELOG.md --- CHANGELOG.md | 1 + .../backend/src/core/NoteDeleteService.ts | 24 +++- .../activitypub/ApDeliverManagerService.ts | 19 ++++ .../backend/test-federation/test/note.test.ts | 106 +++++++++++++++--- 4 files changed, 127 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2399ce8a52..8ce0cc6b36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886) - Fix: メールアドレスの形式が正しくなければ以降の処理を行わないように +- Fix: フォロワーではないユーザーにリノートもしくは返信された場合にノートのDeleteアクティビティが送られていない問題を修正 ## 2025.2.0 diff --git a/packages/backend/src/core/NoteDeleteService.ts b/packages/backend/src/core/NoteDeleteService.ts index 4ecd2592b2..e394506a44 100644 --- a/packages/backend/src/core/NoteDeleteService.ts +++ b/packages/backend/src/core/NoteDeleteService.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Brackets, In } from 'typeorm'; +import { Brackets, In, IsNull, Not } from 'typeorm'; import { Injectable, Inject } from '@nestjs/common'; import type { MiUser, MiLocalUser, MiRemoteUser } from '@/models/User.js'; import type { MiNote, IMentionedRemoteUsers } from '@/models/Note.js'; @@ -189,13 +189,27 @@ export class NoteDeleteService { }) as MiRemoteUser[]; } + @bindThis + private async getRenotedOrRepliedRemoteUsers(note: MiNote) { + const query = this.notesRepository.createQueryBuilder('note') + .leftJoinAndSelect('note.user', 'user') + .where(new Brackets(qb => { + qb.orWhere('note.renoteId = :renoteId', { renoteId: note.id }); + qb.orWhere('note.replyId = :replyId', { replyId: note.id }); + })) + .andWhere({ userHost: Not(IsNull()) }); + const notes = await query.getMany() as (MiNote & { user: MiRemoteUser })[]; + const remoteUsers = notes.map(({ user }) => user); + return remoteUsers; + } + @bindThis private async deliverToConcerned(user: { id: MiLocalUser['id']; host: null; }, note: MiNote, content: any) { this.apDeliverManagerService.deliverToFollowers(user, content); this.relayService.deliverToRelays(user, content); - const remoteUsers = await this.getMentionedRemoteUsers(note); - for (const remoteUser of remoteUsers) { - this.apDeliverManagerService.deliverToUser(user, content, remoteUser); - } + this.apDeliverManagerService.deliverToUsers(user, content, [ + ...await this.getMentionedRemoteUsers(note), + ...await this.getRenotedOrRepliedRemoteUsers(note), + ]); } } diff --git a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts index 5d07cd8e8f..0140ce9fd6 100644 --- a/packages/backend/src/core/activitypub/ApDeliverManagerService.ts +++ b/packages/backend/src/core/activitypub/ApDeliverManagerService.ts @@ -196,6 +196,25 @@ export class ApDeliverManagerService { await manager.execute(); } + /** + * Deliver activity to users + * @param actor + * @param activity Activity + * @param targets Target users + */ + @bindThis + public async deliverToUsers(actor: { id: MiLocalUser['id']; host: null; }, activity: IActivity, targets: MiRemoteUser[]): Promise { + const manager = new DeliverManager( + this.userEntityService, + this.followingsRepository, + this.queueService, + actor, + activity, + ); + for (const to of targets) manager.addDirectRecipe(to); + await manager.execute(); + } + @bindThis public createDeliverManager(actor: { id: MiUser['id']; host: null; }, activity: IActivity | null): DeliverManager { return new DeliverManager( diff --git a/packages/backend/test-federation/test/note.test.ts b/packages/backend/test-federation/test/note.test.ts index 220c22e198..1584f9587e 100644 --- a/packages/backend/test-federation/test/note.test.ts +++ b/packages/backend/test-federation/test/note.test.ts @@ -139,29 +139,99 @@ describe('Note', () => { }); describe('Deletion', () => { - describe('Check Delete consistency', () => { - let carol: LoginUser; + describe('Check Delete is delivered', () => { + describe('To followers', () => { + let carol: LoginUser; - beforeAll(async () => { - carol = await createAccount('a.test'); + beforeAll(async () => { + carol = await createAccount('a.test'); - await carol.client.request('following/create', { userId: bobInA.id }); - await sleep(); + await carol.client.request('following/create', { userId: bobInA.id }); + await sleep(); + }); + + test('Check', async () => { + const note = (await bob.client.request('notes/create', { text: 'I\'m Bob.' })).createdNote; + const noteInA = await resolveRemoteNote('b.test', note.id, carol); + await bob.client.request('notes/delete', { noteId: note.id }); + await sleep(); + + await rejects( + async () => await carol.client.request('notes/show', { noteId: noteInA.id }), + (err: any) => { + strictEqual(err.code, 'NO_SUCH_NOTE'); + return true; + }, + ); + }); + + afterAll(async () => { + await carol.client.request('following/delete', { userId: bobInA.id }); + await sleep(); + }); }); - test('Delete is derivered to followers', async () => { - const note = (await bob.client.request('notes/create', { text: 'I\'m Bob.' })).createdNote; - const noteInA = await resolveRemoteNote('b.test', note.id, carol); - await bob.client.request('notes/delete', { noteId: note.id }); - await sleep(); + describe('To renoted and not followed user', () => { + test('Check', async () => { + const note = (await bob.client.request('notes/create', { text: 'I\'m Bob.' })).createdNote; + const noteInA = await resolveRemoteNote('b.test', note.id, alice); + await alice.client.request('notes/create', { renoteId: noteInA.id }); + await sleep(); - await rejects( - async () => await carol.client.request('notes/show', { noteId: noteInA.id }), - (err: any) => { - strictEqual(err.code, 'NO_SUCH_NOTE'); - return true; - }, - ); + await bob.client.request('notes/delete', { noteId: note.id }); + await sleep(); + + await rejects( + async () => await alice.client.request('notes/show', { noteId: noteInA.id }), + (err: any) => { + strictEqual(err.code, 'NO_SUCH_NOTE'); + return true; + }, + ); + }); + }); + + describe('To replied and not followed user', () => { + test('Check', async () => { + const note = (await bob.client.request('notes/create', { text: 'I\'m Bob.' })).createdNote; + const noteInA = await resolveRemoteNote('b.test', note.id, alice); + await alice.client.request('notes/create', { text: 'Hello Bob!', replyId: noteInA.id }); + await sleep(); + + await bob.client.request('notes/delete', { noteId: note.id }); + await sleep(); + + await rejects( + async () => await alice.client.request('notes/show', { noteId: noteInA.id }), + (err: any) => { + strictEqual(err.code, 'NO_SUCH_NOTE'); + return true; + }, + ); + }); + }); + + /** + * FIXME: not delivered + * @see https://github.com/misskey-dev/misskey/issues/15548 + */ + describe('To only resolved and not followed user', () => { + test.failing('Check', async () => { + const note = (await bob.client.request('notes/create', { text: 'I\'m Bob.' })).createdNote; + const noteInA = await resolveRemoteNote('b.test', note.id, alice); + await sleep(); + + await bob.client.request('notes/delete', { noteId: note.id }); + await sleep(); + + await rejects( + async () => await alice.client.request('notes/show', { noteId: noteInA.id }), + (err: any) => { + strictEqual(err.code, 'NO_SUCH_NOTE'); + return true; + }, + ); + }); }); }); From 7f31fd24b1b2494c97c10625d9c69e4083690f42 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 26 Feb 2025 00:47:08 +0000 Subject: [PATCH 003/649] Bump version to 2025.2.1-beta.1 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c6e20945a1..2d2a906f78 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.2.1-beta.0", + "version": "2025.2.1-beta.1", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index a4c8466272..c61c4f4a3b 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.2.1-beta.0", + "version": "2025.2.1-beta.1", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From b5799351d061d92e71f5f95241bac0939eaf20c9 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: Wed, 26 Feb 2025 10:27:38 +0900 Subject: [PATCH 004/649] =?UTF-8?q?fix(backend):=20clips/update=E3=81=AEde?= =?UTF-8?q?scription=E3=81=A7=E7=A9=BA=E6=96=87=E5=AD=97=E3=82=92=E8=A8=B1?= =?UTF-8?q?=E5=AE=B9=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=20(#1542?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): clips/updateのdescriptionで空文字を許容するように * Update Changelog * fix: createの際も空文字を許容するように * fix test * fix test --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + .../src/server/api/endpoints/clips/create.ts | 6 ++-- .../src/server/api/endpoints/clips/update.ts | 6 ++-- packages/backend/test/e2e/clips.ts | 36 ++++++++++++++++++- 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ce0cc6b36..8b5579db4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ - Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886) - Fix: メールアドレスの形式が正しくなければ以降の処理を行わないように +- Fix: クリップの説明欄を更新する際に空にできない問題を修正 - Fix: フォロワーではないユーザーにリノートもしくは返信された場合にノートのDeleteアクティビティが送られていない問題を修正 ## 2025.2.0 diff --git a/packages/backend/src/server/api/endpoints/clips/create.ts b/packages/backend/src/server/api/endpoints/clips/create.ts index ceebc8ba5e..b40706297d 100644 --- a/packages/backend/src/server/api/endpoints/clips/create.ts +++ b/packages/backend/src/server/api/endpoints/clips/create.ts @@ -39,7 +39,7 @@ export const paramDef = { properties: { name: { type: 'string', minLength: 1, maxLength: 100 }, isPublic: { type: 'boolean', default: false }, - description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + description: { type: 'string', nullable: true, maxLength: 2048 }, }, required: ['name'], } as const; @@ -53,7 +53,9 @@ export default class extends Endpoint { // eslint- super(meta, paramDef, async (ps, me) => { let clip: MiClip; try { - clip = await this.clipService.create(me, ps.name, ps.isPublic, ps.description ?? null); + // 空文字列をnullにしたいので??は使わない + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + clip = await this.clipService.create(me, ps.name, ps.isPublic, ps.description || null); } catch (e) { if (e instanceof ClipService.TooManyClipsError) { throw new ApiError(meta.errors.tooManyClips); diff --git a/packages/backend/src/server/api/endpoints/clips/update.ts b/packages/backend/src/server/api/endpoints/clips/update.ts index 603a3ccf3d..6ff3f9aada 100644 --- a/packages/backend/src/server/api/endpoints/clips/update.ts +++ b/packages/backend/src/server/api/endpoints/clips/update.ts @@ -39,7 +39,7 @@ export const paramDef = { clipId: { type: 'string', format: 'misskey:id' }, name: { type: 'string', minLength: 1, maxLength: 100 }, isPublic: { type: 'boolean' }, - description: { type: 'string', nullable: true, minLength: 1, maxLength: 2048 }, + description: { type: 'string', nullable: true, maxLength: 2048 }, }, required: ['clipId'], } as const; @@ -53,7 +53,9 @@ export default class extends Endpoint { // eslint- ) { super(meta, paramDef, async (ps, me) => { try { - await this.clipService.update(me, ps.clipId, ps.name, ps.isPublic, ps.description); + // 空文字列をnullにしたいので??は使わない + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + await this.clipService.update(me, ps.clipId, ps.name, ps.isPublic, ps.description || null); } catch (e) { if (e instanceof ClipService.NoSuchClipError) { throw new ApiError(meta.errors.noSuchClip); diff --git a/packages/backend/test/e2e/clips.ts b/packages/backend/test/e2e/clips.ts index a130c3698d..7ae1ee4523 100644 --- a/packages/backend/test/e2e/clips.ts +++ b/packages/backend/test/e2e/clips.ts @@ -182,7 +182,6 @@ describe('クリップ', () => { { label: 'nameがnull', parameters: { name: null } }, { label: 'nameが最大長+1', parameters: { name: 'x'.repeat(101) } }, { label: 'isPublicがboolじゃない', parameters: { isPublic: 'true' } }, - { label: 'descriptionがゼロ長', parameters: { description: '' } }, { label: 'descriptionが最大長+1', parameters: { description: 'a'.repeat(2049) } }, ]; test.each(createClipDenyPattern)('の作成は$labelならできない', async ({ parameters }) => failedApiCall({ @@ -199,6 +198,23 @@ describe('クリップ', () => { id: '3d81ceae-475f-4600-b2a8-2bc116157532', })); + test('の作成はdescriptionが空文字ならnullになる', async () => { + const clip = await successfulApiCall({ + endpoint: 'clips/create', + parameters: { + ...defaultCreate(), + description: '', + }, + user: alice, + }); + + assert.deepStrictEqual(clip, { + ...clip, + ...defaultCreate(), + description: null, + }); + }); + test('の更新ができる', async () => { const res = await update({ clipId: (await create()).id, @@ -249,6 +265,24 @@ describe('クリップ', () => { ...assertion, })); + test('の更新はdescriptionが空文字ならnullになる', async () => { + const clip = await successfulApiCall({ + endpoint: 'clips/update', + parameters: { + clipId: (await create()).id, + name: 'updated', + description: '', + }, + user: alice, + }); + + assert.deepStrictEqual(clip, { + ...clip, + name: 'updated', + description: null, + }); + }); + test('の削除ができる', async () => { await deleteClip({ clipId: (await create()).id, From 39c487e1d18985e605ab9adae1b49cf63db4e753 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=B4=87=E5=B3=B0=20=E6=9C=94=E8=8F=AF?= <160555157+sakuhanight@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:28:53 +0900 Subject: [PATCH 005/649] =?UTF-8?q?fix(backend):=20=E3=83=AD=E3=83=BC?= =?UTF-8?q?=E3=82=AB=E3=83=AB=E5=88=A4=E5=AE=9A=E3=81=A7isUriLocal?= =?UTF-8?q?=E3=82=92=E4=BD=BF=E7=94=A8=E3=81=97=E3=81=A6=E3=81=84=E3=81=AA?= =?UTF-8?q?=E3=81=84=E7=AE=87=E6=89=80=E3=82=92=E4=BF=AE=E6=AD=A3=20(#1506?= =?UTF-8?q?9)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): ローカル判定でisUriLocalを使用していない箇所を修正 * fix(test backend): RelayServiceでUtilityServiceを使う --- packages/backend/src/core/RemoteUserResolveService.ts | 2 +- packages/backend/src/core/activitypub/ApRendererService.ts | 4 +++- packages/backend/test/unit/RelayService.ts | 3 +++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/core/RemoteUserResolveService.ts b/packages/backend/src/core/RemoteUserResolveService.ts index 098b5e1706..a2f1b73cdb 100644 --- a/packages/backend/src/core/RemoteUserResolveService.ts +++ b/packages/backend/src/core/RemoteUserResolveService.ts @@ -74,7 +74,7 @@ export class RemoteUserResolveService { if (user == null) { const self = await this.resolveSelf(acctLower); - if (self.href.startsWith(this.config.url)) { + if (this.utilityService.isUriLocal(self.href)) { const local = this.apDbResolverService.parseUri(self.href); if (local.local && local.type === 'users') { // the LR points to local diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 9148095067..8688015aff 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -27,6 +27,7 @@ import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFil import { bindThis } from '@/decorators.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { IdService } from '@/core/IdService.js'; +import { UtilityService } from '@/core/UtilityService.js'; import { JsonLdService } from './JsonLdService.js'; import { ApMfmService } from './ApMfmService.js'; import { CONTEXT } from './misc/contexts.js'; @@ -61,6 +62,7 @@ export class ApRendererService { private apMfmService: ApMfmService, private mfmService: MfmService, private idService: IdService, + private utilityService: UtilityService, ) { } @@ -577,7 +579,7 @@ export class ApRendererService { @bindThis public renderUndo(object: string | IObject, user: { id: MiUser['id'] }): IUndo { - const id = typeof object !== 'string' && typeof object.id === 'string' && object.id.startsWith(this.config.url) ? `${object.id}/undo` : undefined; + const id = typeof object !== 'string' && typeof object.id === 'string' && this.utilityService.isUriLocal(object.id) ? `${object.id}/undo` : undefined; return { type: 'Undo', diff --git a/packages/backend/test/unit/RelayService.ts b/packages/backend/test/unit/RelayService.ts index 9676abf07b..3b3d212c30 100644 --- a/packages/backend/test/unit/RelayService.ts +++ b/packages/backend/test/unit/RelayService.ts @@ -3,6 +3,8 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { UtilityService } from '@/core/UtilityService.js'; + process.env.NODE_ENV = 'test'; import { jest } from '@jest/globals'; @@ -40,6 +42,7 @@ describe('RelayService', () => { ApRendererService, RelayService, UserEntityService, + UtilityService, ], }) .useMocker((token) => { From 495db2743318d43961f2a7fea0084ccae1cd9dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:48:38 +0900 Subject: [PATCH 006/649] =?UTF-8?q?fix(backend):=20=E3=82=AB=E3=82=B9?= =?UTF-8?q?=E3=82=BF=E3=83=A0=E7=B5=B5=E6=96=87=E5=AD=97=E3=81=AE=E4=B8=80?= =?UTF-8?q?=E6=8B=AC=E3=82=A4=E3=83=B3=E3=83=9D=E3=83=BC=E3=83=88=E3=82=92?= =?UTF-8?q?=E3=81=97=E3=81=9F=E6=99=82=E3=81=ABHTTP=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=82=AD=E3=82=B7=E3=81=AE=E9=99=A4=E5=A4=96=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=8C=E5=8A=B9=E3=81=8B=E3=81=AA=E3=81=84=E3=81=AE=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=20(#15431)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * pxory * fix * fix CHANGELOG.md * allow localAddress --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/backend/src/core/DownloadService.ts | 4 +- .../backend/src/core/HttpRequestService.ts | 47 ++++++++++++++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b5579db4c..8ffce0beee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Enhance: 成り済まし対策として、ActivityPub照会された時にリモートのリダイレクトを拒否できるように (config.disallowExternalApRedirect) - Fix: `following/invalidate`でフォロワーを解除しようとしているユーザーの情報を返すように - Fix: オブジェクトストレージの設定でPrefixを設定していなかった場合nullまたは空文字になる問題を修正 +- Fix: HTTPプロキシとその除外設定を行った状態でカスタム絵文字の一括インポートをしたとき、除外設定が効かないのを修正( #8766 ) - Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886) - Fix: メールアドレスの形式が正しくなければ以降の処理を行わないように diff --git a/packages/backend/src/core/DownloadService.ts b/packages/backend/src/core/DownloadService.ts index 2e78e6d877..a2b74d1ab2 100644 --- a/packages/backend/src/core/DownloadService.ts +++ b/packages/backend/src/core/DownloadService.ts @@ -60,8 +60,8 @@ export class DownloadService { request: operationTimeout, // whole operation timeout }, agent: { - http: this.httpRequestService.httpAgent, - https: this.httpRequestService.httpsAgent, + http: this.httpRequestService.getAgentForHttp(urlObj, true), + https: this.httpRequestService.getAgentForHttps(urlObj, true), }, http2: false, // default retry: { diff --git a/packages/backend/src/core/HttpRequestService.ts b/packages/backend/src/core/HttpRequestService.ts index 8085bbf961..13d8f7f43b 100644 --- a/packages/backend/src/core/HttpRequestService.ts +++ b/packages/backend/src/core/HttpRequestService.ts @@ -115,32 +115,32 @@ export class HttpRequestService { /** * Get http non-proxy agent (without local address filtering) */ - private httpNative: http.Agent; + private readonly httpNative: http.Agent; /** * Get https non-proxy agent (without local address filtering) */ - private httpsNative: https.Agent; + private readonly httpsNative: https.Agent; /** * Get http non-proxy agent */ - private http: http.Agent; + private readonly http: http.Agent; /** * Get https non-proxy agent */ - private https: https.Agent; + private readonly https: https.Agent; /** * Get http proxy or non-proxy agent */ - public httpAgent: http.Agent; + public readonly httpAgent: http.Agent; /** * Get https proxy or non-proxy agent */ - public httpsAgent: https.Agent; + public readonly httpsAgent: https.Agent; constructor( @Inject(DI.config) @@ -197,7 +197,8 @@ export class HttpRequestService { /** * Get agent by URL * @param url URL - * @param bypassProxy Allways bypass proxy + * @param bypassProxy Always bypass proxy + * @param isLocalAddressAllowed */ @bindThis public getAgentByUrl(url: URL, bypassProxy = false, isLocalAddressAllowed = false): http.Agent | https.Agent { @@ -214,6 +215,38 @@ export class HttpRequestService { } } + /** + * Get agent for http by URL + * @param url URL + * @param isLocalAddressAllowed + */ + @bindThis + public getAgentForHttp(url: URL, isLocalAddressAllowed = false): http.Agent { + if ((this.config.proxyBypassHosts ?? []).includes(url.hostname)) { + return isLocalAddressAllowed + ? this.httpNative + : this.http; + } else { + return this.httpAgent; + } + } + + /** + * Get agent for https by URL + * @param url URL + * @param isLocalAddressAllowed + */ + @bindThis + public getAgentForHttps(url: URL, isLocalAddressAllowed = false): https.Agent { + if ((this.config.proxyBypassHosts ?? []).includes(url.hostname)) { + return isLocalAddressAllowed + ? this.httpsNative + : this.https; + } else { + return this.httpsAgent; + } + } + @bindThis public async getActivityJson(url: string, isLocalAddressAllowed = false, allowSoftfail: FetchAllowSoftFailMask = FetchAllowSoftFailMask.Strict): Promise { const res = await this.send(url, { From d87488a5f054a60632f0c484c84b0c10319946dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:51:23 +0900 Subject: [PATCH 007/649] =?UTF-8?q?fix(frontend):=20=E3=83=A6=E3=83=BC?= =?UTF-8?q?=E3=82=B6=E3=81=AE=E3=82=B5=E3=82=B8=E3=82=A7=E3=82=B9=E3=83=88?= =?UTF-8?q?=E4=B8=AD=E3=81=AB@=E3=82=92=E5=85=A5=E5=8A=9B=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=82=82=E3=82=B5=E3=82=B8=E3=82=A7=E3=82=B9=E3=83=88?= =?UTF-8?q?=E7=B5=90=E6=9E=9C=E3=81=8C=E6=B6=88=E3=81=88=E3=81=AA=E3=81=84?= =?UTF-8?q?=E3=82=88=E3=81=86=E3=81=AB=20(#15435)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + .../frontend/src/components/MkAutocomplete.vue | 6 ++++-- packages/frontend/src/scripts/autocomplete.ts | 14 ++++++++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ffce0beee..5066b95a19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Fix: 埋め込みプレイヤーから外部ページに移動できない問題を修正 - Fix: Play の再読込時に UI が以前の状態を引き継いでしまう問題を修正 `#14378` - Fix: カスタム絵文字管理画面(beta)にてisSensitive/localOnlyの絞り込みが上手くいかない問題の修正 ( #15445 ) +- Fix: ユーザのサジェスト中に@を入力してもサジェスト結果が消えないように `#14385` - Fix: CWの注釈が100文字を超えている場合、ノート投稿ボタンを非アクティブに ### Server diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 685dcb86e4..33495c8af6 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -49,6 +49,7 @@ import sanitizeHtml from 'sanitize-html'; import { emojilist, getEmojiName } from '@@/js/emojilist.js'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js'; import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js'; +import type { EmojiDef } from '@/scripts/search-emoji.js'; import contains from '@/scripts/contains.js'; import { acct } from '@/filters/user.js'; import * as os from '@/os.js'; @@ -58,7 +59,6 @@ import { i18n } from '@/i18n.js'; import { miLocalStorage } from '@/local-storage.js'; import { customEmojis } from '@/custom-emojis.js'; import { searchEmoji } from '@/scripts/search-emoji.js'; -import type { EmojiDef } from '@/scripts/search-emoji.js'; const lib = emojilist.filter(x => x.category !== 'flags'); @@ -198,8 +198,10 @@ function exec() { users.value = JSON.parse(cache); fetching.value = false; } else { + const [username, host] = props.q.toString().split('@'); misskeyApi('users/search-by-username-and-host', { - username: props.q, + username: username, + host: host, limit: 10, detail: false, }).then(searchedUsers => { diff --git a/packages/frontend/src/scripts/autocomplete.ts b/packages/frontend/src/scripts/autocomplete.ts index 55015c90fd..9a603b848c 100644 --- a/packages/frontend/src/scripts/autocomplete.ts +++ b/packages/frontend/src/scripts/autocomplete.ts @@ -4,9 +4,9 @@ */ import { nextTick, ref, defineAsyncComponent } from 'vue'; -import type { Ref } from 'vue'; import getCaretCoordinates from 'textarea-caret'; import { toASCII } from 'punycode.js'; +import type { Ref } from 'vue'; import { popup } from '@/os.js'; export type SuggestionType = 'user' | 'hashtag' | 'emoji' | 'mfmTag' | 'mfmParam'; @@ -98,15 +98,21 @@ export class Autocomplete { const isMention = mentionIndex !== -1; const isHashtag = hashtagIndex !== -1; - const isMfmParam = mfmParamIndex !== -1 && afterLastMfmParam?.includes('.') && !afterLastMfmParam?.includes(' '); + const isMfmParam = mfmParamIndex !== -1 && afterLastMfmParam?.includes('.') && !afterLastMfmParam.includes(' '); const isMfmTag = mfmTagIndex !== -1 && !isMfmParam; const isEmoji = emojiIndex !== -1 && text.split(/:[a-z0-9_+\-]+:/).pop()!.includes(':'); let opened = false; if (isMention && this.onlyType.includes('user')) { - const username = text.substring(mentionIndex + 1); - if (username !== '' && username.match(/^[a-zA-Z0-9_]+$/)) { + // ユーザのサジェスト中に@を入力すると、その位置から新たにユーザ名を取りなおそうとしてしまう + // この動きはリモートユーザのサジェストを阻害するので、@を検知したらその位置よりも前の@を探し、 + // ホスト名を含むリモートのユーザ名を全て拾えるようにする + const mentionIndexAlt = text.lastIndexOf('@', mentionIndex - 1); + const username = mentionIndexAlt === -1 + ? text.substring(mentionIndex + 1) + : text.substring(mentionIndexAlt + 1); + if (username !== '' && username.match(/^[a-zA-Z0-9_@.]+$/)) { this.open('user', username); opened = true; } else if (username === '') { From bd13fb626c599ad24b63bb617e71e3f88c825d1a Mon Sep 17 00:00:00 2001 From: Esurio/1673beta <60435625+1673beta@users.noreply.github.com> Date: Wed, 26 Feb 2025 10:56:23 +0900 Subject: [PATCH 008/649] =?UTF-8?q?fix(backend):=20S3=5FSAFE=E3=81=8B?= =?UTF-8?q?=E3=81=A4URL=5FSAFE=E3=81=A7=E3=81=AA=E3=81=84=E6=96=87?= =?UTF-8?q?=E5=AD=97=E5=88=97=E3=82=92prefix=E3=81=AB=E4=BD=BF=E3=81=88?= =?UTF-8?q?=E3=81=AA=E3=81=84=E3=82=88=E3=81=86=E3=81=AB=20(#15455)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(backend): S3_SAFEかつURL_SAFEでない文字列をprefixに使えないように * update CHANGELOG * fix validation * fix: remove unused import --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/backend/src/server/api/endpoints/admin/update-meta.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5066b95a19..db29385d73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ - Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886) - Fix: メールアドレスの形式が正しくなければ以降の処理を行わないように +- Fix: `update-meta`でobjectStoragePrefixにS3_SAFEかつURL-safeでない文字列を使えないように - Fix: クリップの説明欄を更新する際に空にできない問題を修正 - Fix: フォロワーではないユーザーにリノートもしくは返信された場合にノートのDeleteアクティビティが送られていない問題を修正 diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 1cfa9cffa6..45c012cb0a 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -118,7 +118,7 @@ export const paramDef = { useObjectStorage: { type: 'boolean' }, objectStorageBaseUrl: { type: 'string', nullable: true }, objectStorageBucket: { type: 'string', nullable: true }, - objectStoragePrefix: { type: 'string', nullable: true }, + objectStoragePrefix: { type: 'string', pattern: /^[a-zA-Z0-9-._]*$/.source, nullable: true }, objectStorageEndpoint: { type: 'string', nullable: true }, objectStorageRegion: { type: 'string', nullable: true }, objectStoragePort: { type: 'integer', nullable: true }, From 96fc7e307ab703d4f59d15d56df1102390c0a83a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 26 Feb 2025 02:23:02 +0000 Subject: [PATCH 009/649] Bump version to 2025.2.1-beta.2 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 2d2a906f78..43d4a01fb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.2.1-beta.1", + "version": "2025.2.1-beta.2", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index c61c4f4a3b..06ea1c78ac 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.2.1-beta.1", + "version": "2025.2.1-beta.2", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From a778a63a121994e271856841c46fcf0f59e11f92 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Wed, 26 Feb 2025 14:58:18 +0900 Subject: [PATCH 010/649] New Crowdin updates (#15421) * New translations ja-jp.yml (Spanish) * New translations ja-jp.yml (Japanese, Kansai) * New translations ja-jp.yml (Japanese, Kansai) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (German) * New translations ja-jp.yml (German) * New translations ja-jp.yml (German) * New translations ja-jp.yml (German) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (English) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Portuguese) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Japanese, Kansai) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Japanese, Kansai) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Catalan) --- locales/ca-ES.yml | 28 ++++++++++---- locales/de-DE.yml | 43 +++++++++++++++++++- locales/en-US.yml | 24 +++++++++--- locales/es-ES.yml | 26 +++++++++++++ locales/it-IT.yml | 18 ++++++++- locales/ja-KS.yml | 99 ++++++++++++++++++++++++++++++++++++++++++++++- locales/ko-KR.yml | 5 ++- locales/pt-PT.yml | 2 - locales/zh-CN.yml | 22 +++++++++-- locales/zh-TW.yml | 58 ++++++++++++++++----------- 10 files changed, 278 insertions(+), 47 deletions(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 7b029c6f41..d12da0676f 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -66,7 +66,7 @@ copyFolderId: "Copiar ID de la carpeta" copyProfileUrl: "Copiar adreça URL del perfil" searchUser: "Cercar un usuari" searchThisUsersNotes: "Cercar les publicacions de l'usuari" -reply: "Respon" +reply: "Respostes" loadMore: "Carregar més" showMore: "Veure més" showLess: "Mostrar menys" @@ -111,7 +111,7 @@ followRequests: "Peticions de seguiment" unfollow: "Deixar de seguir" followRequestPending: "Sol·licituds de seguiment pendents" enterEmoji: "Introduir un emoji" -renote: "Impulsar " +renote: "Impulsos" unrenote: "Anul·la l'impuls" renoted: "S'ha impulsat" renotedToX: "Impulsat per {name}." @@ -646,7 +646,7 @@ disablePlayer: "Tanca el reproductor de vídeo" expandTweet: "Expandir post" themeEditor: "Editor de temes" description: "Descripció" -describeFile: "Afegir subtitulació" +describeFile: "Afegeix una descripció " enterFileDescription: "Escriu un peu de foto" author: "Autor" leaveConfirm: "Hi ha canvis sense guardar. Els vols descartar?" @@ -1189,8 +1189,8 @@ currentAnnouncements: "Informes actuals" pastAnnouncements: "Informes passats" youHaveUnreadAnnouncements: "Tens informes per llegir." useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey." -replies: "Respon" -renotes: "Impulsar " +replies: "Respostes" +renotes: "Impulsos" loadReplies: "Mostrar les respostes" loadConversation: "Mostrar la conversació " pinnedList: "Llista fixada" @@ -1309,6 +1309,8 @@ availableRoles: "Roles disponibles " acknowledgeNotesAndEnable: "Activa'l després de comprendre els possibles perills." federationSpecified: "Aquest servidor treballa amb una federació de llistes blanques. No pot interactuar amb altres servidors que no siguin els especificats per l'administrador." federationDisabled: "La unió es troba deshabilitada en aquest servidor. No es pot interactuar amb usuaris d'altres servidors." +confirmOnReact: "Confirmar en reaccionar" +reactAreYouSure: "Vols reaccionar amb \"{emoji}\"?" _accountSettings: requireSigninToViewContents: "És obligatori l'inici de sessió per poder veure el contingut" requireSigninToViewContentsDescription1: "Es requereix l'inici de sessió per poder veure totes les notes i el contingut que has creat. Amb això esperem evitar que els rastrejadors recopilin informació." @@ -2440,6 +2442,8 @@ _notification: flushNotification: "Netejar notificacions" exportOfXCompleted: "Completada l'exportació de {x}" login: "Algú ha iniciat sessió " + createToken: "Token d'accés generat" + createTokenDescription: "Si no saps què és, esborra el token des de {text}." _types: all: "Tots" note: "Notes noves" @@ -2822,8 +2826,6 @@ _remoteLookupErrors: _responseInvalid: title: "La resposta no és correcta " description: "Hem pogut comunicar-nos amb aquest servidor, però les dades rebudes no són correctes." - _responseInvalidIdHostNotMatch: - description: "El domini de l'adreça introduïda no és el mateix que el domini de l'adreça final obtinguda. Si estàs consultant continguts remots mitjançant servidors tercers, torna a fer la consulta fent servir l'adreça que es pot obtenir en el servidor origen." _noSuchObject: title: "No s'ha trobat" description: "No es pot trobar el recurs sol·licitat, si us plau comprova l'adreça una altra vegada." @@ -2840,3 +2842,15 @@ _captcha: _unknown: title: "Error CAPTCHA" text: "S'ha produït un error inesperat." +_bootErrors: + title: "Hi ha hagut en error en carregar" + serverError: "Si el problema persisteix després d'esperar una mica i recarregar, posa't en contacte amb l'administrador del servidor amb el següent codi d'error." + solution: "Per intentar resoldre el problema pots fer el següent." + solution1: "Actualitza el navegador i el sistema operatiu a l'última versió " + solution2: "Desactiva els adblockers" + solution3: "Esborra la memòria cau del navegador" + solution4: "(Navegador Tor) configura dom.webaudio.enabled a true" + otherOption: "Altres opcions" + otherOption1: "Esborrar la configuració i la memòria cau del client" + otherOption2: "Iniciar client senzill" + otherOption3: "Iniciar l'eina de reparació " diff --git a/locales/de-DE.yml b/locales/de-DE.yml index 11fe6d3ff5..d9072683cb 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1383,6 +1383,9 @@ _initialTutorial: title: "Was sind Notizen?" description: "Beiträge auf Misskey heißen \"Notizen\". Notizen werden chronologisch in der Chronik angeordnet und in Echtzeit aktualisiert." reply: "Klicke auf diesen Button, um auf eine Nachricht zu antworten. Es ist auch möglich, auf Antworten zu antworten und die Unterhaltung wie einen Thread fortzusetzen." + renote: "Du kannst diese Notiz in deiner eigenen Chronik teilen. Du kannst sie auch mit deinen Kommentaren zitieren." + reaction: "Du kannst der Notiz Reaktionen hinzufügen. Weitere Einzelheiten werden auf der nächsten Seite erläutert." + menu: "Du kannst Details zu Notizen anzeigen, Links kopieren und verschiedene andere Aktionen durchführen." _reaction: title: "Was sind Reaktionen?" description: "Auf Notizen kann mit verschiedenen Emojis reagiert werden. Reaktionen ermöglichen es dir, Nuancen auszudrücken, die mit einem einfachen „Gefällt mir“ vielleicht nicht ausgedrückt werden können." @@ -1401,13 +1404,21 @@ _initialTutorial: _visibility: description: "Du kannst einschränken, wer deine Notiz sehen kann." public: "Deine Notiz wird für alle Nutzer sichtbar sein." + direct: "Die Notiz wird nur für den angegebenen Benutzer veröffentlicht und der Empfänger wird benachrichtigt. Kann anstelle von Direktnachrichten verwendet werden." doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!" + doNotSendConfidencialOnDirect2: "Die Administratoren des Servers können den Inhalt der Notiz sehen. Sei vorsichtig mit sensiblen Informationen, wenn du Direktnachrichten an Benutzer auf nicht vertrauenswürdigen Servern sendest." + localOnly: "Wenn du eine Notiz mit dieser Einstellung veröffentlichst, wird sie nicht an andere Server weitergeleitet. Benutzer auf anderen Servern können diese Notizen nicht direkt sehen, unabhängig von den obigen Anzeigeeinstellungen." _cw: title: "Inhaltswarnung" + description: "Anstelle des Textes wird das angezeigt, was du im Abschnitt „Anmerkungen“ angibst. Drücke auf „Inhalt anzeigen“, um den vollständigen Text zu sehen." _exampleNote: + cw: "Das wird dich bestimmt hungrig machen!" note: "Ich hatte gerade einen Donut mit Schokoladenüberzug 🍩😋" _howToMakeAttachmentsSensitive: + title: "Wie markiert man Anhänge als sensibel?" tryThisFile: "Versuche, das angehängte Bild als sensibel zu markieren!" + _exampleNote: + note: "Ups, ich habe es vergeigt, den Natto-Deckel zu öffnen..." method: "Um einen Anhang als sensibel zu kennzeichnen, klicke auf das Vorschaubild der Datei, um das Menü zu öffnen, und klicke auf „Als sensibel markieren“." sensitiveSucceeded: "Wenn du Dateien anhängst, stelle bitte die Sensibilität entsprechend der Serverrichtlinien ein." doItToContinue: "Markiere die angehängte Datei als sensibel, um fortzufahren." @@ -1431,6 +1442,7 @@ _serverSettings: fanoutTimelineDescription: "Ist diese Option aktiviert, kann eine erhebliche Verbesserung im Abrufen von Chroniken und eine Reduzierung der Datenbankbelastung erzielt werden, im Gegenzug zu einer Steigerung in der Speichernutzung von Redis. Bei geringem Serverspeicher oder Serverinstabilität kann diese Option deaktiviert werden." fanoutTimelineDbFallback: "Auf die Datenbank zurückfallen" fanoutTimelineDbFallbackDescription: "Ist diese Option aktiviert, wird die Chronik auf zusätzliche Abfragen in der Datenbank zurückgreifen, wenn sich die Chronik nicht im Cache befindet. Eine Deaktivierung führt zu geringerer Serverlast, aber schränkt den Zeitraum der abrufbaren Chronik ein. " + reactionsBufferingDescription: "Wenn diese Option aktiviert ist, kann sie die Leistung beim Erstellen von Reaktionen erheblich verbessern und die Belastung der Datenbank verringern. Allerdings steigt die Speichernutzung von Redis." openRegistrationWarning: "Das Aktivieren von Registrierungen ist riskant. Es wird empfohlen, sie nur dann zu aktivieren, wenn der Server ständig überwacht wird und im Falle eines Problems sofort reagiert werden kann." thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern." _accountMigration: @@ -1835,6 +1847,7 @@ _plugin: installWarn: "Installiere bitte nur vertrauenswürdige Plugins." manage: "Plugins verwalten" viewSource: "Quelltext anzeigen" + viewLog: "Protokoll anzeigen" _preferencesBackups: list: "Erstellte Backups" saveNew: "Neu erstellen" @@ -1864,6 +1877,8 @@ _aboutMisskey: contributors: "Hauptmitwirkende" allContributors: "Alle Mitwirkenden" source: "Quellcode" + original: "Original" + thisIsModifiedVersion: "{name} verwendet eine modifizierte Version des ursprünglichen Misskey." translation: "Misskey übersetzen" donate: "An Misskey spenden" morePatrons: "Wir schätzen ebenso die Unterstützung vieler anderer hier nicht gelisteter Personen sehr. Danke! 🥰" @@ -1989,6 +2004,8 @@ _soundSettings: driveFileTypeWarn: "Diese Datei wird nicht unterstützt" driveFileTypeWarnDescription: "Bitte wähle eine Audiodatei" driveFileDurationWarn: "Audio zu lang." + driveFileDurationWarnDescription: "Lange Töne kann die Verwendung von Misskey stören. Trotzdem fortfahren?" + driveFileError: "Audio konnte nicht geladen werden. Bitte ändere die Einstellung." _ago: future: "Zukunft" justNow: "Gerade eben" @@ -2000,6 +2017,10 @@ _ago: monthsAgo: "vor {n} Monat(en)" yearsAgo: "vor {n} Jahr(en)" invalid: "Ungültig" +_timeIn: + seconds: "In {n}s" + minutes: "In {n} Min." + hours: "In {n} Std." _time: second: "Sekunde(n)" minute: "Minute(n)" @@ -2105,6 +2126,7 @@ _auth: permissionAsk: "Diese Anwendung fordert folgende Berechtigungen" pleaseGoBack: "Bitte kehre zur Anwendung zurück" callback: "Es wird zur Anwendung zurückgekehrt" + accepted: "Zugriff gewährt" denied: "Zugriff verweigert" pleaseLogin: "Bitte logge dich ein, um Apps zu authorisieren." _antennaSources: @@ -2215,6 +2237,7 @@ _profile: changeBanner: "Banner ändern" verifiedLinkDescription: "Gibst du hier eine URL ein, die einen Link zu deinem Profile enthält, wird neben diesem Feld ein Icon zur Besitzbestätigung angezeigt." avatarDecorationMax: "Du kannst bis zu {max} Dekorationen hinzufügen." + followedMessage: "Nachricht, wenn dir jemand folgt" followedMessageDescription: "Du kannst eine kurze Nachricht festlegen, die dem Empfänger angezeigt wird, wenn er dir folgt." _exportOrImport: allNotes: "Alle Notizen" @@ -2343,8 +2366,11 @@ _notification: sendTestNotification: "Testbenachrichtigung senden" notificationWillBeDisplayedLikeThis: "Benachrichtigungen sehen so aus" reactedBySomeUsers: "{n} Benutzer haben eine Reaktion geschickt" + likedBySomeUsers: "{n} Benutzer mochten deine Notiz" renotedBySomeUsers: "Renote von {n} Benutzern" followedBySomeUsers: "Von {n} Benutzern gefolgt" + flushNotification: "Benachrichtigungen löschen" + exportOfXCompleted: "Der Export von {x} ist abgeschlossen" login: "Neue Anmeldung erfolgt" _types: all: "Alle" @@ -2360,7 +2386,9 @@ _notification: followRequestAccepted: "Akzeptierte Follow-Anfragen" roleAssigned: "Rolle zugewiesen" achievementEarned: "Errungenschaft freigeschaltet" - login: "Anmelden" + exportCompleted: "Der Export ist abgeschlossen" + login: "Anmeldung" + test: "Test-Benachrichtigungen" app: "Benachrichtigungen von Apps" _actions: followBack: "folgt dir nun auch" @@ -2370,6 +2398,7 @@ _deck: alwaysShowMainColumn: "Hauptspalte immer zeigen" columnAlign: "Spaltenausrichtung" addColumn: "Spalte hinzufügen" + newNoteNotificationSettings: "Benachrichtigungseinstellungen für neue Notizen" configureColumn: "Spalteneinstellungen" swapLeft: "Mit linker Spalte tauschen" swapRight: "Mit rechter Spalte tauschen" @@ -2408,6 +2437,7 @@ _drivecleaner: orderByCreatedAtAsc: "Aufsteigendes Erstelldatum" _webhookSettings: createWebhook: "Webhook erstellen" + modifyWebhook: "Webhook bearbeiten" name: "Name" secret: "Secret" trigger: "Auslöser" @@ -2420,12 +2450,22 @@ _webhookSettings: renote: "Wenn du ein Renote erhältst" reaction: "Wenn du eine Reaktion erhältst" mention: "Wenn du erwähnt wirst" + deleteConfirm: "Bist du sicher, dass du den Webhook löschen willst?" _abuseReport: _notificationRecipient: createRecipient: "Meldungsempfänger hinzufügen" + modifyRecipient: "Bearbeite einen Empfänger für Meldungen" + recipientType: "Art der Benachrichtigung" _recipientType: mail: "Email" + webhook: "Webhook" + _captions: + mail: "Die Benachrichtigung wird bei Eingang einer Meldung an die E-Mail-Adressen der Moderatoren gesendet" + webhook: "Sendet eine Benachrichtigung an den System Webhook, wenn eine Meldung eingegangen ist oder gelöst wurde" keywords: "Schlüsselwort" + notifiedUser: "Zu benachrichtigender Benutzer" + notifiedWebhook: "Zu verwendender Webhook" + deleteConfirm: "Bist du sicher, dass du den Empfänger der Benachrichtigung entfernen möchtest?" _moderationLogTypes: createRole: "Rolle erstellt" deleteRole: "Rolle gelöscht" @@ -2465,6 +2505,7 @@ _moderationLogTypes: createSystemWebhook: "System-Webhook erstellt" updateSystemWebhook: "System-Webhook aktualisiert" deleteSystemWebhook: "System-Webhook gelöscht" + deleteAccount: "Benutzerkonto gelöscht" deletePage: "Seite gelöscht" deleteGalleryPost: "Galeriebeitrag gelöscht" _fileViewer: diff --git a/locales/en-US.yml b/locales/en-US.yml index 6ff7e5fb7c..fe4bbef391 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -132,7 +132,7 @@ reaction: "Reactions" reactions: "Reactions" emojiPicker: "Emoji picker" pinnedEmojisForReactionSettingDescription: "Set the emojis to be pinned and displayed when reacting." -pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker." +pinnedEmojisSettingDescription: "Set the emojis to be pinned and displayed when viewing emoji picker" emojiPickerDisplay: "Emoji picker display" overwriteFromPinnedEmojisForReaction: "Override from reaction settings" overwriteFromPinnedEmojis: "Override from general settings" @@ -586,7 +586,7 @@ popout: "Pop-out" volume: "Volume" masterVolume: "Master volume" notUseSound: "Disable sound" -useSoundOnlyWhenActive: "Output sounds only if Misskey is active." +useSoundOnlyWhenActive: "Output sounds only if Misskey is active" details: "Details" renoteDetails: "Renote details" chooseEmoji: "Select an emoji" @@ -1261,7 +1261,7 @@ copyReplayData: "Copy replay data" ranking: "Ranking" lastNDays: "Last {n} days" backToTitle: "Go back to title" -hemisphere: "Where are you located" +hemisphere: "Where you live" withSensitive: "Include notes with sensitive files" userSaysSomethingSensitive: "Post by {name} contains sensitive content" enableHorizontalSwipe: "Swipe to switch tabs" @@ -1309,6 +1309,8 @@ availableRoles: "Available roles" acknowledgeNotesAndEnable: "Turn on after understanding the precautions." federationSpecified: "This server is operated in a whitelist federation. Interacting with servers other than those designated by the administrator is not allowed." federationDisabled: "Federation is disabled on this server. You cannot interact with users on other servers." +confirmOnReact: "Confirm when reacting" +reactAreYouSure: "Would you like to add a \"{emoji}\" reaction?" _accountSettings: requireSigninToViewContents: "Require sign-in to view contents" requireSigninToViewContentsDescription1: "Require login to view all notes and other content you have created. This will have the effect of preventing crawlers from collecting your information." @@ -2440,6 +2442,8 @@ _notification: flushNotification: "Clear notifications" exportOfXCompleted: "Export of {x} has been completed" login: "Someone logged in" + createToken: "An access token has been created" + createTokenDescription: "If you have no idea, delete the access token through \"{text}\"." _types: all: "All" note: "New notes" @@ -2822,8 +2826,6 @@ _remoteLookupErrors: _responseInvalid: title: "Response is invalid" description: "It could communicate with this server, but the data obtained was incorrect." - _responseInvalidIdHostNotMatch: - description: "The domain of the entered URI differs from the domain of the final obtained URI. If you are looking up remote content through a third-party server, please look up again using a URI that can be obtained from the origin server." _noSuchObject: title: "Not found" description: "The requested resource was not found, please recheck the URI." @@ -2840,3 +2842,15 @@ _captcha: _unknown: title: "CAPTCHA error" text: "An unexpected error occurred." +_bootErrors: + title: "Failed to load" + serverError: "If the problem persists after waiting a moment and reloading, please contact the server administrator with the following Error ID." + solution: "The following may solve the problem." + solution1: "Update your browser and OS to the latest version" + solution2: "Disable ad blocker" + solution3: "Clear the browser cache" + solution4: "Set the dom.webaudio.enabled to true for Tor Browser" + otherOption: "Other options" + otherOption1: "Delete client settings and cache" + otherOption2: "Start the simple client" + otherOption3: "Launch the repair tool" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 0b1411d84b..05d5e8c4c7 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -605,6 +605,7 @@ descendingOrder: "Descendente" scratchpad: "Scratch pad" scratchpadDescription: "Scratchpad proporciona un entorno experimental para AiScript. Puede escribir, ejecutar y verificar los resultados que interactúan con Misskey." uiInspector: "Inspector de UI" +uiInspectorDescription: "Puedes visualizar una lista de elementos UI presentes en la memoria. Los componentes de la interfaz de usuario son generados por las funciones UI:C:" output: "Salida" script: "Script" disablePagesScript: "Deshabilitar AiScript en Páginas" @@ -693,6 +694,7 @@ regexpError: "Error de la expresión regular" regexpErrorDescription: "Ocurrió un error en la expresión regular en la linea {line} de las palabras muteadas {tab}" instanceMute: "Instancias silenciadas" userSaysSomething: "{name} dijo algo" +userSaysSomethingAbout: "{name} dijo algo sobre {word}" makeActive: "Activar" display: "Apariencia" copy: "Copiar" @@ -861,6 +863,7 @@ administration: "Administrar" accounts: "Cuentas" switch: "Cambiar" noMaintainerInformationWarning: "No se ha establecido la información del administrador" +noInquiryUrlWarning: "No se ha guardado la URL de consulta." noBotProtectionWarning: "La protección contra los bots no está configurada" configure: "Configurar" postToGallery: "Crear una nueva publicación en la galería" @@ -925,6 +928,7 @@ followersVisibility: "Visibilidad de seguidores" continueThread: "Ver la continuación del hilo" deleteAccountConfirm: "La cuenta será borrada. ¿Está seguro?" incorrectPassword: "La contraseña es incorrecta" +incorrectTotp: "La contraseña de un solo uso es incorrecta o ha caducado." voteConfirm: "¿Confirma su voto a {choice}?" hide: "Ocultar" useDrawerReactionPickerForMobile: "Mostrar panel de reacciones en móviles" @@ -1053,6 +1057,7 @@ thisPostMayBeAnnoyingHome: "Publicar en línea de tiempo 'Inicio'" thisPostMayBeAnnoyingCancel: "detener" thisPostMayBeAnnoyingIgnore: "Publicar de todos modos" collapseRenotes: "Colapsar renotas que ya hayas visto" +collapseRenotesDescription: "Contrae notas a las que ya has reaccionado o renotado " internalServerError: "Error interno del servidor" internalServerErrorDescription: "El servidor tuvo un error inesperado." copyErrorInfo: "Copiar detalles del error" @@ -1091,6 +1096,7 @@ retryAllQueuesConfirmTitle: "Desea ¿reintentar inmediatamente todas las colas?" retryAllQueuesConfirmText: "La carga del servidor está incrementándose temporalmente " enableChartsForRemoteUser: "Generar gráficas de usuarios remotos." enableChartsForFederatedInstances: "Generar gráficos de servidores remotos" +enableStatsForFederatedInstances: "Activar las estadísticas de las instancias remotas federadas" showClipButtonInNoteFooter: "Añadir \"Clip\" al menú de notas" reactionsDisplaySize: "Tamaño de las reacciones" limitWidthOfReaction: "Limitar ancho de las reacciones" @@ -1139,6 +1145,7 @@ preventAiLearningDescription: "Pedirle a las arañas (crawlers) no usar los text options: "Opción" specifyUser: "Especificar usuario" lookupConfirm: "¿Quiere informarse?" +openTagPageConfirm: "¿Quieres abrir la página de etiquetas?" specifyHost: "Especificar Host" failedToPreviewUrl: "No se pudo generar la vista previa" update: "Actualizar" @@ -1267,13 +1274,29 @@ useBackupCode: "Usar códigos de respaldo" launchApp: "Ejecutar la app" useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reproduce audio y vídeo" keepOriginalFilename: "Mantener el nombre original del archivo" +keepOriginalFilenameDescription: "Si desactivas esta opción, los nombres de los archivos serán remplazados por una cadena de caracteres aleatoria cuando subas los archivos." noDescription: "No hay descripción" alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien" inquiry: "Contacto" tryAgain: "Por favor , inténtalo de nuevo" +confirmWhenRevealingSensitiveMedia: "Confirmación cuando se revele contenido sensible" +sensitiveMediaRevealConfirm: "Esto puede contener contenido sensible. ¿Estás seguro/a de querer mostrarlo?" +createdLists: "Listas creadas" +createdAntennas: "Antenas creadas" +fromX: "De {x}" +genEmbedCode: "Obtener el código para incrustar" +noteOfThisUser: "Notas de este usuario" +clipNoteLimitExceeded: "No se pueden añadir más notas a este clip." performance: "Rendimiento" +modified: "Modificado" +discard: "Descartar" +thereAreNChanges: "Hay {n} cambio(s)" +signinWithPasskey: "Iniciar sesión con clave de acceso" unknownWebAuthnKey: "Esto no se ha registrado llave maestra." +passkeyVerificationFailed: "La verificación de la clave de acceso ha fallado." +passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificación de la clave de acceso ha sido satisfactoria pero se ha deshabilitado el inicio de sesión sin contraseña." messageToFollower: "Mensaje a seguidores" +target: "Para" federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador." federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores" _accountSettings: @@ -2560,6 +2583,9 @@ _mediaControls: pip: "Picture in Picture" playbackRate: "Velocidad de reproducción" loop: "Reproducción en bucle" +_followRequest: + recieved: "Petición de seguimiento recibida" + sent: "Petición de seguimiento enviada" _remoteLookupErrors: _noSuchObject: title: "No se encuentra" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index c233e3ab87..66cdd5af76 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1309,6 +1309,8 @@ availableRoles: "Ruoli disponibili" acknowledgeNotesAndEnable: "Attivare dopo averne compreso il comportamento." federationSpecified: "Questo server è federato solo con istanze specifiche del Fediverso. Puoi interagire solo con quelle scelte dall'amministrazione." federationDisabled: "Questo server ha la federazione disabilitata. Non puoi interagire con profili provenienti da altri server." +confirmOnReact: "Confermare le reazioni" +reactAreYouSure: "Vuoi davvero reagire con {emoji} ?" _accountSettings: requireSigninToViewContents: "Per vedere il contenuto, è necessaria l'iscrizione" requireSigninToViewContentsDescription1: "Richiedere l'iscrizione per visualizzare tutte le Note e gli altri contenuti che hai creato. Probabilmente l'effetto è impedire la raccolta di informazioni da parte dei bot crawler." @@ -2440,6 +2442,8 @@ _notification: flushNotification: "Azzera le notifiche" exportOfXCompleted: "Abbiamo completato l'esportazione di {x}" login: "Autenticazione avvenuta" + createToken: "È stato creato un token di accesso" + createTokenDescription: "In caso contrario, eliminare il token di accesso tramite ({text})." _types: all: "Tutto" note: "Nuove Note" @@ -2822,8 +2826,6 @@ _remoteLookupErrors: _responseInvalid: title: "Risposta non valida" description: "La comunicazione col server è andata a buon fine, ma abbiamo ricevuto dati non validi." - _responseInvalidIdHostNotMatch: - description: "L'indirizzo immesso non coincide con la URL finale. Interrogando i server per un contenuto remoto, assicurarsi di utilizzare la URL finale e non quella di un server intermedio." _noSuchObject: title: "Non trovato" description: "La risorsa richiesta non è stata trovata. Verificare nuovamente la URL." @@ -2840,3 +2842,15 @@ _captcha: _unknown: title: "Errore CAPTCHA" text: "Si è verificato un errore imprevisto." +_bootErrors: + title: "Caricamento non riuscito" + serverError: "Dopo una breve attesa, e dopo aver ricaricato la pagina, se il problema persiste, contatta l'amministrazione comunicando il seguente ID di errore." + solution: "Di seguito, alcune probabili soluzioni al problema." + solution1: "Aggiornare browser e il sistema operativo all'ultima versione" + solution2: "Disattivare gli adblocker" + solution3: "Cancellare la cache del browser" + solution4: "(Per chi utilizza il Browser Tor) Impostare dom.webaudio.enabled = vero" + otherOption: "Altre opzioni" + otherOption1: "Nelle impostazioni, cancellare le impostazioni del client e svuotare la cache" + otherOption2: "Avviare il client predefinito" + otherOption3: "Avviare lo strumento di riparazione" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index 66560f524b..e5d0f153a6 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -5,6 +5,7 @@ introMisskey: "ようお越し!Misskeyは、オープンソースの分散型 poweredByMisskeyDescription: "{name}は、オープンソースのプラットフォームMisskeyのサーバーのひとつなんやで。" monthAndDay: "{month}月 {day}日" search: "探す" +reset: "リセット" notifications: "通知" username: "ユーザー名" password: "パスワード" @@ -48,6 +49,7 @@ pin: "ピン留めしとく" unpin: "ピン留めやめる" copyContent: "内容をコピー" copyLink: "リンクをコピー" +copyRemoteLink: "リモートのリンクをコピーするで?" copyLinkRenote: "リノートのリンクをコピーするで?" delete: "ほかす" deleteAndEdit: "ほかして直す" @@ -684,11 +686,15 @@ smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する" smtpSecureInfo: "STARTTLS使っとる時はオフにしてや。" testEmail: "配信テスト" wordMute: "ワードミュート" +wordMuteDescription: "指定した語句が入ってるノートを最小化するで。最小化されたノートをクリックしたら、表示できるようになるで。" hardWordMute: "ハードワードミュート" +showMutedWord: "ミュートされたワードを表示するで" +hardWordMuteDescription: "指定した語句が入ってるノートを隠すで。ワードミュートとちゃうて、ノートは完全に表示されんようになるで。" regexpError: "正規表現エラー" regexpErrorDescription: "{tab}ワードミュートの{line}行目の正規表現にエラーが出てきたで:" instanceMute: "サーバーミュート" userSaysSomething: "{name}が何か言うとるわ" +userSaysSomethingAbout: "{name}が「{word}」についてなんか言うてたで" makeActive: "使うで" display: "表示" copy: "コピー" @@ -1301,6 +1307,10 @@ lockdown: "ロックダウン" pleaseSelectAccount: "アカウント選んでや" availableRoles: "使えるロール" acknowledgeNotesAndEnable: "注意事項をわかった上でオンにする。" +federationSpecified: "このサーバーはホワイトリスト連合で運用されてるで。管理者が指定したサーバー以外とはやり取りできひんで。" +federationDisabled: "このサーバーは連合が無効化されてるで。他のサーバーのユーザーとやり取りすることはできひんで。" +confirmOnReact: "ツッコむときに確認とる" +reactAreYouSure: "\" {emoji} \" でツッコむ?" _accountSettings: requireSigninToViewContents: "ログインしてもらってからコンテンツ見てもらう" requireSigninToViewContentsDescription1: "あなたが作成した全部のノートとかのコンテンツを見れるようにするのにログインがいるようにするで。クローラーにいろいろ収集されるんを防げるかもしれん。" @@ -2432,6 +2442,8 @@ _notification: flushNotification: "通知の履歴をリセットする" exportOfXCompleted: "{x}のエクスポートが終わったわ" login: "ログインしとったで" + createToken: "アクセストークンが作成されたで" + createTokenDescription: "心当たりないんやったら「{text}」でアクセストークンを削除してやって。" _types: all: "すべて" note: "あんたらの新規投稿" @@ -2718,6 +2730,66 @@ _contextMenu: app: "アプリ" appWithShift: "Shiftキーでアプリ" native: "ブラウザのUI" +_gridComponent: + _error: + requiredValue: "この値は必須項目やで" + columnTypeNotSupport: "正規表現によるバリデーションはtype:textのカラムだけサポートしてるで" + patternNotMatch: "この値は{pattern}のパターンに一致しいひんで" + notUnique: "この値は一意でなあかんで" +_roleSelectDialog: + notSelected: "選択されとらんで" +_customEmojisManager: + _gridCommon: + copySelectionRows: "選択行をコピーするで" + copySelectionRanges: "選択範囲をコピーするで" + deleteSelectionRows: "選択行を削除するで" + deleteSelectionRanges: "選択範囲の値をクリアするで" + searchSettings: "検索設定" + searchSettingCaption: "検索条件を詳しく設定するで。" + searchLimit: "表示件数" + sortOrder: "並び順" + registrationLogs: "登録ログ" + registrationLogsCaption: "絵文字更新・削除時のログが表示されるで。更新・削除操作をしたり、ページを遷移・リロードしたら消えるから気ぃつけてな。" + alertEmojisRegisterFailedDescription: "絵文字の更新・削除に失敗したで。詳細は登録ログを確認してな。" + _logs: + showSuccessLogSwitch: "成功ログを表示するで" + failureLogNothing: "失敗ログはあらへん。" + logNothing: "失敗ログはあらへん。" + _remote: + selectionRowDetail: "選択行の詳細やで" + importSelectionRows: "選択行をインポートするで" + importSelectionRangesRows: "選択範囲の行をインポートするで" + importEmojisButton: "チェックされた絵文字をインポートするで" + confirmImportEmojisTitle: "絵文字のインポートするで" + confirmImportEmojisDescription: "リモートから受信した{count}個の絵文字をインポートするで。絵文字のライセンスには十分気ぃつけてな。実行してもええか?" + _local: + tabTitleList: "登録済み絵文字一覧" + tabTitleRegister: "絵文字の登録" + _list: + emojisNothing: "登録された絵文字はないで。" + markAsDeleteTargetRows: "選択行を削除対象にするで" + markAsDeleteTargetRanges: "選択範囲の行を削除対象にするで" + alertUpdateEmojisNothingDescription: "変更された絵文字はないで。" + alertDeleteEmojisNothingDescription: "削除対象の絵文字はないで。" + confirmMovePage: "ページを移動してもええんか?" + confirmChangeView: "表示を変更してもええんか?" + confirmUpdateEmojisDescription: "{count}個の絵文字を更新するで。実行してもええか?" + confirmDeleteEmojisDescription: "チェックがつけられた{count}個の絵文字を削除するで。ほんまにええか?" + confirmResetDescription: "今までやった変更が全部リセットされるで。" + confirmMovePageDesciption: "このページの絵文字に変更が加えられてるで。\n保存せずページを移動してまうと、このページで加えた変更が全てパーになるで。" + dialogSelectRoleTitle: "絵文字に設定されたロールで検索" + _register: + uploadSettingTitle: "アップロード設定" + uploadSettingDescription: "この画面で絵文字アップロードするときの動きを設定できるで。" + directoryToCategoryLabel: "ディレクトリ名を\"category\"に入力する" + directoryToCategoryCaption: "ディレクトリをドラッグ・ドロップした時に、ディレクトリ名を\"category\"に入力します。" + emojiInputAreaCaption: "どれかの方法で登録する絵文字を選択して。" + emojiInputAreaList1: "この枠に画像ファイルかディレクトリをドラッグ&ドロップ" + emojiInputAreaList2: "このリンクをクリックしてPCから選択する" + emojiInputAreaList3: "このリンクをクリックしてドライブから選択する" + confirmRegisterEmojisDescription: "リストに表示されてる絵文字を新たなカスタム絵文字として登録するで。ほんまにええか? (サーバーがしんどくなるから、一回で登録できる絵文字は{count}件までやで)" + confirmClearEmojisDescription: "編集内容をほかして、リストに表示されている絵文字をクリアするで。ほんまにええか?" + confirmUploadEmojisDescription: "ドラッグ&ドロップされた{count}個のファイルをドライブにアップロードするで。ほんまにええか?" _embedCodeGen: title: "埋め込みコードをカスタム" header: "ヘッダー出す" @@ -2754,8 +2826,31 @@ _remoteLookupErrors: _responseInvalid: title: "レスポンスがおかしいで" description: "このサーバーと通信することはできたけど、もらったデータがおかしかったで。" - _responseInvalidIdHostNotMatch: - description: "入力されたURIのドメインと最終的に得られたURIのドメインとが違うで。第三者のサーバーを介してリモートのコンテンツを照会してるんやったら、発信元のサーバーで取得できるURIを使って照会し直して。" _noSuchObject: title: "見つからへんね" description: "求められたリソースが見つからんかったで。URIをもっかい確かめてや。" +_captcha: + verify: "CAPTCHAしばいたって" + testSiteKeyMessage: "サイトキーとシークレットキーにテスト用の値を入力することでプレビューを確認できるで。\n詳細は下記ページを確認してな。" + _error: + _requestFailed: + title: "CAPTCHAのリクエストに失敗してもうた" + text: "しばらく後で実行するか、設定をもっかい確認してや。" + _verificationFailed: + title: "CAPTCHAのリクエストに失敗してもうた" + text: "設定がほんまに合ってるかもっかい確認してや。" + _unknown: + title: "CAPTCHAエラー" + text: "思いもせんかったエラーが起きたわ。" +_bootErrors: + title: "読み込みに失敗したで" + serverError: "少し待ってからリロードしてもまだ問題が解決されんのやったら、以下のError IDを添えてサーバー管理者に連絡して。" + solution: "以下のことやったら解決するかもやで。" + solution1: "ブラウザとかOSを最新バージョンに更新する" + solution2: "アドブロッカーを無効にする" + solution3: "ブラウザのキャッシュをクリアする" + solution4: "(Tor Browser) dom.webaudio.enabledをtrueに設定する" + otherOption: "ほかのオプション" + otherOption1: "クライアント設定とキャッシュをほかす" + otherOption2: "簡易クライアントを起動" + otherOption3: "修復ツールを起動" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 36b818c117..d956b37934 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -2822,8 +2822,6 @@ _remoteLookupErrors: _responseInvalid: title: "유효하지 않은 반응입니다." description: "이 서버와 통신할 수 있지만, 데이터가 올바르지 않습니다." - _responseInvalidIdHostNotMatch: - description: "입력된 URI과 실제 URI가 다릅니다. 제 3자 서버를 통한 리모트 컨텐츠를 조회하는 경우, 원래 서버 측에서 받아올 수 있는 URI를 사용하여 조회하시길 바랍니다." _noSuchObject: title: "찾을 수 없습니다" description: "요구된 리소스를 찾을 수 없습니다. URI를 다시 한 번 확인해보세요." @@ -2840,3 +2838,6 @@ _captcha: _unknown: title: "CAPTCHA 에러" text: "알 수 없는 에러가 발생했습니다." +_bootErrors: + title: "로딩이 실패함" + solution4: "(Tor Browser) dom.webaudio.enabled를 true로 설정하세요" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index d691022d75..cc05e33703 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -2754,8 +2754,6 @@ _remoteLookupErrors: _responseInvalid: title: "Resposta inválida" description: "Foi possível comunicar com o servidor, porém os dados obtidos foram incorretos." - _responseInvalidIdHostNotMatch: - description: "O domínio do endereço inserido difere do domínio do endereço final. Se você estiver pesquisando por um servidor de terceiros, tente buscar novamente com um endereço que pode ser obtido através do servidor original." _noSuchObject: title: "Não encontrado" description: "O recurso solicitado não foi encontrado, confira o endereço." diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index f4df425af4..5fec7353dc 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1309,6 +1309,8 @@ availableRoles: "可用角色" acknowledgeNotesAndEnable: "理解注意事项后再开启。" federationSpecified: "此服务器已开启联合白名单。只能与管理员指定的服务器通信。" federationDisabled: "此服务器已禁用联合。无法与其它服务器上的用户通信。" +confirmOnReact: "发送回应前需要确认" +reactAreYouSure: "要用「{emoji}」进行回应吗?" _accountSettings: requireSigninToViewContents: "需要登录才能显示内容" requireSigninToViewContentsDescription1: "您发布的所有帖子将变成需要登入后才会显示。有望防止爬虫收集各种信息。" @@ -2440,6 +2442,8 @@ _notification: flushNotification: "重置通知历史" exportOfXCompleted: "已完成 {x} 的导出" login: "有新的登录" + createToken: "访问令牌已创建" + createTokenDescription: "如果不明白其用途,请遵循「{text}」的指示删除访问令牌。" _types: all: "全部" note: "用户的新帖子" @@ -2777,8 +2781,8 @@ _customEmojisManager: _register: uploadSettingTitle: "上传设置" uploadSettingDescription: "可以在此页面设置上传表情符号时的行为。" - directoryToCategoryLabel: "目录名请输入「category」" - directoryToCategoryCaption: "拖放目录时,目录名请输入「category」" + directoryToCategoryLabel: "将目录名设为「category」" + directoryToCategoryCaption: "拖放目录时,将目录名设置为「category」" emojiInputAreaCaption: "请使用其中一种方法选择要注册的表情符号。" emojiInputAreaList1: "在此区域内拖放图像文件或者目录" emojiInputAreaList2: "单击此链接以从电脑中选择" @@ -2822,8 +2826,6 @@ _remoteLookupErrors: _responseInvalid: title: "响应无效" description: "成功与此服务器通信,但返回的数据无效。" - _responseInvalidIdHostNotMatch: - description: "输入 URI 的域名和最终取得的 URI 的域名不同。如果是通过第三方服务器获取远程内容,请使用可以从原始服务器获取内容的 URI 再试一次。" _noSuchObject: title: "未找到" description: "未找到请求的资源。请再次检查 URI。" @@ -2840,3 +2842,15 @@ _captcha: _unknown: title: "CAPTCHA 错误" text: "发生意外错误。" +_bootErrors: + title: "加载失败" + serverError: "请稍等片刻再重试。若问题仍无法解决,请将以下 Error ID 一起发送给管理员。" + solution: "以下方法或许可以解决问题:" + solution1: "将浏览器及操作系统更新到最新版本" + solution2: "禁用广告屏蔽插件" + solution3: "清除浏览器缓存" + solution4: "(Tor Browser)将 dom.webaudio.enabled 设定为 true" + otherOption: "其它选项" + otherOption1: "清除客户端设定与缓存" + otherOption2: "使用简易客户端" + otherOption3: "启动修复工具" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 466e3cc1d8..23b55d8da4 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -368,7 +368,7 @@ normal: "正常" instanceName: "伺服器名稱" instanceDescription: "伺服器介紹" maintainerName: "管理員名稱" -maintainerEmail: "管理員郵箱" +maintainerEmail: "管理員信箱" tosUrl: "服務條款 URL" thisYear: "本年" thisMonth: "本月" @@ -464,7 +464,7 @@ securityKey: "安全金鑰" lastUsed: "上次使用" lastUsedAt: "上次使用:{t}" unregister: "註銷" -passwordLessLogin: "設置無密碼登入" +passwordLessLogin: "無密碼登入" passwordLessLoginDescription: "不使用密碼,以安全金鑰或 Passkey 登入" resetPassword: "重設密碼" newPasswordIs: "新密碼為「{password}」" @@ -521,7 +521,7 @@ menuStyle: "選單風格" style: "風格" drawer: "側邊欄" popup: "彈出式視窗" -showNoteActionsOnlyHover: "僅在游標停留時顯示貼文的" +showNoteActionsOnlyHover: "僅於游標懸停時顯示貼文選項" showReactionsCount: "顯示貼文的反應數目" noHistory: "沒有歷史紀錄" signinHistory: "登入歷史" @@ -558,12 +558,12 @@ useObjectStorage: "使用物件儲存" objectStorageBaseUrl: "Base URL" objectStorageBaseUrlDesc: "用於引用的 URL。如果您使用的是 CDN 或反向代理,請指定其 URL,例如 S3(https://.s3.amazonaws.com)、GCS(https://storage.googleapis.com/)。" objectStorageBucket: "儲存空間(Bucket)" -objectStorageBucketDesc: "請填寫所用服務的儲存空間(Bucket)名稱。 " +objectStorageBucketDesc: "請填寫所用服務的儲存桶(Bucket)名稱。 " objectStoragePrefix: "前綴" objectStoragePrefixDesc: "它儲存在此前綴目錄下。" objectStorageEndpoint: "端點(Endpoint)" objectStorageEndpointDesc: "如使用 AWS S3,請留空。如使用其他服務,請按照其說明文件以「」或「:」的形式設定端點(Endpoint)。" -objectStorageRegion: "地域(Region)" +objectStorageRegion: "區域(Region)" objectStorageRegionDesc: "請填寫一個分區,例如「xx-east-1」。 如果您使用的服務不設分區,請留空或填寫「us-east-1」。" objectStorageUseSSL: "使用 SSL" objectStorageUseSSLDesc: "請在不使用 https 連接 API 時關閉" @@ -586,7 +586,7 @@ popout: "彈出式視窗" volume: "音量" masterVolume: "主音量" notUseSound: "關閉音效" -useSoundOnlyWhenActive: "瀏覽器在前景運作時,Misskey 才會發出音效" +useSoundOnlyWhenActive: "僅在 Misskey 於前景運作時發出音效" details: "詳細資訊" renoteDetails: "轉發貼文的細節" chooseEmoji: "選擇您的表情符號" @@ -681,7 +681,7 @@ smtpHost: "主機" smtpPort: "埠" smtpUser: "使用者名稱" smtpPass: "密碼" -emptyToDisableSmtpAuth: "留空使用者名稱和密碼以關閉SMTP驗證。" +emptyToDisableSmtpAuth: "將使用者名稱和密碼留空以關閉 SMTP 驗證。" smtpSecure: "在 SMTP 連接中使用隱式 SSL/TLS" smtpSecureInfo: "使用 STARTTLS 時關閉。" testEmail: "測試郵件發送" @@ -711,7 +711,7 @@ useGlobalSetting: "使用全域設定" useGlobalSettingDesc: "啟用時,將使用帳戶通知設定。停用時,則可以單獨設定。" other: "其他" regenerateLoginToken: "重新產生登入權杖" -regenerateLoginTokenDescription: "重新產生用於登入的內部權杖。一般情況下是不需要這樣做的。重新產生後,所有裝置將會被登出。" +regenerateLoginTokenDescription: "重新產生用於登入的內部權杖。通常不需要使用此功能。重新產生後,所有裝置都將被登出。" theKeywordWhenSearchingForCustomEmoji: "這是搜尋自訂表情符號時的關鍵字" setMultipleBySeparatingWithSpace: "您可以使用空格分隔多個項目。" fileIdOrUrl: "檔案 ID 或 URL" @@ -745,7 +745,7 @@ unclip: "解除摘錄" confirmToUnclipAlreadyClippedNote: "此貼文已包含在摘錄「{name}」中。 你想將貼文從這個摘錄中排除嗎?" public: "公開" private: "私密" -i18nInfo: "Misskey 已被志願者們翻譯成各種語言版本。您可以瀏覽 {link} 幫助翻譯。" +i18nInfo: "Misskey 已被志願者們翻譯成各種語言版本。您可以前往 {link} 以協助翻譯。" manageAccessTokens: "管理存取權杖" accountInfo: "帳戶資訊" notesCount: "貼文數量" @@ -781,7 +781,7 @@ useSystemFont: "使用系統預設的字型" clips: "摘錄" experimentalFeatures: "實驗中的功能" experimental: "實驗性" -thisIsExperimentalFeature: "這是實驗性的功能。可能會有變更規格和不能正常動作的可能性。" +thisIsExperimentalFeature: "這是一項實驗性功能,其行為會隨需要進行調整,也可能無法正常運作。" developer: "開發者" makeExplorable: "使自己的帳戶更容易被找到" makeExplorableDescription: "如果關閉,帳戶將不會被顯示在「探索」頁面中。" @@ -1207,7 +1207,7 @@ notificationRecieveConfig: "接受通知的設定" mutualFollow: "互相追隨" followingOrFollower: "追隨中或者追隨者" fileAttachedOnly: "只顯示包含附件的貼文" -showRepliesToOthersInTimeline: "顯示給其他人的回覆" +showRepliesToOthersInTimeline: "在時間軸上顯示給其他人的回覆" hideRepliesToOthersInTimeline: "在時間軸上隱藏給其他人的回覆" showRepliesToOthersInTimelineAll: "在時間軸包含追隨中所有人的回覆" hideRepliesToOthersInTimelineAll: "在時間軸不包含追隨中所有人的回覆" @@ -1247,7 +1247,7 @@ reloadRequiredToApplySettings: "需要重新載入頁面設定才能生效。" remainingN: "剩餘:{n}" overwriteContentConfirm: "確定要覆蓋目前的內容嗎?" seasonalScreenEffect: "隨季節變換畫面的呈現" -decorate: "設置頭像裝飾" +decorate: "裝飾" addMfmFunction: "插入 MFM 功能語法" enableQuickAddMfmFunction: "顯示進階 MFM 選擇器" bubbleGame: "氣泡遊戲" @@ -1274,7 +1274,7 @@ useBackupCode: "使用備用驗證碼" launchApp: "啟動 APP" useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊" keepOriginalFilename: "保留原始檔名" -keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。" +keepOriginalFilenameDescription: "如果關閉此設定,上傳時檔案名稱會自動替換為隨機字串。" noDescription: "沒有說明文字" alwaysConfirmFollow: "追隨時總是確認" inquiry: "聯絡我們" @@ -1309,6 +1309,8 @@ availableRoles: "可用角色" acknowledgeNotesAndEnable: "了解注意事項後再開啟。" federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。" federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。" +confirmOnReact: "反應時確認" +reactAreYouSure: "用「 {emoji} 」反應嗎?" _accountSettings: requireSigninToViewContents: "須登入以顯示內容" requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。" @@ -1433,7 +1435,7 @@ _initialTutorial: useCases: "伺服器的服務條款可能會規範特定的貼文需要使用隱藏內容,除此之外也會用在隱藏劇情洩漏與敏感內容的貼文。" _howToMakeAttachmentsSensitive: title: "如何標記上傳附件為敏感內容?" - description: "如果伺服器服務條款有規範,又或者不希望上傳附件直接被看見,可以設置為「敏感內容」" + description: "如果伺服器的服務條款有規範,又或者不適合直接展示的附件,請記得加上「敏感」標記。" tryThisFile: "試試看!把附加在發文表單的圖像檔案標記為敏感內容。" _exampleNote: note: "打開納豆的包裝失敗了…" @@ -1467,7 +1469,7 @@ _serverSettings: inquiryUrlDescription: "指定伺服器運營者的聯絡表單網址,或包含運營者聯絡資訊網頁的網址。" openRegistration: "允許建立帳戶" openRegistrationWarning: "開放註冊伴隨著風險。 建議只有在伺服器受到持續監控,並準備好在出現問題時能立即處理的情況下才開放註冊。" - thisSettingWillAutomaticallyOffWhenModeratorsInactive: "為了防止 spam,如果一段期間內沒有偵測到審查員的活動,此設定將自動關閉。" + thisSettingWillAutomaticallyOffWhenModeratorsInactive: "如果在一段期間內沒有偵測到任何審查員活動,此設定將自動關閉,以防止垃圾內容。" _accountMigration: moveFrom: "從其他帳戶遷移到這個帳戶" moveFromSub: "為另一個帳戶建立別名" @@ -1481,7 +1483,7 @@ _accountMigration: startMigration: "遷移" migrationConfirm: "確定要將這個帳戶遷移至 {account} 嗎?一旦遷移就無法撤銷,也就無法以原來的狀態使用這個帳戶。\n另外,請確認在要遷移到的帳戶已經建立了一個別名。" movedAndCannotBeUndone: "帳戶已遷移。\n遷移無法撤消。" - postMigrationNote: "將在完成遷移後的 24 小時取消追隨所有帳號。\n此帳戶的追隨中/追隨者人數將歸零。由於不會解除粉絲對您的追隨,因此他們仍然可以繼續閱覽此帳戶僅對追隨者公開的貼文。" + postMigrationNote: "將在完成遷移的 24 小時後取消追隨所有帳號。\n此帳戶的追隨中/追隨者人數將歸零。由於不會解除粉絲對您的追隨,因此他們仍然可以繼續閱覽此帳戶內僅對追隨者公開的貼文。" movedTo: "要遷移到的帳戶:" _achievements: earnedAt: "獲得日期" @@ -1798,7 +1800,7 @@ _role: canHideAds: "不顯示廣告" canSearchNotes: "可否搜尋貼文" canUseTranslator: "使用翻譯功能" - avatarDecorationLimit: "頭像裝飾的最大設置量" + avatarDecorationLimit: "頭像可掛上的最大裝飾數量" canImportAntennas: "允許匯入天線" canImportBlocking: "允許匯入封鎖名單" canImportFollowing: "允許匯入追隨名單" @@ -1957,7 +1959,7 @@ _instanceMute: instanceMuteDescription: "包括對被靜音伺服器上的使用者的回覆,被設定的伺服器上所有貼文及轉發都會被靜音。" instanceMuteDescription2: "設定時以換行進行分隔" title: "將隱藏被設定的伺服器貼文。" - heading: "將伺服器靜音" + heading: "要靜音的伺服器" _theme: explore: "探索佈景主題" install: "安裝佈景主題" @@ -2408,7 +2410,7 @@ _pages: note: "嵌式貼文" _note: id: "貼文ID" - idDescription: "您也可以粘貼筆記 URL 並進行設置。 " + idDescription: "您也可以貼上貼文 URL 來進行設定。 " detailed: "顯示詳細內容" _relayStatus: requesting: "等待核准" @@ -2440,6 +2442,8 @@ _notification: flushNotification: "重置通知歷史紀錄" exportOfXCompleted: "{x} 的匯出已完成。" login: "已登入" + createToken: "已產生存取權杖" + createTokenDescription: "如果您不知道,請透過「{text}」刪除存取權杖。" _types: all: "全部 " note: "使用者的最新貼文" @@ -2655,7 +2659,7 @@ _dataSaver: _hemisphere: N: "北半球" S: "南半球" - caption: "在某些客戶端的設定中,用於判斷季節。" + caption: "某些客戶端的設定會用此來判斷季節。" _reversi: reversi: "黑白棋" gameSettings: "對弈設定" @@ -2822,8 +2826,6 @@ _remoteLookupErrors: _responseInvalid: title: "回應不正確" description: "雖然能夠與這個伺服器通訊,但是取得的資料不正確。" - _responseInvalidIdHostNotMatch: - description: "輸入的 URI 的網域與最終取得的 URI 的網域不同。 如果您是透過第三方伺服器查詢遠端內容,請使用可在原始伺服器上取得的 URI 再次查詢。" _noSuchObject: title: "查無項目" description: "無法找到所要求的資源,請再次檢查 URI。" @@ -2840,3 +2842,15 @@ _captcha: _unknown: title: "CAPTCHA 錯誤" text: "發生了意外的錯誤。" +_bootErrors: + title: "載入失敗" + serverError: "如果稍等片刻並重新載入後問題仍然存在,請聯絡您的伺服器管理員並提供以下的錯誤 ID。" + solution: "執行以下操作或許可以解決問題。" + solution1: "將瀏覽器和作業系統更新至最新版本" + solution2: "停用廣告攔截器" + solution3: "清除瀏覽器的快取" + solution4: "(Tor 瀏覽器)將 dom.webaudio.enabled 設為 true" + otherOption: "其他選項" + otherOption1: "刪除用戶端設定和快取" + otherOption2: "啟動簡易用戶端" + otherOption3: "啟動修復工具" From 28b40691d5e26571d0cd52a98c60195534cc4407 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: Wed, 26 Feb 2025 15:51:28 +0900 Subject: [PATCH 011/649] =?UTF-8?q?fix(frontend):=20=E3=83=AA=E3=83=8E?= =?UTF-8?q?=E3=83=BC=E3=83=88=E7=B5=8C=E7=94=B1=E3=81=A7=E3=83=8E=E3=83=BC?= =?UTF-8?q?=E3=83=88=E3=81=AE=E8=A9=B3=E7=B4=B0=E6=83=85=E5=A0=B1=E3=82=92?= =?UTF-8?q?=E8=A6=8B=E3=82=8B=E3=81=A8=E3=81=8D=E3=80=81=E3=82=AF=E3=83=AA?= =?UTF-8?q?=E3=83=83=E3=83=97=E4=B8=80=E8=A6=A7=E3=81=8CappearNote?= =?UTF-8?q?=E3=81=AE=E3=82=82=E3=81=AE=E3=81=AB=E3=81=AA=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#15417)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): リノート経由でノートの詳細情報を見るとき、クリップ一覧がappearNoteのものになるように * Update Changelog --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/frontend/src/components/MkNoteDetailed.vue | 2 +- packages/frontend/src/components/MkRemoteCaution.vue | 4 ++-- packages/frontend/src/pages/note.vue | 8 +++++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db29385d73..d51369f4bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - Enhance: ノートに埋め込まれたメディアのコンテキストメニューから管理者用のファイル管理画面を開けるように ( #15440 ) - Enhance: リアクションする際に確認ダイアログを表示できるように - Enhance: CWの注釈で入力済みの文字数を表示 +- Fix: ノートページで、クリップ一覧が表示されないことがある問題を修正 - Fix: コンディショナルロールを手動で割り当てできる導線を削除 `#13529` - Fix: 埋め込みプレイヤーから外部ページに移動できない問題を修正 - Fix: Play の再読込時に UI が以前の状態を引き継いでしまう問題を修正 `#14378` diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 835a663868..d5bd4ad133 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -257,7 +257,7 @@ import type { Keymap } from '@/scripts/hotkey.js'; const props = withDefaults(defineProps<{ note: Misskey.entities.Note; - initialTab: string; + initialTab?: string; }>(), { initialTab: 'replies', }); diff --git a/packages/frontend/src/components/MkRemoteCaution.vue b/packages/frontend/src/components/MkRemoteCaution.vue index a56a4b1671..2d3b7d107d 100644 --- a/packages/frontend/src/components/MkRemoteCaution.vue +++ b/packages/frontend/src/components/MkRemoteCaution.vue @@ -4,14 +4,14 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/pages/note.vue b/packages/frontend/src/pages/note.vue index e6b4a0b222..0791c1343b 100644 --- a/packages/frontend/src/pages/note.vue +++ b/packages/frontend/src/pages/note.vue @@ -63,6 +63,7 @@ import { dateString } from '@/filters/date.js'; import MkClipPreview from '@/components/MkClipPreview.vue'; import { defaultStore } from '@/store.js'; import { pleaseLogin } from '@/scripts/please-login.js'; +import { getAppearNote } from '@/scripts/get-appear-note.js'; import { serverContext, assertServerContext } from '@/server-context.js'; import { $i } from '@/account.js'; @@ -132,10 +133,11 @@ function fetchNote() { noteId: props.noteId, }).then(res => { note.value = res; + const appearNote = getAppearNote(res); // 古いノートは被クリップ数をカウントしていないので、2023-10-01以前のものは強制的にnotes/clipsを叩く - if (note.value.clippedCount > 0 || new Date(note.value.createdAt).getTime() < new Date('2023-10-01').getTime()) { + if ((appearNote.clippedCount ?? 0) > 0 || new Date(appearNote.createdAt).getTime() < new Date('2023-10-01').getTime()) { misskeyApi('notes/clips', { - noteId: note.value.id, + noteId: appearNote.id, }).then((_clips) => { clips.value = _clips; }); @@ -170,7 +172,7 @@ definePageMetadata(() => ({ avatar: note.value.user, path: `/notes/${note.value.id}`, share: { - title: i18n.tsx.noteOf({ user: note.value.user.name }), + title: i18n.tsx.noteOf({ user: note.value.user.name ?? note.value.user.username }), text: note.value.text, }, } : {}, From 15b0345335397ae6df8c85871793adab49343ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:28:35 +0900 Subject: [PATCH 012/649] =?UTF-8?q?enhance(frontend):=20=E3=82=B3=E3=83=B3?= =?UTF-8?q?=E3=83=88=E3=83=AD=E3=83=BC=E3=83=AB=E3=83=91=E3=83=8D=E3=83=AB?= =?UTF-8?q?=E3=81=AE=E3=83=A6=E3=83=BC=E3=82=B6=E6=A4=9C=E7=B4=A2=E3=81=A7?= =?UTF-8?q?=E5=85=A5=E5=8A=9B=E3=81=95=E3=82=8C=E3=81=9F=E6=83=85=E5=A0=B1?= =?UTF-8?q?=E3=82=92=E3=83=9A=E3=83=BC=E3=82=B8=E9=81=B7=E7=A7=BB=E3=81=A7?= =?UTF-8?q?=E6=90=8D=E3=81=AA=E3=82=8F=E3=81=AA=E3=81=84=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB=20(#15438)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): コントロールパネルのユーザ検索で入力された情報をページ遷移で損なわないように * sessionStorageよりも更に短命な方法で持つように変更 * add comment --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 1 + packages/frontend/src/account.ts | 5 +- packages/frontend/src/memory-storage.ts | 57 +++++++++++++++++++++ packages/frontend/src/pages/admin/users.vue | 46 ++++++++++++++--- 4 files changed, 101 insertions(+), 8 deletions(-) create mode 100644 packages/frontend/src/memory-storage.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d51369f4bb..940a4309bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - Enhance: 開発者モードでメニューからファイルIDをコピー出来るように `#15441' - Enhance: ノートに埋め込まれたメディアのコンテキストメニューから管理者用のファイル管理画面を開けるように ( #15440 ) - Enhance: リアクションする際に確認ダイアログを表示できるように +- Enhance: コントロールパネルのユーザ検索で入力された情報をページ遷移で損なわないように `#15437` - Enhance: CWの注釈で入力済みの文字数を表示 - Fix: ノートページで、クリップ一覧が表示されないことがある問題を修正 - Fix: コンディショナルロールを手動で割り当てできる導線を削除 `#13529` diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 9006150bc8..17d690cd3a 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -7,6 +7,7 @@ import { defineAsyncComponent, reactive, ref } from 'vue'; import * as Misskey from 'misskey-js'; import { apiUrl } from '@@/js/config.js'; import type { MenuItem, MenuButton } from '@/types/menu.js'; +import { defaultMemoryStorage } from '@/memory-storage'; import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js'; import { i18n } from '@/i18n.js'; import { miLocalStorage } from '@/local-storage.js'; @@ -40,6 +41,8 @@ export function incNotesCount() { export async function signout() { if (!$i) return; + defaultMemoryStorage.clear(); + waiting(); document.cookie.split(';').forEach((cookie) => { const cookieName = cookie.split('=')[0].trim(); @@ -107,7 +110,7 @@ export async function removeAccount(idOrToken: Account['id']) { } function fetchAccount(token: string, id?: string, forceShowDialog?: boolean): Promise { - document.cookie = "token=; path=/; max-age=0"; + document.cookie = 'token=; path=/; max-age=0'; document.cookie = `token=${token}; path=/queue; max-age=86400; SameSite=Strict; Secure`; // bull dashboardの認証とかで使う return new Promise((done, fail) => { diff --git a/packages/frontend/src/memory-storage.ts b/packages/frontend/src/memory-storage.ts new file mode 100644 index 0000000000..df0dc1308f --- /dev/null +++ b/packages/frontend/src/memory-storage.ts @@ -0,0 +1,57 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export type MemoryStorage = { + has: (key: string) => boolean; + getItem: (key: string) => T | null; + setItem: (key: string, value: unknown) => void; + removeItem: (key: string) => void; + clear: () => void; + size: number; +}; + +class MemoryStorageImpl implements MemoryStorage { + private readonly storage: Map; + + constructor() { + this.storage = new Map(); + } + + has(key: string): boolean { + return this.storage.has(key); + } + + getItem(key: string): T | null { + return this.storage.has(key) ? this.storage.get(key) as T : null; + } + + setItem(key: string, value: unknown): void { + this.storage.set(key, value); + } + + removeItem(key: string): void { + this.storage.delete(key); + } + + clear(): void { + this.storage.clear(); + } + + get size(): number { + return this.storage.size; + } +} + +export function createMemoryStorage(): MemoryStorage { + return new MemoryStorageImpl(); +} + +/** + * SessionStorageよりも更に短い期間でクリアされるストレージです + * - ブラウザの再読み込みやタブの閉じると内容が揮発します + * - このストレージは他のタブと共有されません + * - アカウント切り替えやログアウトを行うと内容が揮発します + */ +export const defaultMemoryStorage: MemoryStorage = createMemoryStorage(); diff --git a/packages/frontend/src/pages/admin/users.vue b/packages/frontend/src/pages/admin/users.vue index 870c3ce88b..91104b676d 100644 --- a/packages/frontend/src/pages/admin/users.vue +++ b/packages/frontend/src/pages/admin/users.vue @@ -9,6 +9,9 @@ SPDX-License-Identifier: AGPL-3.0-only
+
+ {{ i18n.ts.reset }} +
@@ -57,8 +60,10 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/search.user.vue b/packages/frontend/src/pages/search.user.vue index e8bc4cd6d3..2b8faf5465 100644 --- a/packages/frontend/src/pages/search.user.vue +++ b/packages/frontend/src/pages/search.user.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only - +
@@ -49,14 +49,16 @@ const props = withDefaults(defineProps<{ const router = useRouter(); -const key = ref(''); +const key = ref(0); +const userPagination = ref>(); + const searchQuery = ref(toRef(props, 'query').value); const searchOrigin = ref(toRef(props, 'origin').value); -const userPagination = ref(); async function search() { const query = searchQuery.value.toString().trim(); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (query == null || query === '') return; //#region AP lookup @@ -76,6 +78,7 @@ async function search() { if (res.type === 'User') { router.push(`/@${res.object.username}@${res.object.host}`); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition } else if (res.type === 'Note') { router.push(`/notes/${res.object.id}`); } @@ -118,6 +121,6 @@ async function search() { }, }; - key.value = query; + key.value++; } diff --git a/packages/frontend/src/scripts/gen-search-query.ts b/packages/frontend/src/scripts/gen-search-query.ts deleted file mode 100644 index a85ee01e26..0000000000 --- a/packages/frontend/src/scripts/gen-search-query.ts +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import * as Misskey from 'misskey-js'; -import { host as localHost } from '@@/js/config.js'; - -export async function genSearchQuery(v: any, q: string) { - let host: string; - let userId: string; - if (q.split(' ').some(x => x.startsWith('@'))) { - for (const at of q.split(' ').filter(x => x.startsWith('@')).map(x => x.substring(1))) { - if (at.includes('.')) { - if (at === localHost || at === '.') { - host = null; - } else { - host = at; - } - } else { - const user = await v.api('users/show', Misskey.acct.parse(at)).catch(x => null); - if (user) { - userId = user.id; - } else { - // todo: show error - } - } - } - } - return { - query: q.split(' ').filter(x => !x.startsWith('/') && !x.startsWith('@')).join(' '), - host: host, - userId: userId, - }; -} From cc09de7b27bcc3ce1145171086e65e4dcf7cacbf Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 27 Feb 2025 16:13:37 +0900 Subject: [PATCH 016/649] New Crowdin updates (#15560) * New translations ja-jp.yml (Russian) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Portuguese) * New translations ja-jp.yml (Turkish) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Japanese, Kansai) * New translations ja-jp.yml (Romanian) * New translations ja-jp.yml (French) * New translations ja-jp.yml (Spanish) * New translations ja-jp.yml (Arabic) * New translations ja-jp.yml (Czech) * New translations ja-jp.yml (German) * New translations ja-jp.yml (Greek) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Dutch) * New translations ja-jp.yml (Norwegian) * New translations ja-jp.yml (Polish) * New translations ja-jp.yml (Slovak) * New translations ja-jp.yml (Swedish) * New translations ja-jp.yml (Ukrainian) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Vietnamese) * New translations ja-jp.yml (Indonesian) * New translations ja-jp.yml (Bengali) * New translations ja-jp.yml (Thai) * New translations ja-jp.yml (Uzbek) * New translations ja-jp.yml (Lao) * New translations ja-jp.yml (Korean (Gyeongsang)) * New translations ja-jp.yml (Catalan) --- locales/ar-SA.yml | 4 ++++ locales/bn-BD.yml | 3 +++ locales/ca-ES.yml | 8 ++++++++ locales/cs-CZ.yml | 4 ++++ locales/de-DE.yml | 4 ++++ locales/el-GR.yml | 2 ++ locales/en-US.yml | 4 ++++ locales/es-ES.yml | 4 ++++ locales/fr-FR.yml | 4 ++++ locales/id-ID.yml | 4 ++++ locales/it-IT.yml | 4 ++++ locales/ja-KS.yml | 4 ++++ locales/ko-GS.yml | 3 +++ locales/ko-KR.yml | 4 ++++ locales/lo-LA.yml | 2 ++ locales/nl-NL.yml | 2 ++ locales/no-NO.yml | 2 ++ locales/pl-PL.yml | 3 +++ locales/pt-PT.yml | 4 ++++ locales/ro-RO.yml | 2 ++ locales/ru-RU.yml | 4 ++++ locales/sk-SK.yml | 3 +++ locales/sv-SE.yml | 2 ++ locales/th-TH.yml | 4 ++++ locales/tr-TR.yml | 2 ++ locales/uk-UA.yml | 3 +++ locales/uz-UZ.yml | 3 +++ locales/vi-VN.yml | 4 ++++ locales/zh-CN.yml | 4 ++++ locales/zh-TW.yml | 4 ++++ 30 files changed, 104 insertions(+) diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 91c90ce75a..1a3eeaead3 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -1584,3 +1584,7 @@ _offlineScreen: _remoteLookupErrors: _noSuchObject: title: "غير موجود" +_search: + searchScopeAll: "الكل" + searchScopeLocal: "المحلي" + searchScopeUser: "مستخدم محدد" diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 709874ac20..d9a58ce824 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -1348,3 +1348,6 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "পাওয়া যায়নি" +_search: + searchScopeAll: "সবগুলো" + searchScopeLocal: "স্থানীয়" diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index d12da0676f..a42ebb0a5a 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -2854,3 +2854,11 @@ _bootErrors: otherOption1: "Esborrar la configuració i la memòria cau del client" otherOption2: "Iniciar client senzill" otherOption3: "Iniciar l'eina de reparació " +_search: + searchScopeAll: "Tot" + searchScopeLocal: "Local" + searchScopeServer: "Instància " + searchScopeUser: "Especificar usuari" + pleaseEnterServerHost: "Introdueix l'adreça de la instància " + pleaseSelectUser: "Selecciona un usuari" + serverHostPlaceholder: "Ex: misskey.example.com" diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index afa3047c1d..fea8902ab8 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -2024,3 +2024,7 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Nenalezeno" +_search: + searchScopeAll: "Vše" + searchScopeLocal: "Místní" + searchScopeUser: "Upřesnit uživatele" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index d9072683cb..30f8574594 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -2614,3 +2614,7 @@ _remoteLookupErrors: _noSuchObject: title: "Nicht gefunden" description: "Die angeforderte Ressource konnte nicht gefunden werden, bitte überprüfe die URI erneut." +_search: + searchScopeAll: "Alle" + searchScopeLocal: "Lokal" + searchScopeUser: "Spezifischer Benutzer" diff --git a/locales/el-GR.yml b/locales/el-GR.yml index 4657842ca5..272ec07d89 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -397,3 +397,5 @@ _moderationLogTypes: suspend: "Αποβολή" _reversi: total: "Σύνολο" +_search: + searchScopeLocal: "Τοπικό" diff --git a/locales/en-US.yml b/locales/en-US.yml index fe4bbef391..04ddd2966a 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -2854,3 +2854,7 @@ _bootErrors: otherOption1: "Delete client settings and cache" otherOption2: "Start the simple client" otherOption3: "Launch the repair tool" +_search: + searchScopeAll: "All" + searchScopeLocal: "Local" + searchScopeUser: "Specific user" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 05d5e8c4c7..070bc397cb 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -2589,3 +2589,7 @@ _followRequest: _remoteLookupErrors: _noSuchObject: title: "No se encuentra" +_search: + searchScopeAll: "Todo" + searchScopeLocal: "Local" + searchScopeUser: "Especificar usuario" diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index ccfd462a76..09a4d4bc84 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -2364,3 +2364,7 @@ _embedCodeGen: _remoteLookupErrors: _noSuchObject: title: "Non trouvé" +_search: + searchScopeAll: "Tous" + searchScopeLocal: "Local" + searchScopeUser: "Spécifier l'utilisateur·rice" diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 7be56b1494..75e420aac7 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -2610,3 +2610,7 @@ _mediaControls: _remoteLookupErrors: _noSuchObject: title: "Tidak dapat ditemukan" +_search: + searchScopeAll: "Semua" + searchScopeLocal: "Lokal" + searchScopeUser: "Pengguna spesifik" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 66cdd5af76..eaf9e81b0e 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -2854,3 +2854,7 @@ _bootErrors: otherOption1: "Nelle impostazioni, cancellare le impostazioni del client e svuotare la cache" otherOption2: "Avviare il client predefinito" otherOption3: "Avviare lo strumento di riparazione" +_search: + searchScopeAll: "Tutte" + searchScopeLocal: "Locale" + searchScopeUser: "Profilo specifico" diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index e5d0f153a6..f00eb6a6e3 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -2854,3 +2854,7 @@ _bootErrors: otherOption1: "クライアント設定とキャッシュをほかす" otherOption2: "簡易クライアントを起動" otherOption3: "修復ツールを起動" +_search: + searchScopeAll: "みんな" + searchScopeLocal: "ローカル" + searchScopeUser: "ユーザー指定" diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml index 4b9650b636..ce83ef0e07 100644 --- a/locales/ko-GS.yml +++ b/locales/ko-GS.yml @@ -843,3 +843,6 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "몬 찾앗십니다" +_search: + searchScopeAll: "말캉" + searchScopeUser: "사용자 지정" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index d956b37934..82b42ec2be 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -2841,3 +2841,7 @@ _captcha: _bootErrors: title: "로딩이 실패함" solution4: "(Tor Browser) dom.webaudio.enabled를 true로 설정하세요" +_search: + searchScopeAll: "전체" + searchScopeLocal: "로컬" + searchScopeUser: "사용자 지정" diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 2d55c289aa..06acda44be 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -477,3 +477,5 @@ _moderationLogTypes: _remoteLookupErrors: _noSuchObject: title: "ບໍ່ພົບ" +_search: + searchScopeAll: "ທັງໝົດ" diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index 685094b4a5..320b9d62ba 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -540,3 +540,5 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Niet gevonden" +_search: + searchScopeAll: "Alle" diff --git a/locales/no-NO.yml b/locales/no-NO.yml index 474e05ba67..c1b145cab4 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -730,3 +730,5 @@ _moderationLogTypes: _remoteLookupErrors: _noSuchObject: title: "Ikke funnet" +_search: + searchScopeAll: "Alle" diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index 9bd585de86..13f3b118fe 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -1583,3 +1583,6 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Nie znaleziono" +_search: + searchScopeAll: "Wszystkie" + searchScopeLocal: "Lokalne" diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index cc05e33703..8892e6574f 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -2757,3 +2757,7 @@ _remoteLookupErrors: _noSuchObject: title: "Não encontrado" description: "O recurso solicitado não foi encontrado, confira o endereço." +_search: + searchScopeAll: "Todos" + searchScopeLocal: "Local" + searchScopeUser: "Usuário específico" diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 07f4c98d96..0d43e174a7 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -736,3 +736,5 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Nu a fost găsit" +_search: + searchScopeAll: "Tot" diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 7ed41a9c47..5ba3bc8e87 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -2147,3 +2147,7 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Не найдено" +_search: + searchScopeAll: "Все" + searchScopeLocal: "Местная" + searchScopeUser: "Указанный пользователь" diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 521d172671..91de8a3352 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -1449,3 +1449,6 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Nenájdené" +_search: + searchScopeAll: "Všetko" + searchScopeLocal: "Lokálne" diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 5961605645..91413e3bc7 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -707,3 +707,5 @@ _reversi: white: "Vit" _selfXssPrevention: warning: "VARNING" +_search: + searchScopeAll: "Allt" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index ec83ba888c..b76c088b3f 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -2709,3 +2709,7 @@ _embedCodeGen: _remoteLookupErrors: _noSuchObject: title: "ไม่พบหน้าที่ต้องการ" +_search: + searchScopeAll: "ทั้งหมด" + searchScopeLocal: "ท้องถิ่น" + searchScopeUser: "ผู้ใช้เฉพาะ" diff --git a/locales/tr-TR.yml b/locales/tr-TR.yml index 2c63f15aa2..e99aa64254 100644 --- a/locales/tr-TR.yml +++ b/locales/tr-TR.yml @@ -460,3 +460,5 @@ _deck: _moderationLogTypes: suspend: "askıya al" resetPassword: "Şifre sıfırlama" +_search: + searchScopeAll: "Tümü" diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index a83ad80683..4f7e6430e9 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -1624,3 +1624,6 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Не знайдено" +_search: + searchScopeAll: "Всі" + searchScopeLocal: "Локальна" diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index 6015492b92..c70802e417 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -1094,3 +1094,6 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Topilmadi" +_search: + searchScopeAll: "Barcha" + searchScopeLocal: "Mahalliy" diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index e6a9418126..628bd513fe 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -1930,3 +1930,7 @@ _reversi: _remoteLookupErrors: _noSuchObject: title: "Không tìm thấy" +_search: + searchScopeAll: "Tất cả" + searchScopeLocal: "Máy chủ này" + searchScopeUser: "Người dùng chỉ định" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 5fec7353dc..1599db5854 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -2854,3 +2854,7 @@ _bootErrors: otherOption1: "清除客户端设定与缓存" otherOption2: "使用简易客户端" otherOption3: "启动修复工具" +_search: + searchScopeAll: "全部" + searchScopeLocal: "本地" + searchScopeUser: "用户指定" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 23b55d8da4..10079f2bee 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -2854,3 +2854,7 @@ _bootErrors: otherOption1: "刪除用戶端設定和快取" otherOption2: "啟動簡易用戶端" otherOption3: "啟動修復工具" +_search: + searchScopeAll: "全部" + searchScopeLocal: "本地" + searchScopeUser: "指定使用者" From 94a3e37ba86374b2a0c7d174a5eb67c971002f1e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Feb 2025 08:58:40 +0000 Subject: [PATCH 017/649] Release: 2025.2.1 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 43d4a01fb7..201b30ec36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.2.1-beta.2", + "version": "2025.2.1", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 06ea1c78ac..f9a61fd0b1 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.2.1-beta.2", + "version": "2025.2.1", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From a3bba23b7d6e0d3fde4943b95cc42afa3dcb35d4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 27 Feb 2025 08:58:46 +0000 Subject: [PATCH 018/649] [skip ci] Update CHANGELOG.md (prepend template) --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53cf1b0cca..f765ea48e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## Unreleased + +### General +- + +### Client +- + +### Server +- + + ## 2025.2.1 ### General From c63c3462dd00e7de3f40b15ad43993a26734263f Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 28 Feb 2025 09:34:21 +0900 Subject: [PATCH 019/649] refactor --- packages/backend/src/core/CreateSystemUserService.ts | 2 +- packages/backend/src/core/SignupService.ts | 4 ++-- packages/backend/src/misc/is-native-token.ts | 7 ------- .../src/misc/{generate-native-user-token.ts => token.ts} | 5 +++-- packages/backend/src/server/api/AuthenticateService.ts | 4 ++-- .../backend/src/server/api/endpoints/i/regenerate-token.ts | 4 ++-- 6 files changed, 10 insertions(+), 16 deletions(-) delete mode 100644 packages/backend/src/misc/is-native-token.ts rename packages/backend/src/misc/{generate-native-user-token.ts => token.ts} (54%) diff --git a/packages/backend/src/core/CreateSystemUserService.ts b/packages/backend/src/core/CreateSystemUserService.ts index 6c5b0f6a36..7ef75edb3c 100644 --- a/packages/backend/src/core/CreateSystemUserService.ts +++ b/packages/backend/src/core/CreateSystemUserService.ts @@ -14,7 +14,7 @@ import { IdService } from '@/core/IdService.js'; import { MiUserKeypair } from '@/models/UserKeypair.js'; import { MiUsedUsername } from '@/models/UsedUsername.js'; import { DI } from '@/di-symbols.js'; -import generateNativeUserToken from '@/misc/generate-native-user-token.js'; +import { generateNativeUserToken } from '@/misc/token.js'; import { bindThis } from '@/decorators.js'; @Injectable() diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts index 3865392b7f..d2f09ea15d 100644 --- a/packages/backend/src/core/SignupService.ts +++ b/packages/backend/src/core/SignupService.ts @@ -14,7 +14,7 @@ import { MiUserProfile } from '@/models/UserProfile.js'; import { IdService } from '@/core/IdService.js'; import { MiUserKeypair } from '@/models/UserKeypair.js'; import { MiUsedUsername } from '@/models/UsedUsername.js'; -import generateUserToken from '@/misc/generate-native-user-token.js'; +import { generateNativeUserToken } from '@/misc/token.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { InstanceActorService } from '@/core/InstanceActorService.js'; import { bindThis } from '@/decorators.js'; @@ -74,7 +74,7 @@ export class SignupService { } // Generate secret - const secret = generateUserToken(); + const secret = generateNativeUserToken(); // Check username duplication if (await this.usersRepository.exists({ where: { usernameLower: username.toLowerCase(), host: IsNull() } })) { diff --git a/packages/backend/src/misc/is-native-token.ts b/packages/backend/src/misc/is-native-token.ts deleted file mode 100644 index 300c4c05b3..0000000000 --- a/packages/backend/src/misc/is-native-token.ts +++ /dev/null @@ -1,7 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -// eslint-disable-next-line import/no-default-export -export default (token: string) => token.length === 16; diff --git a/packages/backend/src/misc/generate-native-user-token.ts b/packages/backend/src/misc/token.ts similarity index 54% rename from packages/backend/src/misc/generate-native-user-token.ts rename to packages/backend/src/misc/token.ts index 85fb383ba2..5d37cba26d 100644 --- a/packages/backend/src/misc/generate-native-user-token.ts +++ b/packages/backend/src/misc/token.ts @@ -5,5 +5,6 @@ import { secureRndstr } from '@/misc/secure-rndstr.js'; -// eslint-disable-next-line import/no-default-export -export default () => secureRndstr(16); +export const generateNativeUserToken = () => secureRndstr(16); + +export const isNativeUserToken = (token: string) => token.length === 16; diff --git a/packages/backend/src/server/api/AuthenticateService.ts b/packages/backend/src/server/api/AuthenticateService.ts index 690ff2e022..601618553e 100644 --- a/packages/backend/src/server/api/AuthenticateService.ts +++ b/packages/backend/src/server/api/AuthenticateService.ts @@ -11,7 +11,7 @@ import type { MiAccessToken } from '@/models/AccessToken.js'; import { MemoryKVCache } from '@/misc/cache.js'; import type { MiApp } from '@/models/App.js'; import { CacheService } from '@/core/CacheService.js'; -import isNativeToken from '@/misc/is-native-token.js'; +import { isNativeUserToken } from '@/misc/token.js'; import { bindThis } from '@/decorators.js'; export class AuthenticationError extends Error { @@ -46,7 +46,7 @@ export class AuthenticateService implements OnApplicationShutdown { return [null, null]; } - if (isNativeToken(token)) { + if (isNativeUserToken(token)) { const user = await this.cacheService.localUserByNativeTokenCache.fetch(token, () => this.usersRepository.findOneBy({ token }) as Promise); diff --git a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts index 78f3cce9ad..d25d5d5e0e 100644 --- a/packages/backend/src/server/api/endpoints/i/regenerate-token.ts +++ b/packages/backend/src/server/api/endpoints/i/regenerate-token.ts @@ -7,7 +7,7 @@ import bcrypt from 'bcryptjs'; import { Inject, Injectable } from '@nestjs/common'; import { Endpoint } from '@/server/api/endpoint-base.js'; import type { UsersRepository, UserProfilesRepository } from '@/models/_.js'; -import generateUserToken from '@/misc/generate-native-user-token.js'; +import { generateNativeUserToken } from '@/misc/token.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; @@ -49,7 +49,7 @@ export default class extends Endpoint { // eslint- throw new Error('incorrect password'); } - const newToken = generateUserToken(); + const newToken = generateNativeUserToken(); await this.usersRepository.update(me.id, { token: newToken, From 734c78ddd1eb1489c02a0667cbfe12030aeb3f16 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 13:07:36 +0900 Subject: [PATCH 020/649] chore(deps): update [tools] update dependencies (#15563) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- scripts/changelog-checker/package-lock.json | 342 ++++++++++---------- scripts/changelog-checker/package.json | 12 +- 2 files changed, 177 insertions(+), 177 deletions(-) diff --git a/scripts/changelog-checker/package-lock.json b/scripts/changelog-checker/package-lock.json index b7348a7fac..d017475fc8 100644 --- a/scripts/changelog-checker/package-lock.json +++ b/scripts/changelog-checker/package-lock.json @@ -9,16 +9,16 @@ "version": "1.0.0", "devDependencies": { "@types/mdast": "4.0.4", - "@types/node": "22.13.5", - "@vitest/coverage-v8": "3.0.6", + "@types/node": "22.13.7", + "@vitest/coverage-v8": "3.0.7", "mdast-util-to-string": "4.0.0", "remark": "15.0.1", "remark-parse": "11.0.0", - "typescript": "5.7.3", + "typescript": "5.8.2", "unified": "11.0.5", - "vite": "6.1.1", - "vite-node": "3.0.6", - "vitest": "3.0.6" + "vite": "6.2.0", + "vite-node": "3.0.7", + "vitest": "3.0.7" } }, "node_modules/@ampproject/remapping": { @@ -96,9 +96,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz", + "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==", "cpu": [ "ppc64" ], @@ -113,9 +113,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz", + "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==", "cpu": [ "arm" ], @@ -130,9 +130,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz", + "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==", "cpu": [ "arm64" ], @@ -147,9 +147,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz", + "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==", "cpu": [ "x64" ], @@ -164,9 +164,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz", + "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==", "cpu": [ "arm64" ], @@ -181,9 +181,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz", + "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==", "cpu": [ "x64" ], @@ -198,9 +198,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz", + "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==", "cpu": [ "arm64" ], @@ -215,9 +215,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz", + "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==", "cpu": [ "x64" ], @@ -232,9 +232,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz", + "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==", "cpu": [ "arm" ], @@ -249,9 +249,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz", + "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==", "cpu": [ "arm64" ], @@ -266,9 +266,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz", + "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==", "cpu": [ "ia32" ], @@ -283,9 +283,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz", + "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==", "cpu": [ "loong64" ], @@ -300,9 +300,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz", + "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==", "cpu": [ "mips64el" ], @@ -317,9 +317,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz", + "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==", "cpu": [ "ppc64" ], @@ -334,9 +334,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz", + "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==", "cpu": [ "riscv64" ], @@ -351,9 +351,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz", + "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==", "cpu": [ "s390x" ], @@ -368,9 +368,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz", + "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==", "cpu": [ "x64" ], @@ -385,9 +385,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz", + "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==", "cpu": [ "arm64" ], @@ -402,9 +402,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz", + "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==", "cpu": [ "x64" ], @@ -419,9 +419,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz", + "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==", "cpu": [ "arm64" ], @@ -436,9 +436,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz", + "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==", "cpu": [ "x64" ], @@ -453,9 +453,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz", + "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==", "cpu": [ "x64" ], @@ -470,9 +470,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz", + "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==", "cpu": [ "arm64" ], @@ -487,9 +487,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz", + "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==", "cpu": [ "ia32" ], @@ -504,9 +504,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz", + "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==", "cpu": [ "x64" ], @@ -909,9 +909,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "22.13.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz", - "integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==", + "version": "22.13.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.7.tgz", + "integrity": "sha512-oU2q+BsQldB9lYxHNp/5aZO+/Bs0Usa74Abo9mAKulz4ahQyXRHK6UVKYIN8KSC8HXwhWSi7b49JnX+txuac0w==", "dev": true, "license": "MIT", "dependencies": { @@ -925,9 +925,9 @@ "dev": true }, "node_modules/@vitest/coverage-v8": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.6.tgz", - "integrity": "sha512-JRTlR8Bw+4BcmVTICa7tJsxqphAktakiLsAmibVLAWbu1lauFddY/tXeM6sAyl1cgkPuXtpnUgaCPhTdz1Qapg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-3.0.7.tgz", + "integrity": "sha512-Av8WgBJLTrfLOer0uy3CxjlVuWK4CzcLBndW1Nm2vI+3hZ2ozHututkfc7Blu1u6waeQ7J8gzPK/AsBRnWA5mQ==", "dev": true, "license": "MIT", "dependencies": { @@ -948,8 +948,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "3.0.6", - "vitest": "3.0.6" + "@vitest/browser": "3.0.7", + "vitest": "3.0.7" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -958,14 +958,14 @@ } }, "node_modules/@vitest/expect": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.6.tgz", - "integrity": "sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.7.tgz", + "integrity": "sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.6", - "@vitest/utils": "3.0.6", + "@vitest/spy": "3.0.7", + "@vitest/utils": "3.0.7", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, @@ -974,13 +974,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.6.tgz", - "integrity": "sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.7.tgz", + "integrity": "sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "3.0.6", + "@vitest/spy": "3.0.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, @@ -1001,9 +1001,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.6.tgz", - "integrity": "sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.7.tgz", + "integrity": "sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==", "dev": true, "license": "MIT", "dependencies": { @@ -1014,13 +1014,13 @@ } }, "node_modules/@vitest/runner": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.6.tgz", - "integrity": "sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.7.tgz", + "integrity": "sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "3.0.6", + "@vitest/utils": "3.0.7", "pathe": "^2.0.3" }, "funding": { @@ -1028,13 +1028,13 @@ } }, "node_modules/@vitest/snapshot": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.6.tgz", - "integrity": "sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.7.tgz", + "integrity": "sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.6", + "@vitest/pretty-format": "3.0.7", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, @@ -1043,9 +1043,9 @@ } }, "node_modules/@vitest/spy": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.6.tgz", - "integrity": "sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.7.tgz", + "integrity": "sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==", "dev": true, "license": "MIT", "dependencies": { @@ -1056,13 +1056,13 @@ } }, "node_modules/@vitest/utils": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.6.tgz", - "integrity": "sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.7.tgz", + "integrity": "sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "3.0.6", + "@vitest/pretty-format": "3.0.7", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, @@ -1298,9 +1298,9 @@ "license": "MIT" }, "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz", + "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1311,31 +1311,31 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" + "@esbuild/aix-ppc64": "0.25.0", + "@esbuild/android-arm": "0.25.0", + "@esbuild/android-arm64": "0.25.0", + "@esbuild/android-x64": "0.25.0", + "@esbuild/darwin-arm64": "0.25.0", + "@esbuild/darwin-x64": "0.25.0", + "@esbuild/freebsd-arm64": "0.25.0", + "@esbuild/freebsd-x64": "0.25.0", + "@esbuild/linux-arm": "0.25.0", + "@esbuild/linux-arm64": "0.25.0", + "@esbuild/linux-ia32": "0.25.0", + "@esbuild/linux-loong64": "0.25.0", + "@esbuild/linux-mips64el": "0.25.0", + "@esbuild/linux-ppc64": "0.25.0", + "@esbuild/linux-riscv64": "0.25.0", + "@esbuild/linux-s390x": "0.25.0", + "@esbuild/linux-x64": "0.25.0", + "@esbuild/netbsd-arm64": "0.25.0", + "@esbuild/netbsd-x64": "0.25.0", + "@esbuild/openbsd-arm64": "0.25.0", + "@esbuild/openbsd-x64": "0.25.0", + "@esbuild/sunos-x64": "0.25.0", + "@esbuild/win32-arm64": "0.25.0", + "@esbuild/win32-ia32": "0.25.0", + "@esbuild/win32-x64": "0.25.0" } }, "node_modules/estree-walker": { @@ -2223,9 +2223,9 @@ "license": "ISC" }, "node_modules/postcss": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.2.tgz", - "integrity": "sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "funding": [ { @@ -2599,9 +2599,9 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", + "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { @@ -2724,14 +2724,14 @@ } }, "node_modules/vite": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.1.1.tgz", - "integrity": "sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.0.tgz", + "integrity": "sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==", "dev": true, "license": "MIT", "dependencies": { - "esbuild": "^0.24.2", - "postcss": "^8.5.2", + "esbuild": "^0.25.0", + "postcss": "^8.5.3", "rollup": "^4.30.1" }, "bin": { @@ -2796,9 +2796,9 @@ } }, "node_modules/vite-node": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.6.tgz", - "integrity": "sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.7.tgz", + "integrity": "sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==", "dev": true, "license": "MIT", "dependencies": { @@ -2819,19 +2819,19 @@ } }, "node_modules/vitest": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.6.tgz", - "integrity": "sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.7.tgz", + "integrity": "sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/expect": "3.0.6", - "@vitest/mocker": "3.0.6", - "@vitest/pretty-format": "^3.0.6", - "@vitest/runner": "3.0.6", - "@vitest/snapshot": "3.0.6", - "@vitest/spy": "3.0.6", - "@vitest/utils": "3.0.6", + "@vitest/expect": "3.0.7", + "@vitest/mocker": "3.0.7", + "@vitest/pretty-format": "^3.0.7", + "@vitest/runner": "3.0.7", + "@vitest/snapshot": "3.0.7", + "@vitest/spy": "3.0.7", + "@vitest/utils": "3.0.7", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", @@ -2843,7 +2843,7 @@ "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.0.6", + "vite-node": "3.0.7", "why-is-node-running": "^2.3.0" }, "bin": { @@ -2859,8 +2859,8 @@ "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.0.6", - "@vitest/ui": "3.0.6", + "@vitest/browser": "3.0.7", + "@vitest/ui": "3.0.7", "happy-dom": "*", "jsdom": "*" }, diff --git a/scripts/changelog-checker/package.json b/scripts/changelog-checker/package.json index b5353e3d01..a98935ae69 100644 --- a/scripts/changelog-checker/package.json +++ b/scripts/changelog-checker/package.json @@ -10,15 +10,15 @@ }, "devDependencies": { "@types/mdast": "4.0.4", - "@types/node": "22.13.5", - "@vitest/coverage-v8": "3.0.6", + "@types/node": "22.13.7", + "@vitest/coverage-v8": "3.0.7", "mdast-util-to-string": "4.0.0", "remark": "15.0.1", "remark-parse": "11.0.0", - "typescript": "5.7.3", + "typescript": "5.8.2", "unified": "11.0.5", - "vite": "6.1.1", - "vite-node": "3.0.6", - "vitest": "3.0.6" + "vite": "6.2.0", + "vite-node": "3.0.7", + "vitest": "3.0.7" } } From d4f9bf1f11dc775647420e9f4af8d33a48893d5a Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 13:07:47 +0900 Subject: [PATCH 021/649] chore(deps): update [misskey-js] update dependencies (#15565) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/misskey-js/generator/package.json | 8 +- packages/misskey-js/package.json | 10 +- pnpm-lock.yaml | 324 +++++++++++++++------ 3 files changed, 242 insertions(+), 100 deletions(-) diff --git a/packages/misskey-js/generator/package.json b/packages/misskey-js/generator/package.json index 135d8eafdc..8014e96fe8 100644 --- a/packages/misskey-js/generator/package.json +++ b/packages/misskey-js/generator/package.json @@ -8,14 +8,14 @@ }, "devDependencies": { "@readme/openapi-parser": "2.7.0", - "@types/node": "22.13.5", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", + "@types/node": "22.13.7", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", "openapi-types": "12.1.3", "openapi-typescript": "6.7.6", "ts-case-convert": "2.1.0", "tsx": "4.19.3", - "typescript": "5.7.3" + "typescript": "5.8.2" }, "files": [ "built" diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index f9a61fd0b1..3f24b28bfe 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -35,12 +35,12 @@ "directory": "packages/misskey-js" }, "devDependencies": { - "@microsoft/api-extractor": "7.50.1", + "@microsoft/api-extractor": "7.51.0", "@swc/jest": "0.2.37", "@types/jest": "29.5.14", - "@types/node": "22.13.5", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", + "@types/node": "22.13.7", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", "jest": "29.7.0", "jest-fetch-mock": "3.0.3", "jest-websocket-mock": "2.5.0", @@ -49,7 +49,7 @@ "nodemon": "3.1.9", "execa": "8.0.1", "tsd": "0.31.2", - "typescript": "5.7.3", + "typescript": "5.8.2", "esbuild": "0.25.0", "glob": "11.0.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 45f28ac7bb..158b741686 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1300,8 +1300,8 @@ importers: version: 4.4.0 devDependencies: '@microsoft/api-extractor': - specifier: 7.50.1 - version: 7.50.1(@types/node@22.13.5) + specifier: 7.51.0 + version: 7.51.0(@types/node@22.13.7) '@swc/jest': specifier: 0.2.37 version: 0.2.37(@swc/core@1.10.16) @@ -1309,14 +1309,14 @@ importers: specifier: 29.5.14 version: 29.5.14 '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) esbuild: specifier: 0.25.0 version: 0.25.0 @@ -1328,7 +1328,7 @@ importers: version: 11.0.1 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@22.13.5) + version: 29.7.0(@types/node@22.13.7) jest-fetch-mock: specifier: 3.0.3 version: 3.0.3(encoding@0.1.13) @@ -1348,8 +1348,8 @@ importers: specifier: 0.31.2 version: 0.31.2 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 packages/misskey-js/generator: devDependencies: @@ -1357,14 +1357,14 @@ importers: specifier: 2.7.0 version: 2.7.0(openapi-types@12.1.3) '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) openapi-types: specifier: 12.1.3 version: 12.1.3 @@ -1378,8 +1378,8 @@ importers: specifier: 4.19.3 version: 4.19.3 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 packages/misskey-reversi: dependencies: @@ -2707,8 +2707,8 @@ packages: '@microsoft/api-extractor-model@7.30.3': resolution: {integrity: sha512-yEAvq0F78MmStXdqz9TTT4PZ05Xu5R8nqgwI5xmUmQjWBQ9E6R2n8HB/iZMRciG4rf9iwI2mtuQwIzDXBvHn1w==} - '@microsoft/api-extractor@7.50.1': - resolution: {integrity: sha512-L18vz0ARLNaBLKwWe0DdEf7eijDsb7ERZspgZK7PxclLoQrc+9hJZo8y4OVfCHxNVyxlwVywY2WdE/3pOFViLQ==} + '@microsoft/api-extractor@7.51.0': + resolution: {integrity: sha512-LjyQ2xljliss2kIsSo8Npu9mBv6wnaR3ikBagCU2mC7Ggn30sTAOFLzVNyMLOMiuSOFxsEbskrBO5lLn92qnZQ==} hasBin: true '@microsoft/tsdoc-config@0.17.1': @@ -4364,6 +4364,9 @@ packages: '@types/node@22.13.5': resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} + '@types/node@22.13.7': + resolution: {integrity: sha512-oU2q+BsQldB9lYxHNp/5aZO+/Bs0Usa74Abo9mAKulz4ahQyXRHK6UVKYIN8KSC8HXwhWSi7b49JnX+txuac0w==} + '@types/nodemailer@6.4.17': resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==} @@ -4533,6 +4536,14 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/eslint-plugin@8.25.0': + resolution: {integrity: sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/parser@8.24.0': resolution: {integrity: sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4547,6 +4558,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/parser@8.25.0': + resolution: {integrity: sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/scope-manager@8.24.0': resolution: {integrity: sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4555,6 +4573,10 @@ packages: resolution: {integrity: sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.25.0': + resolution: {integrity: sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/type-utils@8.24.0': resolution: {integrity: sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4569,6 +4591,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/type-utils@8.25.0': + resolution: {integrity: sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/types@8.24.0': resolution: {integrity: sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4577,6 +4606,10 @@ packages: resolution: {integrity: sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/types@8.25.0': + resolution: {integrity: sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/typescript-estree@8.24.0': resolution: {integrity: sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4589,6 +4622,12 @@ packages: peerDependencies: typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/typescript-estree@8.25.0': + resolution: {integrity: sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/utils@8.24.0': resolution: {integrity: sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4603,6 +4642,13 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/utils@8.25.0': + resolution: {integrity: sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.8.0' + '@typescript-eslint/visitor-keys@8.24.0': resolution: {integrity: sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4611,6 +4657,10 @@ packages: resolution: {integrity: sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.25.0': + resolution: {integrity: sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} @@ -10402,6 +10452,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + uid2@0.0.4: resolution: {integrity: sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==} @@ -12443,7 +12498,7 @@ snapshots: '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 @@ -12456,14 +12511,14 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.7.1 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@22.13.5) + jest-config: 29.7.0(@types/node@22.13.7) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 @@ -12492,7 +12547,7 @@ snapshots: dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 jest-mock: 29.7.0 '@jest/expect-utils@29.7.0': @@ -12510,7 +12565,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 22.13.5 + '@types/node': 22.13.7 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -12532,7 +12587,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.25 - '@types/node': 22.13.5 + '@types/node': 22.13.7 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -12602,7 +12657,7 @@ snapshots: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/yargs': 17.0.19 chalk: 4.1.2 @@ -12675,23 +12730,23 @@ snapshots: '@types/react': 18.0.28 react: 19.0.0 - '@microsoft/api-extractor-model@7.30.3(@types/node@22.13.5)': + '@microsoft/api-extractor-model@7.30.3(@types/node@22.13.7)': dependencies: '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.11.0(@types/node@22.13.5) + '@rushstack/node-core-library': 5.11.0(@types/node@22.13.7) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.50.1(@types/node@22.13.5)': + '@microsoft/api-extractor@7.51.0(@types/node@22.13.7)': dependencies: - '@microsoft/api-extractor-model': 7.30.3(@types/node@22.13.5) + '@microsoft/api-extractor-model': 7.30.3(@types/node@22.13.7) '@microsoft/tsdoc': 0.15.1 '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.11.0(@types/node@22.13.5) + '@rushstack/node-core-library': 5.11.0(@types/node@22.13.7) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.15.0(@types/node@22.13.5) - '@rushstack/ts-command-line': 4.23.5(@types/node@22.13.5) + '@rushstack/terminal': 0.15.0(@types/node@22.13.7) + '@rushstack/ts-command-line': 4.23.5(@types/node@22.13.7) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -13407,7 +13462,7 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@rushstack/node-core-library@5.11.0(@types/node@22.13.5)': + '@rushstack/node-core-library@5.11.0(@types/node@22.13.7)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -13418,23 +13473,23 @@ snapshots: resolve: 1.22.8 semver: 7.5.4 optionalDependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.15.0(@types/node@22.13.5)': + '@rushstack/terminal@0.15.0(@types/node@22.13.7)': dependencies: - '@rushstack/node-core-library': 5.11.0(@types/node@22.13.5) + '@rushstack/node-core-library': 5.11.0(@types/node@22.13.7) supports-color: 8.1.1 optionalDependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 - '@rushstack/ts-command-line@4.23.5(@types/node@22.13.5)': + '@rushstack/ts-command-line@4.23.5(@types/node@22.13.7)': dependencies: - '@rushstack/terminal': 0.15.0(@types/node@22.13.5) + '@rushstack/terminal': 0.15.0(@types/node@22.13.7) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.1 @@ -14239,9 +14294,9 @@ snapshots: find-package-json: 1.2.0 magic-string: 0.30.17 storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - typescript: 5.7.3 + typescript: 5.8.2 vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) - vue-component-meta: 2.0.16(typescript@5.7.3) + vue-component-meta: 2.0.16(typescript@5.8.2) vue-docgen-api: 4.75.1(vue@3.5.13(typescript@5.7.3)) transitivePeerDependencies: - vue @@ -14513,7 +14568,7 @@ snapshots: '@types/accepts@1.3.7': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/archiver@6.0.3': dependencies: @@ -14549,7 +14604,7 @@ snapshots: '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.35 - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/braces@3.0.1': {} @@ -14563,11 +14618,11 @@ snapshots: '@types/connect@3.4.35': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/connect@3.4.36': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/content-disposition@0.5.8': {} @@ -14592,7 +14647,7 @@ snapshots: '@types/express-serve-static-core@4.17.33': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 @@ -14605,11 +14660,11 @@ snapshots: '@types/fluent-ffmpeg@2.1.27': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/graceful-fs@4.1.6': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/hammerjs@2.0.46': {} @@ -14623,7 +14678,7 @@ snapshots: '@types/http-link-header@1.0.7': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/istanbul-lib-coverage@2.0.4': {} @@ -14644,7 +14699,7 @@ snapshots: '@types/jsdom@21.1.7': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/tough-cookie': 4.0.2 parse5: 7.2.1 @@ -14680,11 +14735,11 @@ snapshots: '@types/mysql@2.15.26': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/node-fetch@2.6.11': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 form-data: 4.0.2 '@types/node@22.13.4': @@ -14695,9 +14750,13 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/node@22.13.7': + dependencies: + undici-types: 6.20.0 + '@types/nodemailer@6.4.17': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/normalize-package-data@2.4.1': {} @@ -14708,11 +14767,11 @@ snapshots: '@types/oauth2orize@1.11.5': dependencies: '@types/express': 4.17.17 - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/oauth@0.9.6': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/offscreencanvas@2019.3.0': {} @@ -14724,13 +14783,13 @@ snapshots: '@types/pg@8.11.11': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 pg-protocol: 1.7.0 pg-types: 4.0.1 '@types/pg@8.6.1': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 pg-protocol: 1.7.0 pg-types: 2.2.0 @@ -14742,7 +14801,7 @@ snapshots: '@types/qrcode@1.5.5': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/qs@6.9.7': {} @@ -14760,7 +14819,7 @@ snapshots: '@types/readdir-glob@1.1.1': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/rename@1.0.7': {} @@ -14781,7 +14840,7 @@ snapshots: '@types/serve-static@1.15.1': dependencies: '@types/mime': 3.0.1 - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/serviceworker@0.0.74': {} @@ -14805,7 +14864,7 @@ snapshots: '@types/tedious@4.0.14': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/throttle-debounce@5.0.2': {} @@ -14823,15 +14882,15 @@ snapshots: '@types/vary@1.1.3': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/web-push@3.6.4': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/ws@8.5.14': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@types/yargs-parser@21.0.0': {} @@ -14841,7 +14900,7 @@ snapshots: '@types/yauzl@2.10.0': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 optional: true '@typescript-eslint/eslint-plugin@8.24.0(@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3)': @@ -14878,6 +14937,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/eslint-plugin@8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.25.0(eslint@9.20.1)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/type-utils': 8.25.0(eslint@9.20.1)(typescript@5.8.2) + '@typescript-eslint/utils': 8.25.0(eslint@9.20.1)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.25.0 + eslint: 9.20.1 + graphemer: 1.4.0 + ignore: 5.3.1 + natural-compare: 1.4.0 + ts-api-utils: 2.0.1(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/parser@8.24.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: '@typescript-eslint/scope-manager': 8.24.0 @@ -14902,6 +14978,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.25.0 + debug: 4.4.0(supports-color@8.1.1) + eslint: 9.20.1 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.24.0': dependencies: '@typescript-eslint/types': 8.24.0 @@ -14912,6 +15000,11 @@ snapshots: '@typescript-eslint/types': 8.24.1 '@typescript-eslint/visitor-keys': 8.24.1 + '@typescript-eslint/scope-manager@8.25.0': + dependencies: + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/visitor-keys': 8.25.0 + '@typescript-eslint/type-utils@8.24.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: '@typescript-eslint/typescript-estree': 8.24.0(typescript@5.7.3) @@ -14934,10 +15027,23 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.25.0(eslint@9.20.1)(typescript@5.8.2)': + dependencies: + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.8.2) + '@typescript-eslint/utils': 8.25.0(eslint@9.20.1)(typescript@5.8.2) + debug: 4.4.0(supports-color@8.1.1) + eslint: 9.20.1 + ts-api-utils: 2.0.1(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.24.0': {} '@typescript-eslint/types@8.24.1': {} + '@typescript-eslint/types@8.25.0': {} + '@typescript-eslint/typescript-estree@8.24.0(typescript@5.7.3)': dependencies: '@typescript-eslint/types': 8.24.0 @@ -14966,6 +15072,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/typescript-estree@8.25.0(typescript@5.8.2)': + dependencies: + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/visitor-keys': 8.25.0 + debug: 4.4.0(supports-color@8.1.1) + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.4 + semver: 7.6.3 + ts-api-utils: 2.0.1(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/utils@8.24.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.20.1) @@ -14988,6 +15108,17 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/utils@8.25.0(eslint@9.20.1)(typescript@5.8.2)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.20.1) + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.8.2) + eslint: 9.20.1 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/visitor-keys@8.24.0': dependencies: '@typescript-eslint/types': 8.24.0 @@ -14998,6 +15129,11 @@ snapshots: '@typescript-eslint/types': 8.24.1 eslint-visitor-keys: 4.2.0 + '@typescript-eslint/visitor-keys@8.25.0': + dependencies: + '@typescript-eslint/types': 8.25.0 + eslint-visitor-keys: 4.2.0 + '@ungap/structured-clone@1.2.0': {} '@vitejs/plugin-vue@5.2.1(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.7.3))': @@ -15156,7 +15292,7 @@ snapshots: de-indent: 1.0.2 he: 1.2.0 - '@vue/language-core@2.0.16(typescript@5.7.3)': + '@vue/language-core@2.0.16(typescript@5.8.2)': dependencies: '@volar/language-core': 2.2.0 '@vue/compiler-dom': 3.5.13 @@ -15166,7 +15302,7 @@ snapshots: path-browserify: 1.0.1 vue-template-compiler: 2.7.14 optionalDependencies: - typescript: 5.7.3 + typescript: 5.8.2 '@vue/language-core@2.2.4(typescript@5.7.3)': dependencies: @@ -16263,13 +16399,13 @@ snapshots: - supports-color - ts-node - create-jest@29.7.0(@types/node@22.13.5): + create-jest@29.7.0(@types/node@22.13.7): 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.13.5) + jest-config: 29.7.0(@types/node@22.13.7) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -18481,7 +18617,7 @@ snapshots: '@jest/expect': 29.7.0 '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 chalk: 4.1.2 co: 4.6.0 dedent: 1.3.0 @@ -18520,16 +18656,16 @@ snapshots: - supports-color - ts-node - jest-cli@29.7.0(@types/node@22.13.5): + jest-cli@29.7.0(@types/node@22.13.7): 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.13.5) + create-jest: 29.7.0(@types/node@22.13.7) exit: 0.1.2 import-local: 3.1.0 - jest-config: 29.7.0(@types/node@22.13.5) + jest-config: 29.7.0(@types/node@22.13.7) jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 @@ -18569,7 +18705,7 @@ snapshots: - babel-plugin-macros - supports-color - jest-config@29.7.0(@types/node@22.13.5): + jest-config@29.7.0(@types/node@22.13.7): dependencies: '@babel/core': 7.23.5 '@jest/test-sequencer': 29.7.0 @@ -18594,7 +18730,7 @@ snapshots: slash: 3.0.0 strip-json-comments: 3.1.1 optionalDependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 transitivePeerDependencies: - babel-plugin-macros - supports-color @@ -18623,7 +18759,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -18640,7 +18776,7 @@ snapshots: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.6 - '@types/node': 22.13.5 + '@types/node': 22.13.7 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -18679,7 +18815,7 @@ snapshots: jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 jest-util: 29.7.0 jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): @@ -18714,7 +18850,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -18742,7 +18878,7 @@ snapshots: '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -18788,7 +18924,7 @@ snapshots: jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 chalk: 4.1.2 ci-info: 3.7.1 graceful-fs: 4.2.11 @@ -18807,7 +18943,7 @@ snapshots: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 22.13.5 + '@types/node': 22.13.7 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 @@ -18821,7 +18957,7 @@ snapshots: jest-worker@29.7.0: dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -18838,12 +18974,12 @@ snapshots: - supports-color - ts-node - jest@29.7.0(@types/node@22.13.5): + jest@29.7.0(@types/node@22.13.7): dependencies: '@jest/core': 29.7.0 '@jest/types': 29.6.3 import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@22.13.5) + jest-cli: 29.7.0(@types/node@22.13.7) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -21839,6 +21975,10 @@ snapshots: dependencies: typescript: 5.7.3 + ts-api-utils@2.0.1(typescript@5.8.2): + dependencies: + typescript: 5.8.2 + ts-case-convert@2.1.0: {} ts-dedent@2.2.0: {} @@ -22005,6 +22145,8 @@ snapshots: typescript@5.7.3: {} + typescript@5.8.2: {} + uid2@0.0.4: {} uid@2.0.2: @@ -22288,14 +22430,14 @@ snapshots: vscode-uri@3.0.8: {} - vue-component-meta@2.0.16(typescript@5.7.3): + vue-component-meta@2.0.16(typescript@5.8.2): dependencies: '@volar/typescript': 2.2.0 - '@vue/language-core': 2.0.16(typescript@5.7.3) + '@vue/language-core': 2.0.16(typescript@5.8.2) path-browserify: 1.0.1 vue-component-type-helpers: 2.0.16 optionalDependencies: - typescript: 5.7.3 + typescript: 5.8.2 vue-component-type-helpers@1.8.4: {} From e2eddd5b1a0d48373bdea5e2167c891ca3d79914 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 13:07:59 +0900 Subject: [PATCH 022/649] chore(deps): update actions/cache action to v4.2.2 (#15564) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index a34ac38d74..b1d52e8b3b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -79,7 +79,7 @@ jobs: - run: corepack enable - run: pnpm i --frozen-lockfile - name: Restore eslint cache - uses: actions/cache@v4.2.1 + uses: actions/cache@v4.2.2 with: path: ${{ env.eslint-cache-path }} key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }} From 830da5e9f1f1902e37ec17b2afa82190c3fe6573 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 1 Mar 2025 13:11:09 +0900 Subject: [PATCH 023/649] fix(deps): update [frontend] update dependencies (#15566) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- packages/frontend-embed/package.json | 22 +- packages/frontend-shared/package.json | 8 +- packages/frontend/package.json | 70 +- packages/misskey-bubble-game/package.json | 8 +- packages/misskey-reversi/package.json | 8 +- packages/sw/package.json | 4 +- pnpm-lock.yaml | 1508 +++++++++------------ 7 files changed, 664 insertions(+), 964 deletions(-) diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index 4768356865..416aa89bc0 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -26,15 +26,15 @@ "frontend-shared": "workspace:*", "punycode.js": "2.3.1", "rollup": "4.34.8", - "sass": "1.85.0", - "shiki": "3.0.0", + "sass": "1.85.1", + "shiki": "3.1.0", "tinycolor2": "1.6.0", - "tsc-alias": "1.8.10", + "tsc-alias": "1.8.11", "tsconfig-paths": "4.2.0", - "typescript": "5.7.3", + "typescript": "5.8.2", "uuid": "11.1.0", "json5": "2.2.3", - "vite": "6.1.1", + "vite": "6.2.0", "vue": "3.5.13" }, "devDependencies": { @@ -42,23 +42,23 @@ "@testing-library/vue": "8.1.0", "@types/estree": "1.0.6", "@types/micromatch": "4.0.9", - "@types/node": "22.13.5", + "@types/node": "22.13.7", "@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/tinycolor2": "1.4.6", "@types/ws": "8.5.14", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", - "@vitest/coverage-v8": "3.0.6", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", + "@vitest/coverage-v8": "3.0.7", "@vue/runtime-core": "3.5.13", "acorn": "8.14.0", "cross-env": "7.0.3", "eslint-plugin-import": "2.31.0", "eslint-plugin-vue": "9.32.0", "fast-glob": "3.3.3", - "happy-dom": "17.1.4", + "happy-dom": "17.1.8", "intersection-observer": "0.12.2", "micromatch": "4.0.8", - "msw": "2.7.1", + "msw": "2.7.3", "nodemon": "3.1.9", "prettier": "3.5.2", "start-server-and-test": "2.0.10", diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index ca7bee467b..10df3b3999 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -21,13 +21,13 @@ "lint": "pnpm typecheck && pnpm eslint" }, "devDependencies": { - "@types/node": "22.13.5", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", + "@types/node": "22.13.7", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", "esbuild": "0.25.0", "eslint-plugin-vue": "9.32.0", "nodemon": "3.1.9", - "typescript": "5.7.3", + "typescript": "5.8.2", "vue-eslint-parser": "9.4.3" }, "files": [ diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 10fbc58cf0..c4b81b847d 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -40,7 +40,7 @@ "chartjs-chart-matrix": "2.0.1", "chartjs-plugin-gradient": "0.6.1", "chartjs-plugin-zoom": "2.2.0", - "chromatic": "11.25.2", + "chromatic": "11.26.1", "compare-versions": "6.1.1", "cropperjs": "2.0.0-rc.2", "date-fns": "4.1.0", @@ -60,68 +60,68 @@ "punycode.js": "2.3.1", "rollup": "4.34.8", "sanitize-html": "2.14.0", - "sass": "1.85.0", - "shiki": "3.0.0", + "sass": "1.85.1", + "shiki": "3.1.0", "strict-event-emitter-types": "2.0.0", "textarea-caret": "3.1.0", - "three": "0.173.0", + "three": "0.174.0", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", - "tsc-alias": "1.8.10", + "tsc-alias": "1.8.11", "tsconfig-paths": "4.2.0", - "typescript": "5.7.3", + "typescript": "5.8.2", "uuid": "11.1.0", "v-code-diff": "1.13.1", - "vite": "6.1.1", + "vite": "6.2.0", "vue": "3.5.13", "vuedraggable": "next" }, "devDependencies": { "@misskey-dev/summaly": "5.2.0", - "@storybook/addon-actions": "8.5.8", - "@storybook/addon-essentials": "8.5.8", - "@storybook/addon-interactions": "8.5.8", - "@storybook/addon-links": "8.5.8", - "@storybook/addon-mdx-gfm": "8.5.8", - "@storybook/addon-storysource": "8.5.8", - "@storybook/blocks": "8.5.8", - "@storybook/components": "8.5.8", - "@storybook/core-events": "8.5.8", - "@storybook/manager-api": "8.5.8", - "@storybook/preview-api": "8.5.8", - "@storybook/react": "8.5.8", - "@storybook/react-vite": "8.5.8", - "@storybook/test": "8.5.8", - "@storybook/theming": "8.5.8", - "@storybook/types": "8.5.8", - "@storybook/vue3": "8.5.8", - "@storybook/vue3-vite": "8.5.8", + "@storybook/addon-actions": "8.6.2", + "@storybook/addon-essentials": "8.6.2", + "@storybook/addon-interactions": "8.6.2", + "@storybook/addon-links": "8.6.2", + "@storybook/addon-mdx-gfm": "8.6.2", + "@storybook/addon-storysource": "8.6.2", + "@storybook/blocks": "8.6.2", + "@storybook/components": "8.6.2", + "@storybook/core-events": "8.6.2", + "@storybook/manager-api": "8.6.2", + "@storybook/preview-api": "8.6.2", + "@storybook/react": "8.6.2", + "@storybook/react-vite": "8.6.2", + "@storybook/test": "8.6.2", + "@storybook/theming": "8.6.2", + "@storybook/types": "8.6.2", + "@storybook/vue3": "8.6.2", + "@storybook/vue3-vite": "8.6.2", "@testing-library/vue": "8.1.0", "@types/canvas-confetti": "1.9.0", "@types/estree": "1.0.6", "@types/matter-js": "0.19.8", "@types/micromatch": "4.0.9", - "@types/node": "22.13.5", + "@types/node": "22.13.7", "@types/punycode.js": "npm:@types/punycode@2.1.4", "@types/sanitize-html": "2.13.0", "@types/seedrandom": "3.0.8", "@types/throttle-debounce": "5.0.2", "@types/tinycolor2": "1.4.6", "@types/ws": "8.5.14", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", - "@vitest/coverage-v8": "3.0.6", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", + "@vitest/coverage-v8": "3.0.7", "@vue/runtime-core": "3.5.13", "acorn": "8.14.0", "cross-env": "7.0.3", - "cypress": "14.0.3", + "cypress": "14.1.0", "eslint-plugin-import": "2.31.0", "eslint-plugin-vue": "9.32.0", "fast-glob": "3.3.3", - "happy-dom": "17.1.4", + "happy-dom": "17.1.8", "intersection-observer": "0.12.2", "micromatch": "4.0.8", - "msw": "2.7.1", + "msw": "2.7.3", "msw-storybook-addon": "2.0.4", "nodemon": "3.1.9", "prettier": "3.5.2", @@ -129,11 +129,11 @@ "react-dom": "19.0.0", "seedrandom": "3.0.5", "start-server-and-test": "2.0.10", - "storybook": "8.5.8", + "storybook": "8.6.2", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "vite-plugin-turbosnap": "1.0.3", - "vitest": "3.0.6", - "vitest-fetch-mock": "0.4.3", + "vitest": "3.0.7", + "vitest-fetch-mock": "0.4.4", "vue-component-type-helpers": "2.2.4", "vue-eslint-parser": "9.4.3", "vue-tsc": "2.2.4" diff --git a/packages/misskey-bubble-game/package.json b/packages/misskey-bubble-game/package.json index 881d245613..4a47a0fa56 100644 --- a/packages/misskey-bubble-game/package.json +++ b/packages/misskey-bubble-game/package.json @@ -24,12 +24,12 @@ "devDependencies": { "@types/matter-js": "0.19.8", "@types/seedrandom": "3.0.8", - "@types/node": "22.13.5", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", + "@types/node": "22.13.7", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", "nodemon": "3.1.9", "execa": "9.5.2", - "typescript": "5.7.3", + "typescript": "5.8.2", "esbuild": "0.25.0", "glob": "11.0.1" }, diff --git a/packages/misskey-reversi/package.json b/packages/misskey-reversi/package.json index a9837f8e0a..35e183b51e 100644 --- a/packages/misskey-reversi/package.json +++ b/packages/misskey-reversi/package.json @@ -22,12 +22,12 @@ "lint": "pnpm typecheck && pnpm eslint" }, "devDependencies": { - "@types/node": "22.13.5", - "@typescript-eslint/eslint-plugin": "8.24.1", - "@typescript-eslint/parser": "8.24.1", + "@types/node": "22.13.7", + "@typescript-eslint/eslint-plugin": "8.25.0", + "@typescript-eslint/parser": "8.25.0", "execa": "9.5.2", "nodemon": "3.1.9", - "typescript": "5.7.3", + "typescript": "5.8.2", "esbuild": "0.25.0", "glob": "11.0.1" }, diff --git a/packages/sw/package.json b/packages/sw/package.json index 7a72ff39fe..f9fca80139 100644 --- a/packages/sw/package.json +++ b/packages/sw/package.json @@ -14,11 +14,11 @@ "misskey-js": "workspace:*" }, "devDependencies": { - "@typescript-eslint/parser": "8.24.1", + "@typescript-eslint/parser": "8.25.0", "@typescript/lib-webworker": "npm:@types/serviceworker@0.0.74", "eslint-plugin-import": "2.31.0", "nodemon": "3.1.9", - "typescript": "5.7.3" + "typescript": "5.8.2" }, "type": "module" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 158b741686..8b40bf1a4f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -720,7 +720,7 @@ importers: version: 15.1.1 '@vitejs/plugin-vue': specifier: 5.2.1 - version: 5.2.1(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.7.3)) + version: 5.2.1(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2)) '@vue/compiler-sfc': specifier: 3.5.13 version: 3.5.13 @@ -758,8 +758,8 @@ importers: specifier: 2.2.0 version: 2.2.0(chart.js@4.4.8) chromatic: - specifier: 11.25.2 - version: 11.25.2 + specifier: 11.26.1 + version: 11.26.1 compare-versions: specifier: 6.1.1 version: 6.1.1 @@ -818,11 +818,11 @@ importers: specifier: 2.14.0 version: 2.14.0 sass: - specifier: 1.85.0 - version: 1.85.0 + specifier: 1.85.1 + version: 1.85.1 shiki: - specifier: 3.0.0 - version: 3.0.0 + specifier: 3.1.0 + version: 3.1.0 strict-event-emitter-types: specifier: 2.0.0 version: 2.0.0 @@ -830,8 +830,8 @@ importers: specifier: 3.1.0 version: 3.1.0 three: - specifier: 0.173.0 - version: 0.173.0 + specifier: 0.174.0 + version: 0.174.0 throttle-debounce: specifier: 5.0.2 version: 5.0.2 @@ -839,90 +839,90 @@ importers: specifier: 1.6.0 version: 1.6.0 tsc-alias: - specifier: 1.8.10 - version: 1.8.10 + specifier: 1.8.11 + version: 1.8.11 tsconfig-paths: specifier: 4.2.0 version: 4.2.0 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 uuid: specifier: 11.1.0 version: 11.1.0 v-code-diff: specifier: 1.13.1 - version: 1.13.1(vue@3.5.13(typescript@5.7.3)) + version: 1.13.1(vue@3.5.13(typescript@5.8.2)) vite: - specifier: 6.1.1 - version: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + specifier: 6.2.0 + version: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) vue: specifier: 3.5.13 - version: 3.5.13(typescript@5.7.3) + version: 3.5.13(typescript@5.8.2) vuedraggable: specifier: next - version: 4.1.0(vue@3.5.13(typescript@5.7.3)) + version: 4.1.0(vue@3.5.13(typescript@5.8.2)) devDependencies: '@misskey-dev/summaly': specifier: 5.2.0 version: 5.2.0 '@storybook/addon-actions': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/addon-essentials': - specifier: 8.5.8 - version: 8.5.8(@types/react@18.0.28)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(@types/react@18.0.28)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/addon-interactions': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/addon-links': - specifier: 8.5.8 - version: 8.5.8(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/addon-mdx-gfm': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/addon-storysource': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/blocks': - specifier: 8.5.8 - version: 8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/components': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/core-events': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/manager-api': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/preview-api': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/react': - specifier: 8.5.8 - version: 8.5.8(@storybook/test@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.7.3) + specifier: 8.6.2 + version: 8.6.2(@storybook/test@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.8.2) '@storybook/react-vite': - specifier: 8.5.8 - version: 8.5.8(@storybook/test@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.34.8)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.7.3)(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) + specifier: 8.6.2 + version: 8.6.2(@storybook/test@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.34.8)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) '@storybook/test': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/theming': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/types': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/vue3': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.7.3)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2)) '@storybook/vue3-vite': - specifier: 8.5.8 - version: 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.7.3)) + specifier: 8.6.2 + version: 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2)) '@testing-library/vue': specifier: 8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) + version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2)) '@types/canvas-confetti': specifier: 1.9.0 version: 1.9.0 @@ -936,8 +936,8 @@ importers: specifier: 4.0.9 version: 4.0.9 '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@types/punycode.js': specifier: npm:@types/punycode@2.1.4 version: '@types/punycode@2.1.4' @@ -957,14 +957,14 @@ importers: specifier: 8.5.14 version: 8.5.14 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) '@vitest/coverage-v8': - specifier: 3.0.6 - version: 3.0.6(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) + specifier: 3.0.7 + version: 3.0.7(vitest@3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) '@vue/runtime-core': specifier: 3.5.13 version: 3.5.13 @@ -975,11 +975,11 @@ importers: specifier: 7.0.3 version: 7.0.3 cypress: - specifier: 14.0.3 - version: 14.0.3 + specifier: 14.1.0 + version: 14.1.0 eslint-plugin-import: specifier: 2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1) + version: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1) eslint-plugin-vue: specifier: 9.32.0 version: 9.32.0(eslint@9.20.1) @@ -987,8 +987,8 @@ importers: specifier: 3.3.3 version: 3.3.3 happy-dom: - specifier: 17.1.4 - version: 17.1.4 + specifier: 17.1.8 + version: 17.1.8 intersection-observer: specifier: 0.12.2 version: 0.12.2 @@ -996,11 +996,11 @@ importers: specifier: 4.0.8 version: 4.0.8 msw: - specifier: 2.7.1 - version: 2.7.1(@types/node@22.13.5)(typescript@5.7.3) + specifier: 2.7.3 + version: 2.7.3(@types/node@22.13.7)(typescript@5.8.2) msw-storybook-addon: specifier: 2.0.4 - version: 2.0.4(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3)) + version: 2.0.4(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2)) nodemon: specifier: 3.1.9 version: 3.1.9 @@ -1020,20 +1020,20 @@ importers: specifier: 2.0.10 version: 2.0.10 storybook: - specifier: 8.5.8 - version: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + specifier: 8.6.2 + version: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) storybook-addon-misskey-theme: specifier: github:misskey-dev/storybook-addon-misskey-theme - version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/components@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/core-events@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/manager-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/preview-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/theming@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/types@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + version: https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/components@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/core-events@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/manager-api@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/preview-api@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/theming@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/types@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: - specifier: 3.0.6 - version: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + specifier: 3.0.7 + version: 3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) vitest-fetch-mock: - specifier: 0.4.3 - version: 0.4.3(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) + specifier: 0.4.4 + version: 0.4.4(vitest@3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) vue-component-type-helpers: specifier: 2.2.4 version: 2.2.4 @@ -1042,7 +1042,7 @@ importers: version: 9.4.3(eslint@9.20.1) vue-tsc: specifier: 2.2.4 - version: 2.2.4(typescript@5.7.3) + version: 2.2.4(typescript@5.8.2) packages/frontend-embed: dependencies: @@ -1066,7 +1066,7 @@ importers: version: 15.1.1 '@vitejs/plugin-vue': specifier: 5.2.1 - version: 5.2.1(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.7.3)) + version: 5.2.1(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2)) '@vue/compiler-sfc': specifier: 3.5.13 version: 3.5.13 @@ -1098,39 +1098,39 @@ importers: specifier: 4.34.8 version: 4.34.8 sass: - specifier: 1.85.0 - version: 1.85.0 + specifier: 1.85.1 + version: 1.85.1 shiki: - specifier: 3.0.0 - version: 3.0.0 + specifier: 3.1.0 + version: 3.1.0 tinycolor2: specifier: 1.6.0 version: 1.6.0 tsc-alias: - specifier: 1.8.10 - version: 1.8.10 + specifier: 1.8.11 + version: 1.8.11 tsconfig-paths: specifier: 4.2.0 version: 4.2.0 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 uuid: specifier: 11.1.0 version: 11.1.0 vite: - specifier: 6.1.1 - version: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + specifier: 6.2.0 + version: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) vue: specifier: 3.5.13 - version: 3.5.13(typescript@5.7.3) + version: 3.5.13(typescript@5.8.2) devDependencies: '@misskey-dev/summaly': specifier: 5.2.0 version: 5.2.0 '@testing-library/vue': specifier: 8.1.0 - version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) + version: 8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2)) '@types/estree': specifier: 1.0.6 version: 1.0.6 @@ -1138,8 +1138,8 @@ importers: specifier: 4.0.9 version: 4.0.9 '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@types/punycode.js': specifier: npm:@types/punycode@2.1.4 version: '@types/punycode@2.1.4' @@ -1150,14 +1150,14 @@ importers: specifier: 8.5.14 version: 8.5.14 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) '@vitest/coverage-v8': - specifier: 3.0.6 - version: 3.0.6(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) + specifier: 3.0.7 + version: 3.0.7(vitest@3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) '@vue/runtime-core': specifier: 3.5.13 version: 3.5.13 @@ -1169,7 +1169,7 @@ importers: version: 7.0.3 eslint-plugin-import: specifier: 2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1) + version: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1) eslint-plugin-vue: specifier: 9.32.0 version: 9.32.0(eslint@9.20.1) @@ -1177,8 +1177,8 @@ importers: specifier: 3.3.3 version: 3.3.3 happy-dom: - specifier: 17.1.4 - version: 17.1.4 + specifier: 17.1.8 + version: 17.1.8 intersection-observer: specifier: 0.12.2 version: 0.12.2 @@ -1186,8 +1186,8 @@ importers: specifier: 4.0.8 version: 4.0.8 msw: - specifier: 2.7.1 - version: 2.7.1(@types/node@22.13.5)(typescript@5.7.3) + specifier: 2.7.3 + version: 2.7.3(@types/node@22.13.7)(typescript@5.8.2) nodemon: specifier: 3.1.9 version: 3.1.9 @@ -1208,7 +1208,7 @@ importers: version: 9.4.3(eslint@9.20.1) vue-tsc: specifier: 2.2.4 - version: 2.2.4(typescript@5.7.3) + version: 2.2.4(typescript@5.8.2) packages/frontend-shared: dependencies: @@ -1217,17 +1217,17 @@ importers: version: link:../misskey-js vue: specifier: 3.5.13 - version: 3.5.13(typescript@5.7.3) + version: 3.5.13(typescript@5.8.2) devDependencies: '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) esbuild: specifier: 0.25.0 version: 0.25.0 @@ -1238,8 +1238,8 @@ importers: specifier: 3.1.9 version: 3.1.9 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 vue-eslint-parser: specifier: 9.4.3 version: 9.4.3(eslint@9.20.1) @@ -1260,17 +1260,17 @@ importers: specifier: 0.19.8 version: 0.19.8 '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@types/seedrandom': specifier: 3.0.8 version: 3.0.8 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) esbuild: specifier: 0.25.0 version: 0.25.0 @@ -1284,8 +1284,8 @@ importers: specifier: 3.1.9 version: 3.1.9 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 packages/misskey-js: dependencies: @@ -1388,14 +1388,14 @@ importers: version: 1.2.2 devDependencies: '@types/node': - specifier: 22.13.5 - version: 22.13.5 + specifier: 22.13.7 + version: 22.13.7 '@typescript-eslint/eslint-plugin': - specifier: 8.24.1 - version: 8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) esbuild: specifier: 0.25.0 version: 0.25.0 @@ -1409,8 +1409,8 @@ importers: specifier: 3.1.9 version: 3.1.9 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 packages/sw: dependencies: @@ -1425,20 +1425,20 @@ importers: version: link:../misskey-js devDependencies: '@typescript-eslint/parser': - specifier: 8.24.1 - version: 8.24.1(eslint@9.20.1)(typescript@5.7.3) + specifier: 8.25.0 + version: 8.25.0(eslint@9.20.1)(typescript@5.8.2) '@typescript/lib-webworker': specifier: npm:@types/serviceworker@0.0.74 version: '@types/serviceworker@0.0.74' eslint-plugin-import: specifier: 2.31.0 - version: 2.31.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1) + version: 2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1) nodemon: specifier: 3.1.9 version: 3.1.9 typescript: - specifier: 5.7.3 - version: 5.7.3 + specifier: 5.8.2 + version: 5.8.2 packages: @@ -1979,300 +1979,150 @@ packages: '@emnapi/runtime@1.2.0': resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} - '@esbuild/aix-ppc64@0.24.2': - resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.25.0': resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.24.2': - resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.25.0': resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.24.2': - resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.25.0': resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.24.2': - resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.25.0': resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.24.2': - resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.25.0': resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.24.2': - resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.25.0': resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.24.2': - resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.25.0': resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.24.2': - resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.25.0': resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.24.2': - resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.25.0': resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.24.2': - resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.25.0': resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.24.2': - resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.25.0': resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.24.2': - resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.25.0': resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.24.2': - resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.25.0': resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.24.2': - resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.25.0': resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.24.2': - resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.25.0': resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.24.2': - resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.25.0': resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.24.2': - resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.25.0': resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.24.2': - resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.25.0': resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.24.2': - resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.25.0': resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.24.2': - resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.25.0': resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.24.2': - resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.25.0': resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.24.2': - resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.25.0': resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.24.2': - resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.25.0': resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.24.2': - resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.25.0': resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.24.2': - resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.25.0': resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} engines: {node: '>=18'} @@ -3448,23 +3298,23 @@ packages: engines: {node: '>=14.18'} hasBin: true - '@shikijs/core@3.0.0': - resolution: {integrity: sha512-gSm3JQf2J2psiUn5bWokmZwnu5N0jfBtRps4CQ1B+qrFvmZCRAkMVoaxgl9qZgAFK5KisLAS3//XaMFVytYHKw==} + '@shikijs/core@3.1.0': + resolution: {integrity: sha512-1ppAOyg3F18N8Ge9DmJjGqRVswihN33rOgPovR6gUHW17Hw1L4RlRhnmVQcsacSHh0A8IO1FIgNbtTxUFwodmg==} - '@shikijs/engine-javascript@3.0.0': - resolution: {integrity: sha512-zoB10hTfvk1iZk1ldt6VaF+0iucQL+4TtSvTdTu5MhOeLPLEf5nZ8Wz6uxlp99y627OLalYa2z4W0iTTwb6oyA==} + '@shikijs/engine-javascript@3.1.0': + resolution: {integrity: sha512-/LwkhW17jYi7uPcdaaSQQDNW+xgrHXarkrxYPoC6WPzH2xW5mFMw12doHXJBqxmYvtcTbaatcv2MkH9+3PU1FA==} - '@shikijs/engine-oniguruma@3.0.0': - resolution: {integrity: sha512-uM9lqwMrlPHPVcdpAN/4pAzTJah1pY7mi9f1MxG887SDkjF/tdiQK+5200Y8N5Hg125sewdMQ1K2agoAo8hDiA==} + '@shikijs/engine-oniguruma@3.1.0': + resolution: {integrity: sha512-reRgy8VzDPdiDocuGDD60Rk/jLxgcgy+6H4n6jYLeN2Yw5ikasRjQQx8ERXtDM35yg2v/d6KolDBcK8hYYhcmw==} - '@shikijs/langs@3.0.0': - resolution: {integrity: sha512-HBsZAukiYz7k3hzttPWa0en3PABEwK3cpxcAcERRwvwuKc5pn0Y+yPxAIYZtN9cFdtNqrbFJNhfcEu/xbG1u/A==} + '@shikijs/langs@3.1.0': + resolution: {integrity: sha512-hAM//sExPXAXG3ZDWjrmV6Vlw4zlWFOcT1ZXNhFRBwPP27scZu/ZIdZ+TdTgy06zSvyF4KIjnF8j6+ScKGu6ww==} - '@shikijs/themes@3.0.0': - resolution: {integrity: sha512-mz63nyVB5nXWsv5H2hifDFIThZEJ/cJhMq1/+0JjMdOuuBq2H2D1Fn8UM5yzUtEvap/ipRltv381+hsHZFs4ug==} + '@shikijs/themes@3.1.0': + resolution: {integrity: sha512-A4MJmy9+ydLNbNCtkmdTp8a+ON+MMXoUe1KTkELkyu0+pHGOcbouhNuobhZoK59cL4cOST6CCz1x+kUdkp9UZA==} - '@shikijs/types@3.0.0': - resolution: {integrity: sha512-kh/xgZHxI6m9trVvPw+C47jyVHx190r0F5gkF+VO5vYB54UtcoPJe66dzZmK7GbJbzmtGEGbOwct/jsoPjjUqg==} + '@shikijs/types@3.1.0': + resolution: {integrity: sha512-F8e7Fy4ihtcNpJG572BZZC1ErYrBrzJ5Cbc9Zi3REgWry43gIvjJ9lFAoUnuy7Bvy4IFz7grUSxL5edfrrjFEA==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -3769,123 +3619,120 @@ packages: '@sqltools/formatter@1.2.5': resolution: {integrity: sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==} - '@storybook/addon-actions@8.5.8': - resolution: {integrity: sha512-7J0NAz+WDw1NmvmKIh0Qr5cxgVRDPFC5fmngbDNxedk147TkwrgmqOypgEi/SAksHbTWxJclbimoqdcsNtWffA==} + '@storybook/addon-actions@8.6.2': + resolution: {integrity: sha512-grIRReMObwwt/VZemFnaKDbeaiK257egN+/knuqMbT3eUA6aitlzTr5UynBZnsVYbJFdD6PYyIZMKoGWEdFJlQ==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-backgrounds@8.5.8': - resolution: {integrity: sha512-TsQFagQ95+d7H3/+qUZKI2B0SEK8iu6CV13cyry9Dm59nn2bBylFrwx4I3xDQUOWMiSF6QIRjCYzxKQ/jJ5OEg==} + '@storybook/addon-backgrounds@8.6.2': + resolution: {integrity: sha512-xysLkeHCdwh1xcLIrarRnJipl2ccoR1Oy6hHYcPtFiUB89gd6DsTe2WC8zsqrO16ogPYovCTP4UiBzApo+yoYA==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-controls@8.5.8': - resolution: {integrity: sha512-3iifI8mBGPsiPmV9eAYk+tK9i+xuWhVsa+sXz01xTZ/0yoOREpp972hka86mtCqdDTOJIpzh1LmxvB218OssvQ==} + '@storybook/addon-controls@8.6.2': + resolution: {integrity: sha512-MOTzQTZ64Wfc/hWBflnrOsw8qdNSu37VFzvcXtQa1npEJUO6KU822KvvuKGtdDZJhwcVrGDM5yL9gy4Nw5/M5g==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-docs@8.5.8': - resolution: {integrity: sha512-zKVUqE0UGiq1gZtY2TX57SYB4RIsdlbTDxKW2JZ9HhZGLvZ5Qb7AvdiKTZxfOepGhuw3UcNXH/zCFkFCTJifMw==} + '@storybook/addon-docs@8.6.2': + resolution: {integrity: sha512-urc6GCKZRV2Mhh2V0fzhkqOdKYvJ1E45dCeCZ7hNrz0Yfe72NG8rTz5U/+u7ESUMTjE4Q5sAgplW7hnELt4vLg==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-essentials@8.5.8': - resolution: {integrity: sha512-sCNvMZqL6dywnyHuZBrWl4f6QXsvpJHOioL3wJJKaaRMZmctbFmS0u6J8TQjmgZhQfyRzuJuhr1gJg9oeqp6AA==} + '@storybook/addon-essentials@8.6.2': + resolution: {integrity: sha512-nJvtVVcB8847Olsd5vbnW34SVQpboXdSGPRuUNTeRXOAIQQc5heWwRXjgBQgqF2kD5GaPaHfKTfec37cVyJFfA==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-highlight@8.5.8': - resolution: {integrity: sha512-kkldtFrY0oQJY/vfNLkV66hVgtp66OO8T68KoZFsmUz4a3iYgzDS8WF+Av2/9jthktFvMchjFr8NKOno9YBGIg==} + '@storybook/addon-highlight@8.6.2': + resolution: {integrity: sha512-TtRW+JK1NNuRI6zEXQAHImqVW7x+wkFGddhE6ikWX6eXJER+dgXaPd1pGBNlEQp2kzdWbzOEvXbrIKU1cy1A7Q==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-interactions@8.5.8': - resolution: {integrity: sha512-SDyIV3M+c41QemXgg1OchsFBO6YGZkZcmVeUF8C7aWm5SnzLh6B2OiggiKvRk0v3Eh3rDLXdkx3XdR2F/rG+0Q==} + '@storybook/addon-interactions@8.6.2': + resolution: {integrity: sha512-9wv3TX9eupJfzubKbt6f9Z+VtrL6VOIkEKBJN/wifnHBgTHM3DsizerZX/7YKHdFbz6eJFr6efvaSWQ8CIvTNA==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-links@8.5.8': - resolution: {integrity: sha512-nLfcWhqDCTaEB/zPjzdN+FtsJ3WnvrRE7Uq+UZHF/HDqt7EXicUYCnbzHIF6ReyNBFklr48O/RhotDu9cyUDlw==} + '@storybook/addon-links@8.6.2': + resolution: {integrity: sha512-/7ARtUZ0lCEbAiaE5z+tXxrTHiUgSuPXK7yx9Vnekba68vOBLmxVEqw05tZGikzIm4sFi3dpH3iKT325wAYDmg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.5.8 + storybook: ^8.6.2 peerDependenciesMeta: react: optional: true - '@storybook/addon-mdx-gfm@8.5.8': - resolution: {integrity: sha512-jUq2CsZnSqIHpbMfsV4P+H+UTdvekYAb1paB5xRFEEj53WFKKAnc51VCY3yJ/Jwn/NuicDOXHM/GHLp/+1cr/w==} + '@storybook/addon-mdx-gfm@8.6.2': + resolution: {integrity: sha512-ZTtEJFuDw0+Ym5e1YpheziNQTRpkdGFjVxQT5g8PPosMRDuniOPpniaA3b9PXdvsP1zm+KiuhF3ajMNRU4uJWQ==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-measure@8.5.8': - resolution: {integrity: sha512-xf84ByTRkFPoNSck6Z5OJ0kXTYAYgmg/0Ke0eCY/CNgwh7lfjYQBrcjuKiYZ6jyRUMLdysXzIfF9/2MeFqLfIg==} + '@storybook/addon-measure@8.6.2': + resolution: {integrity: sha512-qNzR8yj/g2FRRLBwTreGqeUR5ZcXpkhcdndWlf5rnxp97BDbPnGNCvaI9vhHS3GbjZ+C1FE+yG3o70O5Rhh7Ag==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-outline@8.5.8': - resolution: {integrity: sha512-NAC9VWZFg2gwvduzJRVAtxPeQfJjB8xfDDgcGjgLOCSQkZDDOmGVdLXf78pykMQKyuu/0YZ989KufAac6kRG5g==} + '@storybook/addon-outline@8.6.2': + resolution: {integrity: sha512-lgDCOkOLoehat4APUbKpAA7CBwXtxrRRK91hNBI3prUUBex6ML9jXWcuTDsGTrkilRkLOT7kN6H0DGj5rH/H9Q==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-storysource@8.5.8': - resolution: {integrity: sha512-AbtdMbZ/1hpemJZypRilhzifcEvs0xVhV21CgOmYXz87N1cRkJ/bb2t2aclgdPwfOUE/reQ6r2X7HGeOWcWM9w==} + '@storybook/addon-storysource@8.6.2': + resolution: {integrity: sha512-1psIeoftkw8F/f7wECMJZifs4nvuPpOAJ4rR8dCx4V45fPgKdeRcWO9J36i/a4K/xcQjs5FGLGS6IM1puM8Viw==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-toolbars@8.5.8': - resolution: {integrity: sha512-AfGdMNBp+vOjyiFKlOyUFLIU0kN1QF4PhVBqd0vYkWAk2w9n6a/ZlG0TcJGe7K5+bcvmZDAerYMKbDMSeg9bAw==} + '@storybook/addon-toolbars@8.6.2': + resolution: {integrity: sha512-rfUSMacIfGwPoYYeVro+3I5C3qNy0MgB+qJ16ejuTLTlx4ji0icAOckILmPmhIT577KqIQBo1R2sB+oMVzK9+w==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/addon-viewport@8.5.8': - resolution: {integrity: sha512-SdoRb4bH99Knj2R+rTcMQQxHrtcIO1GLzTFitAefxBE1OUkq8FNLHMHd0Ip/sCQGLW/5F03U70R2uh7SkhBBYA==} + '@storybook/addon-viewport@8.6.2': + resolution: {integrity: sha512-znUIG808UEEfF5Gg+T478ixblBwEebeOYaKLD7yfxKwL2TMTmaIq4DXPESqV9M1lBcy3UrBWrPG9mzvq4PKMxA==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/blocks@8.5.8': - resolution: {integrity: sha512-O6tJDJM83fDm3ZP1+lTf24l7HOTzSRXkkMDD7zB/JHixzlj9p6wI4UQc2lplLadDCa5ya1IwyE7zUDN/0UfC5Q==} + '@storybook/blocks@8.6.2': + resolution: {integrity: sha512-yYskHxUDJcBcRRSTZ95agqO3gZ4gLK9/1QZvANa6+Hb23Z5tGpNDHzLFGZePUJGRBqPPaNraay+SCI1LBY3/yw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - storybook: ^8.5.8 + storybook: ^8.6.2 peerDependenciesMeta: react: optional: true react-dom: optional: true - '@storybook/builder-vite@8.5.8': - resolution: {integrity: sha512-nm07wXP4MN7HlWqLRomSFHibwrwiY7V4kTohgsXSjTUod0J+xY+XvmkM4YRK2QYcUgVesG+Q2q3Q5NHof07sfg==} + '@storybook/builder-vite@8.6.2': + resolution: {integrity: sha512-FE52FnGJhRqxLA9FVtS0fiNI5XfIjuewPlSWYviMJ5JcR/OfHUI3s97IBi/tDgeVcktDCjzMOC63YdYTest68A==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 vite: ^4.0.0 || ^5.0.0 || ^6.0.0 - '@storybook/components@8.5.8': - resolution: {integrity: sha512-PPEMqWPXn7rX+qISaOOv9CDSuuvG538f0+4M5Ppq2LwpjXecgOG5ktqJF0ZqxmTytT+RpEaJmgjGW0dMAKZswA==} + '@storybook/components@8.6.2': + resolution: {integrity: sha512-tPEgj40YMkIE8KfElh5gf3s/B/KOcFKBpf6k7Nn3wZAu+dSifrGNyU33lecHjfkRHO/ZK1QYF7kIkCkPu/SKQA==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core-events@8.5.8': - resolution: {integrity: sha512-yjzDgoErmzzkesA7goiAi4zi4dMSZAS9KVoRwjIyW/w/uzldLJmp+EIg7pHRtZPDsNYGwEiHfsHIz/hwYCgaHA==} + '@storybook/core-events@8.6.2': + resolution: {integrity: sha512-zkQeiYUe+ChgcYifYGwAwZ36QPMiynul8Q+yFEDHkGgcOm/MNlGfbibHoLUfhVZu2xh5Vk8f85hkNllcRlzztA==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/core@8.5.8': - resolution: {integrity: sha512-OT02DQhkGpBgn5P+nZOZmbzxqubC4liVqbhpjp/HOGi5cOA3+fCJzDJeSDTu+pPh7dZnopC4XnR+5dWjtOJHdA==} + '@storybook/core@8.6.2': + resolution: {integrity: sha512-i8a/nUuzzH5RLKjPn8DM7l8xxuTdLZ6xbI4hgpruas3JY8lQq72I7qmH6pmI7ByjGangDWK1iPh+tghdKkS6KQ==} peerDependencies: prettier: ^2 || ^3 peerDependenciesMeta: prettier: optional: true - '@storybook/csf-plugin@8.5.8': - resolution: {integrity: sha512-9p+TFutbvtPYEmg14UsvqBDWKP/p/+OkIdi+gkwCMw0yiJF/+7ErMHDB0vr5SpJpU7SFQmfpY2c/LaglEtaniw==} + '@storybook/csf-plugin@8.6.2': + resolution: {integrity: sha512-YqvtCTzAn4EJ+Da+QcY6oeGxrybeHohRiPwYN6gjGQOgRj0acp5CJakH9Nz/0/U3BaXrf+5YtfTEM+SWhlRROw==} peerDependencies: - storybook: ^8.5.8 - - '@storybook/csf@0.1.12': - resolution: {integrity: sha512-9/exVhabisyIVL0VxTCxo01Tdm8wefIXKXfltAPTSr8cbLn5JAxGQ6QV3mjdecLGEOucfoVhAKtJfVHxEK1iqw==} + storybook: ^8.6.2 '@storybook/global@5.0.0': resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} @@ -3897,49 +3744,49 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@storybook/instrumenter@8.5.8': - resolution: {integrity: sha512-+d5bbnwqcSQlj0wkZo6/1b+8rge70EU2wTq14DO22/VSXa9nm3bwPJlEyqBT7laWmC4DJQWHVJwF/790KjT9yg==} + '@storybook/instrumenter@8.6.2': + resolution: {integrity: sha512-26z5KiAhS/j0DzPwpT08/JZ1Uy2D9TQOiD6pZ8f6H1UJyPhAuctJqAfMCC0rTAKBIWeA5KKxBbjd+lhiMsusRA==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/manager-api@8.5.8': - resolution: {integrity: sha512-ik3yikvYxAJMDFg0s3Pm7hZWucAlkFaaO7e2RlfOctaJFdaEi3evR4RS7GdmS38uKBEk31RC7x+nnIJkqEC59A==} + '@storybook/manager-api@8.6.2': + resolution: {integrity: sha512-75yx3xSDRU1B4dsf2OSJev7VAvR+6SjWUExENmMGXa0PpoO0MBZqMKdIufKMPsRtw77ugKGfS04MWt4yc5lgRQ==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/preview-api@8.5.8': - resolution: {integrity: sha512-HJoz2o28VVprnU5OG6JO6CHrD3ah6qVPWixbnmyUKd0hOYF5dayK5ptmeLyUpYX56Eb2KoYcuVaeQqAby4RkNw==} + '@storybook/preview-api@8.6.2': + resolution: {integrity: sha512-hkKmQ9OWlCpS2mHYsuWTbXMfeLx90fiWdUblTBIUQnj8VLhSbNtmeBZdZRkz33uYHFkAqZ3F2nQ9I2iTv8AmwA==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/react-dom-shim@8.5.8': - resolution: {integrity: sha512-UT/kGJHPW+HLNCTmI1rV1to+dUZuXKUTaRv2wZ2BUq2/gjIuePyqQZYVQeb0LkZbuH2uviLrPfXpS5d3/RSUJw==} + '@storybook/react-dom-shim@8.6.2': + resolution: {integrity: sha512-8VTAaYtvtP3dx9AXk2lMTQ/o/hTBpL/a6C48JYWhfbU1UO6O0B4PUGADFJ8XWzobXRkTm7CR3RGLzA2oYgWxdA==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/react-vite@8.5.8': - resolution: {integrity: sha512-Fa3WjqMsY/52p8IHX52IofbvQpoh88cFA/SQ8Q6RUGCNvUVYG/l025pBYbm+PhAkKDQXTirRul9CwA66gGR9zA==} + '@storybook/react-vite@8.6.2': + resolution: {integrity: sha512-cj5B/mJuscMJPUx+6UgOFIivoY1RyZQDqluPo97qXY6eR5IRB9z/j1chv68BQUDAcjXCS02xTf9Kh5YcVreiIA==} engines: {node: '>=18.0.0'} peerDependencies: - '@storybook/test': 8.5.8 + '@storybook/test': 8.6.2 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.5.8 + storybook: ^8.6.2 vite: ^4.0.0 || ^5.0.0 || ^6.0.0 peerDependenciesMeta: '@storybook/test': optional: true - '@storybook/react@8.5.8': - resolution: {integrity: sha512-QYgKpInR2FLiJHsRoGKCzNhKTRNjOssbLZVd3B0ZABUee+AjkwE0Pey7x2XaNAcp9PxSjQXEPGu+DlaP4BWw2Q==} + '@storybook/react@8.6.2': + resolution: {integrity: sha512-f6mS9nydU2KGY3nIvu4WVUFmJNEjzmFLj86iznO9CK/pELH53e4RjuzXgIqfWIGxBpR0QyFMdwyWjaOB5ZKr7Q==} engines: {node: '>=18.0.0'} peerDependencies: - '@storybook/test': 8.5.8 + '@storybook/test': 8.6.2 react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta - storybook: ^8.5.8 + storybook: ^8.6.2 typescript: '>= 4.2.x' peerDependenciesMeta: '@storybook/test': @@ -3947,38 +3794,38 @@ packages: typescript: optional: true - '@storybook/source-loader@8.5.8': - resolution: {integrity: sha512-qbCGFoUrm15wF5+G1b5Rkrkt7ACN53MO05p3L8pUHT3WX1FQ7KEYmBPERRJB7oZ6wM0nnfkHDEQnovHSwu7RAQ==} + '@storybook/source-loader@8.6.2': + resolution: {integrity: sha512-0E/Nv7AV3f3VeR25NLN47F3oM4CuzPHjv3Tp7DSsP3x3VuQHZGZfjGL3Weh4UppuhTVYzdV8fyqVyQbEVwNssQ==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/test@8.5.8': - resolution: {integrity: sha512-cpdl9Vk4msRnkINwwSNLklyWXOwAsLAA7JsHMICNPR2GFVc8T+TwZHATcRToCHXhFJTZBMMBYrnqCdD5C2Kr3g==} + '@storybook/test@8.6.2': + resolution: {integrity: sha512-9GgLzIqYrHwpfffp43KJR9WIx3LkXIuej9BvSZk/KBWeBbOgqDbHG4CqC8P6uRl994RC91K85vdeRhAShkdtkA==} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 - '@storybook/theming@8.5.8': - resolution: {integrity: sha512-/Rm6BV778sCT+3Ok861VYmw9BlEV5zcCq2zg5TOVuk8HqZw7H7VHtubVsjukEuhveYCs+oF+i2tv/II6jh6jdg==} + '@storybook/theming@8.6.2': + resolution: {integrity: sha512-NF7tMZBbmh6rNf+uw5wVUpsVIwnbhLgauhQJONuQ8i+cI6cJEBaKjIC2uMWUBABqnj1LqGrHSEWVeeYwuAeUYg==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/types@8.5.8': - resolution: {integrity: sha512-XAXi5w+mG8v8m8FFNPE0uDJb5ms39oU+HDOb6hYOYVOt4ezQkKI3g45T9qlqKfdR9rK22zB9JGUYpDir+O7zeA==} + '@storybook/types@8.6.2': + resolution: {integrity: sha512-wSnM7hR81W1koi4Hk9m8ASwrMVpw0naIgIcAJbk+pTxYZnSutG8GAIo4DjDTLWzDnpqG4FL6AL/apGmrxCg+eQ==} peerDependencies: storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0 - '@storybook/vue3-vite@8.5.8': - resolution: {integrity: sha512-bq7y5is0Yvr8GZEL3fiTDLfZ5PF+X9YUAGlkDxvxMywwvMJt1Rh6PQ9RKGFpK4c/iM7I6f/DxjmP8y/pIQIs5g==} + '@storybook/vue3-vite@8.6.2': + resolution: {integrity: sha512-ASr6IHwmlfeQboUdCe/26hGKtRyagkGO9wNQt+CzlZGOk4/05RxrRkCXkhZmvOXR8imSS+IEQ5dp3ipm9VR+Qw==} engines: {node: '>=18.0.0'} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 vite: ^4.0.0 || ^5.0.0 || ^6.0.0 - '@storybook/vue3@8.5.8': - resolution: {integrity: sha512-CI/WX6AcVJgG+q8kw4bEoa44FXEfunFkZIOaBUubckUi7hMFyleSFikAUWyGFv90bN2QXTCU72FnwclQEGX7NA==} + '@storybook/vue3@8.6.2': + resolution: {integrity: sha512-kR7xWdk4LmcKjGK4Ba25ZIzpZT8XfKGWelriwsu94ZKQ3uXuuoBeKi4L0UkVI54BoG07MEZCZ6apkwyRIDENHw==} engines: {node: '>=18.0.0'} peerDependencies: - storybook: ^8.5.8 + storybook: ^8.6.2 vue: ^3.0.0 '@stylistic/eslint-plugin@2.13.0': @@ -4361,9 +4208,6 @@ packages: '@types/node@22.13.4': resolution: {integrity: sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg==} - '@types/node@22.13.5': - resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} - '@types/node@22.13.7': resolution: {integrity: sha512-oU2q+BsQldB9lYxHNp/5aZO+/Bs0Usa74Abo9mAKulz4ahQyXRHK6UVKYIN8KSC8HXwhWSi7b49JnX+txuac0w==} @@ -4528,14 +4372,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/eslint-plugin@8.24.1': - resolution: {integrity: sha512-ll1StnKtBigWIGqvYDVuDmXJHVH4zLVot1yQ4fJtLpL7qacwkxJc1T0bptqw+miBQ/QfUbhl1TcQ4accW5KUyA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/eslint-plugin@8.25.0': resolution: {integrity: sha512-VM7bpzAe7JO/BFf40pIT1lJqS/z1F8OaSsUB3rpFJucQA4cOSuH2RVVVkFULN+En0Djgr29/jb4EQnedUo95KA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4551,13 +4387,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/parser@8.24.1': - resolution: {integrity: sha512-Tqoa05bu+t5s8CTZFaGpCH2ub3QeT9YDkXbPd3uQ4SfsLoh1/vv2GEYAioPoxCWJJNsenXlC88tRjwoHNts1oQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/parser@8.25.0': resolution: {integrity: sha512-4gbs64bnbSzu4FpgMiQ1A+D+urxkoJk/kqlDJ2W//5SygaEiAP2B4GoS7TEdxgwol2el03gckFV9lJ4QOMiiHg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4569,10 +4398,6 @@ packages: resolution: {integrity: sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.24.1': - resolution: {integrity: sha512-OdQr6BNBzwRjNEXMQyaGyZzgg7wzjYKfX2ZBV3E04hUCBDv3GQCHiz9RpqdUIiVrMgJGkXm3tcEh4vFSHreS2Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.25.0': resolution: {integrity: sha512-6PPeiKIGbgStEyt4NNXa2ru5pMzQ8OYKO1hX1z53HMomrmiSB+R5FmChgQAP1ro8jMtNawz+TRQo/cSXrauTpg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4584,13 +4409,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/type-utils@8.24.1': - resolution: {integrity: sha512-/Do9fmNgCsQ+K4rCz0STI7lYB4phTtEXqqCAs3gZW0pnK7lWNkvWd5iW545GSmApm4AzmQXmSqXPO565B4WVrw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/type-utils@8.25.0': resolution: {integrity: sha512-d77dHgHWnxmXOPJuDWO4FDWADmGQkN5+tt6SFRZz/RtCWl4pHgFl3+WdYCn16+3teG09DY6XtEpf3gGD0a186g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4602,10 +4420,6 @@ packages: resolution: {integrity: sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.24.1': - resolution: {integrity: sha512-9kqJ+2DkUXiuhoiYIUvIYjGcwle8pcPpdlfkemGvTObzgmYfJ5d0Qm6jwb4NBXP9W1I5tss0VIAnWFumz3mC5A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.25.0': resolution: {integrity: sha512-+vUe0Zb4tkNgznQwicsvLUJgZIRs6ITeWSCclX1q85pR1iOiaj+4uZJIUp//Z27QWu5Cseiw3O3AR8hVpax7Aw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4616,12 +4430,6 @@ packages: peerDependencies: typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/typescript-estree@8.24.1': - resolution: {integrity: sha512-UPyy4MJ/0RE648DSKQe9g0VDSehPINiejjA6ElqnFaFIhI6ZEiZAkUI0D5MCk0bQcTf/LVqZStvQ6K4lPn/BRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/typescript-estree@8.25.0': resolution: {integrity: sha512-ZPaiAKEZ6Blt/TPAx5Ot0EIB/yGtLI2EsGoY6F7XKklfMxYQyvtL+gT/UCqkMzO0BVFHLDlzvFqQzurYahxv9Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4635,13 +4443,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.24.1': - resolution: {integrity: sha512-OOcg3PMMQx9EXspId5iktsI3eMaXVwlhC8BvNnX6B5w9a4dVgpkQZuU8Hy67TolKcl+iFWq0XX+jbDGN4xWxjQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <5.8.0' - '@typescript-eslint/utils@8.25.0': resolution: {integrity: sha512-syqRbrEv0J1wywiLsK60XzHnQe/kRViI3zwFALrNEgnntn1l24Ra2KvOAWwWbWZ1lBZxZljPDGOq967dsl6fkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4653,10 +4454,6 @@ packages: resolution: {integrity: sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.24.1': - resolution: {integrity: sha512-EwVHlp5l+2vp8CoqJm9KikPZgi3gbdZAtabKT9KPShGeOcJhsv4Zdo3oc8T8I0uKEmYoU4ItyxbptjF08enaxg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.25.0': resolution: {integrity: sha512-kCYXKAum9CecGVHGij7muybDfTS2sD3t0L4bJsEZLkyrXUImiCTq1M3LG2SRtOhiHFwMR9wAFplpT6XHYjTkwQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4671,11 +4468,11 @@ packages: vite: ^5.0.0 || ^6.0.0 vue: ^3.2.25 - '@vitest/coverage-v8@3.0.6': - resolution: {integrity: sha512-JRTlR8Bw+4BcmVTICa7tJsxqphAktakiLsAmibVLAWbu1lauFddY/tXeM6sAyl1cgkPuXtpnUgaCPhTdz1Qapg==} + '@vitest/coverage-v8@3.0.7': + resolution: {integrity: sha512-Av8WgBJLTrfLOer0uy3CxjlVuWK4CzcLBndW1Nm2vI+3hZ2ozHututkfc7Blu1u6waeQ7J8gzPK/AsBRnWA5mQ==} peerDependencies: - '@vitest/browser': 3.0.6 - vitest: 3.0.6 + '@vitest/browser': 3.0.7 + vitest: 3.0.7 peerDependenciesMeta: '@vitest/browser': optional: true @@ -4683,11 +4480,11 @@ packages: '@vitest/expect@2.0.5': resolution: {integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==} - '@vitest/expect@3.0.6': - resolution: {integrity: sha512-zBduHf/ja7/QRX4HdP1DSq5XrPgdN+jzLOwaTq/0qZjYfgETNFCKf9nOAp2j3hmom3oTbczuUzrzg9Hafh7hNg==} + '@vitest/expect@3.0.7': + resolution: {integrity: sha512-QP25f+YJhzPfHrHfYHtvRn+uvkCFCqFtW9CktfBxmB+25QqWsx7VB2As6f4GmwllHLDhXNHvqedwhvMmSnNmjw==} - '@vitest/mocker@3.0.6': - resolution: {integrity: sha512-KPztr4/tn7qDGZfqlSPQoF2VgJcKxnDNhmfR3VgZ6Fy1bO8T9Fc1stUiTXtqz0yG24VpD00pZP5f8EOFknjNuQ==} + '@vitest/mocker@3.0.7': + resolution: {integrity: sha512-qui+3BLz9Eonx4EAuR/i+QlCX6AUZ35taDQgwGkK/Tw6/WgwodSrjN1X2xf69IA/643ZX5zNKIn2svvtZDrs4w==} peerDependencies: msw: ^2.4.9 vite: ^5.0.0 || ^6.0.0 @@ -4703,20 +4500,20 @@ packages: '@vitest/pretty-format@2.1.1': resolution: {integrity: sha512-SjxPFOtuINDUW8/UkElJYQSFtnWX7tMksSGW0vfjxMneFqxVr8YJ979QpMbDW7g+BIiq88RAGDjf7en6rvLPPQ==} - '@vitest/pretty-format@3.0.6': - resolution: {integrity: sha512-Zyctv3dbNL+67qtHfRnUE/k8qxduOamRfAL1BurEIQSyOEFffoMvx2pnDSSbKAAVxY0Ej2J/GH2dQKI0W2JyVg==} + '@vitest/pretty-format@3.0.7': + resolution: {integrity: sha512-CiRY0BViD/V8uwuEzz9Yapyao+M9M008/9oMOSQydwbwb+CMokEq3XVaF3XK/VWaOK0Jm9z7ENhybg70Gtxsmg==} - '@vitest/runner@3.0.6': - resolution: {integrity: sha512-JopP4m/jGoaG1+CBqubV/5VMbi7L+NQCJTu1J1Pf6YaUbk7bZtaq5CX7p+8sY64Sjn1UQ1XJparHfcvTTdu9cA==} + '@vitest/runner@3.0.7': + resolution: {integrity: sha512-WeEl38Z0S2ZcuRTeyYqaZtm4e26tq6ZFqh5y8YD9YxfWuu0OFiGFUbnxNynwLjNRHPsXyee2M9tV7YxOTPZl2g==} - '@vitest/snapshot@3.0.6': - resolution: {integrity: sha512-qKSmxNQwT60kNwwJHMVwavvZsMGXWmngD023OHSgn873pV0lylK7dwBTfYP7e4URy5NiBCHHiQGA9DHkYkqRqg==} + '@vitest/snapshot@3.0.7': + resolution: {integrity: sha512-eqTUryJWQN0Rtf5yqCGTQWsCFOQe4eNz5Twsu21xYEcnFJtMU5XvmG0vgebhdLlrHQTSq5p8vWHJIeJQV8ovsA==} '@vitest/spy@2.0.5': resolution: {integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==} - '@vitest/spy@3.0.6': - resolution: {integrity: sha512-HfOGx/bXtjy24fDlTOpgiAEJbRfFxoX3zIGagCqACkFKKZ/TTOE6gYMKXlqecvxEndKFuNHcHqP081ggZ2yM0Q==} + '@vitest/spy@3.0.7': + resolution: {integrity: sha512-4T4WcsibB0B6hrKdAZTM37ekuyFZt2cGbEGd2+L0P8ov15J1/HUsUaqkXEQPNAWr4BtPPe1gI+FYfMHhEKfR8w==} '@vitest/utils@2.0.5': resolution: {integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==} @@ -4724,8 +4521,8 @@ packages: '@vitest/utils@2.1.1': resolution: {integrity: sha512-Y6Q9TsI+qJ2CC0ZKj6VBb+T8UPz593N113nnUykqwANqhgf3QkZeHFlusgKLTqrnVHbj/XDKZcDHol+dxVT+rQ==} - '@vitest/utils@3.0.6': - resolution: {integrity: sha512-18ktZpf4GQFTbf9jK543uspU03Q2qya7ZGya5yiZ0Gx0nnnalBvd5ZBislbl2EhLjM8A8rt4OilqKG7QwcGkvQ==} + '@vitest/utils@3.0.7': + resolution: {integrity: sha512-xePVpCRfooFX3rANQjwoditoXgWb1MaFbzmGuPP59MK6i13mrnDw/yEIyJudLeW6/38mCNcwCiJIGmpDPibAIg==} '@volar/language-core@2.2.0': resolution: {integrity: sha512-a8WG9+4OdeNDW4ywABZIM6S6UN7em8uIlM/BZ2pWQUYrVmX+m8sj/X+QadvO+Li/t/LjAqbWJQtVgxdpEWLALQ==} @@ -5493,8 +5290,8 @@ packages: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} - chromatic@11.25.2: - resolution: {integrity: sha512-/9eQWn6BU1iFsop86t8Au21IksTRxwXAl7if8YHD05L2AbuMjClLWZo5cZojqrJHGKDhTqfrC2X2xE4uSm0iKw==} + chromatic@11.26.1: + resolution: {integrity: sha512-kVMTigrKI7TOOV04i1lTTIVJsmQ+fj6ZFXyZ3LcdCioOrxO/zCVB1y74iX0iKS++cpi3bJcG+UszkmvptGDEuA==} hasBin: true peerDependencies: '@chromatic-com/cypress': ^0.*.* || ^1.0.0 @@ -5810,6 +5607,11 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + cypress@14.1.0: + resolution: {integrity: sha512-pPPj8Uu9NwjaaiXAEcjYZZmgsq6v9Zs1Nw6a+zRF+ANgYSNhH4S32SjFRsvMcuOHR/8dp4GBJhBPqIPSs+TxaA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + dashdash@1.14.1: resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} engines: {node: '>=0.10'} @@ -6240,11 +6042,6 @@ packages: peerDependencies: esbuild: '>=0.12 <1' - esbuild@0.24.2: - resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.25.0: resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} engines: {node: '>=18'} @@ -6898,8 +6695,8 @@ packages: resolution: {integrity: sha512-n0QrmT9lD81rbpKsyhnlz3DgnMZlaOkJPpgi746doA+HvaMC79bdWkwjrNnGJRvDrWTI8iOcJiVTJ5CdT/AZRw==} engines: {node: '>=18.0.0'} - happy-dom@17.1.4: - resolution: {integrity: sha512-cMxE0HP45kLIgWdI0PFfnitNb95Cv8kG8moqI7CK6kcEcfV7xoYVVvSmJ7EuGfDatSKWtjhG/czVooqEV0L4rA==} + happy-dom@17.1.8: + resolution: {integrity: sha512-Yxbq/FG79z1rhAf/iB6YM8wO2JB/JDQBy99RiLSs+2siEAi5J05x9eW1nnASHZJbpldjJE2KuFLsLZ+AzX/IxA==} engines: {node: '>=18.0.0'} hard-rejection@2.1.0: @@ -6965,8 +6762,8 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hast-util-to-html@9.0.4: - resolution: {integrity: sha512-wxQzXtdbhiwGAUKrnQJXlOPmHnEehzphwkK7aluUPQ+lEc1xefC8pblMgpp2w5ldBTEfveRIrADcrhGIWrlTDA==} + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} @@ -8273,8 +8070,8 @@ packages: peerDependencies: msw: ^2.0.0 - msw@2.7.1: - resolution: {integrity: sha512-TVT65uoWt9LE4lMTLBdClHBQVwvZv5ofac1YyE119nCrNyXf4ktdeVnWH9Fyt94Ifmiedhw6Npp4DSuVRSuRpw==} + msw@2.7.3: + resolution: {integrity: sha512-+mycXv8l2fEAjFZ5sjrtjJDmm2ceKGjrNbBr1durRg6VkU9fNUE/gsmQ51hWbHqs+l35W1iM+ZsmOD9Fd6lspw==} engines: {node: '>=18'} hasBin: true peerDependencies: @@ -8557,8 +8354,8 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} - oniguruma-to-es@3.1.0: - resolution: {integrity: sha512-BJ3Jy22YlgejHSO7Fvmz1kKazlaPmRSUH+4adTDUS/dKQ4wLxI+gALZ8updbaux7/m7fIlpgOZ5fp/Inq5jUAw==} + oniguruma-to-es@3.1.1: + resolution: {integrity: sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==} open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} @@ -9035,6 +8832,10 @@ packages: resolution: {integrity: sha512-MjOadfU3Ys9KYoX0AdkBlFEF1Vx37uCCeN4ZHnmwm9FfpbsGWMZeBLMmmpY+6Ocqod7mkdZ0DT31OlbsFrLlkA==} engines: {node: ^10 || ^12 || >=14} + postcss@8.5.3: + resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + engines: {node: ^10 || ^12 || >=14} + postgres-array@2.0.0: resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} engines: {node: '>=4'} @@ -9149,8 +8950,8 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - property-information@6.5.0: - resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + property-information@7.0.0: + resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -9555,8 +9356,8 @@ packages: sanitize-html@2.14.0: resolution: {integrity: sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g==} - sass@1.85.0: - resolution: {integrity: sha512-3ToiC1xZ1Y8aU7+CkgCI/tqyuPXEmYGJXO7H4uqp0xkLXUqp88rQQ4j1HmP37xSJLbCJPaIiv+cT1y+grssrww==} + sass@1.85.1: + resolution: {integrity: sha512-Uk8WpxM5v+0cMR0XjX9KfRIacmSG86RH4DCCZjLU2rFh5tyutt9siAXJ7G+YfxQ99Q6wrRMbMlVl6KqUms71ag==} engines: {node: '>=14.0.0'} hasBin: true @@ -9658,8 +9459,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@3.0.0: - resolution: {integrity: sha512-x6MMdYN9auPGx7kMFtyKbaj65eCdetfrfkvQZwqisZLnGMnAZsZxOpcWD0ElvLPFWHOSMukVyN9Opm7TxQjnZA==} + shiki@3.1.0: + resolution: {integrity: sha512-LdTNyWQlC5zdCaHdcp1zPA1OVA2ivb+KjGOOnGcy02tGaF5ja+dGibWFH7Ar8YlngUgK/scDqworK18Ys9cbYA==} shimmer@1.2.1: resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} @@ -9927,8 +9728,8 @@ packages: react-dom: optional: true - storybook@8.5.8: - resolution: {integrity: sha512-k3QDa7z4a656oO3Mx929KNm+xIdEI2nIDCKatVl1mA6vt+ge+uwoiG+ro182J9LOEppR5XXD2mQQi4u1xNsy6A==} + storybook@8.6.2: + resolution: {integrity: sha512-IkQGRNImyN14+tx/9KLg9k5xKBgrkWaPFhfwTCxUZUzLNClbVrxkkXyjFaks9kPVQIEUVPGQCiGFqypUiwoM6g==} hasBin: true peerDependencies: prettier: ^2 || ^3 @@ -10152,8 +9953,8 @@ packages: thread-stream@3.1.0: resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} - three@0.173.0: - resolution: {integrity: sha512-AUwVmViIEUgBwxJJ7stnF0NkPpZxx1aZ6WiAbQ/Qq61h6I9UR4grXtZDmO8mnlaNORhHnIBlXJ1uBxILEKuVyw==} + three@0.174.0: + resolution: {integrity: sha512-p+WG3W6Ov74alh3geCMkGK9NWuT62ee21cV3jEnun201zodVF4tCE5aZa2U122/mkLRmhJJUQmLLW1BH00uQJQ==} throttle-debounce@5.0.2: resolution: {integrity: sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A==} @@ -10286,6 +10087,10 @@ packages: resolution: {integrity: sha512-Ibv4KAWfFkFdKJxnWfVtdOmB0Zi1RJVxcbPGiCDsFpCQSsmpWyuzHG3rQyI5YkobWwxFPEyQfu1hdo4qLG2zPw==} hasBin: true + tsc-alias@1.8.11: + resolution: {integrity: sha512-2DuEQ58A9Rj2NE2c1+/qaGKlshni9MCK95MJzRGhQG0CYLw0bE/ACgbhhTSf/p1svLelwqafOd8stQate2bYbg==} + hasBin: true + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -10626,16 +10431,16 @@ packages: vfile@6.0.1: resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} - vite-node@3.0.6: - resolution: {integrity: sha512-s51RzrTkXKJrhNbUzQRsarjmAae7VmMPAsRT7lppVpIg6mK3zGthP9Hgz0YQQKuNcF+Ii7DfYk3Fxz40jRmePw==} + vite-node@3.0.7: + resolution: {integrity: sha512-2fX0QwX4GkkkpULXdT1Pf4q0tC1i1lFOyseKoonavXUNlQ77KpW2XqBGGNIm/J4Ows4KxgGJzDguYVPKwG/n5A==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true vite-plugin-turbosnap@1.0.3: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} - vite@6.1.1: - resolution: {integrity: sha512-4GgM54XrwRfrOp297aIYspIti66k56v16ZnqHvrIM7mG+HjDlAwS7p+Srr7J6fGvEdOJ5JcQ/D9T7HhtdXDTzA==} + vite@6.2.0: + resolution: {integrity: sha512-7dPxoo+WsT/64rDcwoOjk76XHj+TqNTIvHKcuMQ1k4/SeHDaQt5GFAeLYzrimZrMpn/O6DtdI03WUjdxuPM0oQ==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: @@ -10674,22 +10479,22 @@ packages: yaml: optional: true - vitest-fetch-mock@0.4.3: - resolution: {integrity: sha512-PhuEh+9HCsXFMRPUJilDL7yVDFufoxqk7ze+CNks64UGlfFXaJTn1bLABiNlEc0u25RERXQGj0Tm+M9i6UY9HQ==} + vitest-fetch-mock@0.4.4: + resolution: {integrity: sha512-i2RNEAKBgnLWwj5DVz8ouzaHaPVg1xaYgAUmU5p+baJ149upnO+yJLPchAiY9ij8hf0PDkJVVke1pftBxmT05g==} engines: {node: '>=18.0.0'} peerDependencies: vitest: '>=2.0.0' - vitest@3.0.6: - resolution: {integrity: sha512-/iL1Sc5VeDZKPDe58oGK4HUFLhw6b5XdY1MYawjuSaDA4sEfYlY9HnS6aCEG26fX+MgUi7MwlduTBHHAI/OvMA==} + vitest@3.0.7: + resolution: {integrity: sha512-IP7gPK3LS3Fvn44x30X1dM9vtawm0aesAa2yBIZ9vQf+qB69NXC5776+Qmcr7ohUXIQuLhk7xQR0aSUIDPqavg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/debug': ^4.1.12 '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.0.6 - '@vitest/ui': 3.0.6 + '@vitest/browser': 3.0.7 + '@vitest/ui': 3.0.7 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -12033,153 +11838,78 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.24.2': - optional: true - '@esbuild/aix-ppc64@0.25.0': optional: true - '@esbuild/android-arm64@0.24.2': - optional: true - '@esbuild/android-arm64@0.25.0': optional: true - '@esbuild/android-arm@0.24.2': - optional: true - '@esbuild/android-arm@0.25.0': optional: true - '@esbuild/android-x64@0.24.2': - optional: true - '@esbuild/android-x64@0.25.0': optional: true - '@esbuild/darwin-arm64@0.24.2': - optional: true - '@esbuild/darwin-arm64@0.25.0': optional: true - '@esbuild/darwin-x64@0.24.2': - optional: true - '@esbuild/darwin-x64@0.25.0': optional: true - '@esbuild/freebsd-arm64@0.24.2': - optional: true - '@esbuild/freebsd-arm64@0.25.0': optional: true - '@esbuild/freebsd-x64@0.24.2': - optional: true - '@esbuild/freebsd-x64@0.25.0': optional: true - '@esbuild/linux-arm64@0.24.2': - optional: true - '@esbuild/linux-arm64@0.25.0': optional: true - '@esbuild/linux-arm@0.24.2': - optional: true - '@esbuild/linux-arm@0.25.0': optional: true - '@esbuild/linux-ia32@0.24.2': - optional: true - '@esbuild/linux-ia32@0.25.0': optional: true - '@esbuild/linux-loong64@0.24.2': - optional: true - '@esbuild/linux-loong64@0.25.0': optional: true - '@esbuild/linux-mips64el@0.24.2': - optional: true - '@esbuild/linux-mips64el@0.25.0': optional: true - '@esbuild/linux-ppc64@0.24.2': - optional: true - '@esbuild/linux-ppc64@0.25.0': optional: true - '@esbuild/linux-riscv64@0.24.2': - optional: true - '@esbuild/linux-riscv64@0.25.0': optional: true - '@esbuild/linux-s390x@0.24.2': - optional: true - '@esbuild/linux-s390x@0.25.0': optional: true - '@esbuild/linux-x64@0.24.2': - optional: true - '@esbuild/linux-x64@0.25.0': optional: true - '@esbuild/netbsd-arm64@0.24.2': - optional: true - '@esbuild/netbsd-arm64@0.25.0': optional: true - '@esbuild/netbsd-x64@0.24.2': - optional: true - '@esbuild/netbsd-x64@0.25.0': optional: true - '@esbuild/openbsd-arm64@0.24.2': - optional: true - '@esbuild/openbsd-arm64@0.25.0': optional: true - '@esbuild/openbsd-x64@0.24.2': - optional: true - '@esbuild/openbsd-x64@0.25.0': optional: true - '@esbuild/sunos-x64@0.24.2': - optional: true - '@esbuild/sunos-x64@0.25.0': optional: true - '@esbuild/win32-arm64@0.24.2': - optional: true - '@esbuild/win32-arm64@0.25.0': optional: true - '@esbuild/win32-ia32@0.24.2': - optional: true - '@esbuild/win32-ia32@0.25.0': optional: true - '@esbuild/win32-x64@0.24.2': - optional: true - '@esbuild/win32-x64@0.25.0': optional: true @@ -12448,16 +12178,16 @@ snapshots: '@img/sharp-win32-x64@0.33.5': optional: true - '@inquirer/confirm@5.0.2(@types/node@22.13.5)': + '@inquirer/confirm@5.0.2(@types/node@22.13.7)': dependencies: - '@inquirer/core': 10.1.0(@types/node@22.13.5) - '@inquirer/type': 3.0.1(@types/node@22.13.5) - '@types/node': 22.13.5 + '@inquirer/core': 10.1.0(@types/node@22.13.7) + '@inquirer/type': 3.0.1(@types/node@22.13.7) + '@types/node': 22.13.7 - '@inquirer/core@10.1.0(@types/node@22.13.5)': + '@inquirer/core@10.1.0(@types/node@22.13.7)': dependencies: '@inquirer/figures': 1.0.8 - '@inquirer/type': 3.0.1(@types/node@22.13.5) + '@inquirer/type': 3.0.1(@types/node@22.13.7) ansi-escapes: 4.3.2 cli-width: 4.1.0 mute-stream: 2.0.0 @@ -12470,9 +12200,9 @@ snapshots: '@inquirer/figures@1.0.8': {} - '@inquirer/type@3.0.1(@types/node@22.13.5)': + '@inquirer/type@3.0.1(@types/node@22.13.7)': dependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 '@ioredis/commands@1.2.0': {} @@ -12661,14 +12391,14 @@ snapshots: '@types/yargs': 17.0.19 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.7.3)(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.5.0(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))': dependencies: glob: 10.4.5 magic-string: 0.27.0 - react-docgen-typescript: 2.2.2(typescript@5.7.3) - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + react-docgen-typescript: 2.2.2(typescript@5.8.2) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) optionalDependencies: - typescript: 5.7.3 + typescript: 5.8.2 '@jridgewell/gen-mapping@0.3.5': dependencies: @@ -13559,33 +13289,33 @@ snapshots: transitivePeerDependencies: - supports-color - '@shikijs/core@3.0.0': + '@shikijs/core@3.1.0': dependencies: - '@shikijs/types': 3.0.0 + '@shikijs/types': 3.1.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 - hast-util-to-html: 9.0.4 + hast-util-to-html: 9.0.5 - '@shikijs/engine-javascript@3.0.0': + '@shikijs/engine-javascript@3.1.0': dependencies: - '@shikijs/types': 3.0.0 + '@shikijs/types': 3.1.0 '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 3.1.0 + oniguruma-to-es: 3.1.1 - '@shikijs/engine-oniguruma@3.0.0': + '@shikijs/engine-oniguruma@3.1.0': dependencies: - '@shikijs/types': 3.0.0 + '@shikijs/types': 3.1.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.0.0': + '@shikijs/langs@3.1.0': dependencies: - '@shikijs/types': 3.0.0 + '@shikijs/types': 3.1.0 - '@shikijs/themes@3.0.0': + '@shikijs/themes@3.1.0': dependencies: - '@shikijs/types': 3.0.0 + '@shikijs/types': 3.1.0 - '@shikijs/types@3.0.0': + '@shikijs/types@3.1.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -14029,146 +13759,144 @@ snapshots: '@sqltools/formatter@1.2.5': {} - '@storybook/addon-actions@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-actions@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 '@types/uuid': 9.0.8 dequal: 2.0.3 polished: 4.2.2 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) uuid: 9.0.1 - '@storybook/addon-backgrounds@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-backgrounds@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 - '@storybook/addon-controls@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-controls@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 dequal: 2.0.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 - '@storybook/addon-docs@8.5.8(@types/react@18.0.28)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-docs@8.6.2(@types/react@18.0.28)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@mdx-js/react': 3.0.1(@types/react@18.0.28)(react@19.0.0) - '@storybook/blocks': 8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/csf-plugin': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/react-dom-shim': 8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/blocks': 8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/csf-plugin': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/react-dom-shim': 8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-essentials@8.5.8(@types/react@18.0.28)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-essentials@8.6.2(@types/react@18.0.28)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - '@storybook/addon-actions': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-backgrounds': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-controls': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-docs': 8.5.8(@types/react@18.0.28)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-highlight': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-measure': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-outline': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-toolbars': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/addon-viewport': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + '@storybook/addon-actions': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-backgrounds': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-controls': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-docs': 8.6.2(@types/react@18.0.28)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-highlight': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-measure': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-outline': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-toolbars': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/addon-viewport': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - '@storybook/addon-highlight@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-highlight@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/addon-interactions@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-interactions@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/test': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/instrumenter': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/test': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) polished: 4.2.2 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 - '@storybook/addon-links@8.5.8(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-links@8.6.2(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - '@storybook/csf': 0.1.12 '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 optionalDependencies: react: 19.0.0 - '@storybook/addon-mdx-gfm@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-mdx-gfm@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: remark-gfm: 4.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - '@storybook/addon-measure@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-measure@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) tiny-invariant: 1.3.3 - '@storybook/addon-outline@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-outline@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 - '@storybook/addon-storysource@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-storysource@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - '@storybook/source-loader': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/source-loader': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) estraverse: 5.3.0 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) tiny-invariant: 1.3.3 - '@storybook/addon-toolbars@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-toolbars@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/addon-viewport@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/addon-viewport@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: memoizerific: 1.11.3 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/blocks@8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/blocks@8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - '@storybook/csf': 0.1.12 '@storybook/icons': 1.2.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 optionalDependencies: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@storybook/builder-vite@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))': + '@storybook/builder-vite@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))': dependencies: - '@storybook/csf-plugin': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/csf-plugin': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) browser-assert: 1.2.1 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) - '@storybook/components@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/components@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/core-events@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/core-events@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/core@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)': + '@storybook/core@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(utf-8-validate@6.0.5)': dependencies: - '@storybook/csf': 0.1.12 + '@storybook/theming': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) better-opn: 3.0.2 browser-assert: 1.2.1 esbuild: 0.25.0 @@ -14183,18 +13911,15 @@ snapshots: prettier: 3.5.2 transitivePeerDependencies: - bufferutil + - storybook - supports-color - utf-8-validate - '@storybook/csf-plugin@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/csf-plugin@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) unplugin: 1.4.0 - '@storybook/csf@0.1.12': - dependencies: - type-fest: 2.19.0 - '@storybook/global@5.0.0': {} '@storybook/icons@1.2.12(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': @@ -14202,122 +13927,120 @@ snapshots: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - '@storybook/instrumenter@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/instrumenter@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: '@storybook/global': 5.0.0 '@vitest/utils': 2.1.1 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/manager-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/manager-api@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/preview-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/preview-api@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/react-dom-shim@8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/react-dom-shim@8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/react-vite@8.5.8(@storybook/test@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.34.8)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.7.3)(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))': + '@storybook/react-vite@8.6.2(@storybook/test@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(rollup@4.34.8)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.7.3)(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.5.0(typescript@5.8.2)(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) '@rollup/pluginutils': 5.1.4(rollup@4.34.8) - '@storybook/builder-vite': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) - '@storybook/react': 8.5.8(@storybook/test@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.7.3) + '@storybook/builder-vite': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) + '@storybook/react': 8.6.2(@storybook/test@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.8.2) find-up: 5.0.0 magic-string: 0.30.17 react: 19.0.0 react-docgen: 7.0.1 react-dom: 19.0.0(react@19.0.0) resolve: 1.22.8 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) tsconfig-paths: 4.2.0 - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) optionalDependencies: - '@storybook/test': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/test': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) transitivePeerDependencies: - rollup - supports-color - typescript - '@storybook/react@8.5.8(@storybook/test@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.7.3)': + '@storybook/react@8.6.2(@storybook/test@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(typescript@5.8.2)': dependencies: - '@storybook/components': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/components': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/preview-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/react-dom-shim': 8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/theming': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/manager-api': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/preview-api': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/react-dom-shim': 8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/theming': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) optionalDependencies: - '@storybook/test': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - typescript: 5.7.3 + '@storybook/test': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + typescript: 5.8.2 - '@storybook/source-loader@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/source-loader@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - '@storybook/csf': 0.1.12 es-toolkit: 1.27.0 estraverse: 5.3.0 prettier: 3.5.2 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/test@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/test@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - '@storybook/csf': 0.1.12 '@storybook/global': 5.0.0 - '@storybook/instrumenter': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/instrumenter': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@testing-library/dom': 10.4.0 '@testing-library/jest-dom': 6.5.0 '@testing-library/user-event': 14.5.2(@testing-library/dom@10.4.0) '@vitest/expect': 2.0.5 '@vitest/spy': 2.0.5 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/theming@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/theming@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/types@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': + '@storybook/types@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))': dependencies: - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) - '@storybook/vue3-vite@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.7.3))': + '@storybook/vue3-vite@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))': dependencies: - '@storybook/builder-vite': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) - '@storybook/vue3': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.7.3)) + '@storybook/builder-vite': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) + '@storybook/vue3': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2)) find-package-json: 1.2.0 magic-string: 0.30.17 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) typescript: 5.8.2 - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) vue-component-meta: 2.0.16(typescript@5.8.2) - vue-docgen-api: 4.75.1(vue@3.5.13(typescript@5.7.3)) + vue-docgen-api: 4.75.1(vue@3.5.13(typescript@5.8.2)) transitivePeerDependencies: - vue - '@storybook/vue3@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.7.3))': + '@storybook/vue3@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(vue@3.5.13(typescript@5.8.2))': dependencies: - '@storybook/components': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/components': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@storybook/global': 5.0.0 - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/preview-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/theming': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/manager-api': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/preview-api': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/theming': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) '@vue/compiler-core': 3.5.13 - storybook: 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + storybook: 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) ts-dedent: 2.2.0 type-fest: 2.19.0 - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.13(typescript@5.8.2) vue-component-type-helpers: 2.2.4 '@stylistic/eslint-plugin@2.13.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: - '@typescript-eslint/utils': 8.24.1(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/utils': 8.25.0(eslint@9.20.1)(typescript@5.7.3) eslint: 9.20.1 eslint-visitor-keys: 4.2.0 espree: 10.3.0 @@ -14543,12 +14266,12 @@ snapshots: dependencies: '@testing-library/dom': 10.4.0 - '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': + '@testing-library/vue@8.1.0(@vue/compiler-sfc@3.5.13)(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2))': dependencies: '@babel/runtime': 7.23.4 '@testing-library/dom': 9.3.4 - '@vue/test-utils': 2.4.1(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3)) - vue: 3.5.13(typescript@5.7.3) + '@vue/test-utils': 2.4.1(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2)) + vue: 3.5.13(typescript@5.8.2) optionalDependencies: '@vue/compiler-sfc': 3.5.13 transitivePeerDependencies: @@ -14746,10 +14469,6 @@ snapshots: dependencies: undici-types: 6.20.0 - '@types/node@22.13.5': - dependencies: - undici-types: 6.20.0 - '@types/node@22.13.7': dependencies: undici-types: 6.20.0 @@ -14920,23 +14639,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.24.1(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1)(typescript@5.7.3)': - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.24.1(eslint@9.20.1)(typescript@5.7.3) - '@typescript-eslint/scope-manager': 8.24.1 - '@typescript-eslint/type-utils': 8.24.1(eslint@9.20.1)(typescript@5.7.3) - '@typescript-eslint/utils': 8.24.1(eslint@9.20.1)(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.24.1 - eslint: 9.20.1 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - ts-api-utils: 2.0.1(typescript@5.7.3) - typescript: 5.7.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/eslint-plugin@8.25.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1)(typescript@5.8.2)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -14966,18 +14668,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.24.1 - '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) - '@typescript-eslint/visitor-keys': 8.24.1 - debug: 4.4.0(supports-color@8.1.1) - eslint: 9.20.1 - typescript: 5.7.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2)': dependencies: '@typescript-eslint/scope-manager': 8.25.0 @@ -14995,11 +14685,6 @@ snapshots: '@typescript-eslint/types': 8.24.0 '@typescript-eslint/visitor-keys': 8.24.0 - '@typescript-eslint/scope-manager@8.24.1': - dependencies: - '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/visitor-keys': 8.24.1 - '@typescript-eslint/scope-manager@8.25.0': dependencies: '@typescript-eslint/types': 8.25.0 @@ -15016,17 +14701,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.24.1(eslint@9.20.1)(typescript@5.7.3)': - dependencies: - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) - '@typescript-eslint/utils': 8.24.1(eslint@9.20.1)(typescript@5.7.3) - debug: 4.4.0(supports-color@8.1.1) - eslint: 9.20.1 - ts-api-utils: 2.0.1(typescript@5.7.3) - typescript: 5.7.3 - transitivePeerDependencies: - - supports-color - '@typescript-eslint/type-utils@8.25.0(eslint@9.20.1)(typescript@5.8.2)': dependencies: '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.8.2) @@ -15040,8 +14714,6 @@ snapshots: '@typescript-eslint/types@8.24.0': {} - '@typescript-eslint/types@8.24.1': {} - '@typescript-eslint/types@8.25.0': {} '@typescript-eslint/typescript-estree@8.24.0(typescript@5.7.3)': @@ -15058,10 +14730,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.24.1(typescript@5.7.3)': + '@typescript-eslint/typescript-estree@8.25.0(typescript@5.7.3)': dependencies: - '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/visitor-keys': 8.24.1 + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/visitor-keys': 8.25.0 debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.3 is-glob: 4.0.3 @@ -15097,12 +14769,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.24.1(eslint@9.20.1)(typescript@5.7.3)': + '@typescript-eslint/utils@8.25.0(eslint@9.20.1)(typescript@5.7.3)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@9.20.1) - '@typescript-eslint/scope-manager': 8.24.1 - '@typescript-eslint/types': 8.24.1 - '@typescript-eslint/typescript-estree': 8.24.1(typescript@5.7.3) + '@typescript-eslint/scope-manager': 8.25.0 + '@typescript-eslint/types': 8.25.0 + '@typescript-eslint/typescript-estree': 8.25.0(typescript@5.7.3) eslint: 9.20.1 typescript: 5.7.3 transitivePeerDependencies: @@ -15124,11 +14796,6 @@ snapshots: '@typescript-eslint/types': 8.24.0 eslint-visitor-keys: 4.2.0 - '@typescript-eslint/visitor-keys@8.24.1': - dependencies: - '@typescript-eslint/types': 8.24.1 - eslint-visitor-keys: 4.2.0 - '@typescript-eslint/visitor-keys@8.25.0': dependencies: '@typescript-eslint/types': 8.25.0 @@ -15136,12 +14803,12 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-vue@5.2.1(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.7.3))': + '@vitejs/plugin-vue@5.2.1(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))(vue@3.5.13(typescript@5.8.2))': dependencies: - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) - vue: 3.5.13(typescript@5.7.3) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) + vue: 3.5.13(typescript@5.8.2) - '@vitest/coverage-v8@3.0.6(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))': + '@vitest/coverage-v8@3.0.7(vitest@3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -15155,7 +14822,7 @@ snapshots: std-env: 3.8.0 test-exclude: 7.0.1 tinyrainbow: 2.0.0 - vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vitest: 3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) transitivePeerDependencies: - supports-color @@ -15166,21 +14833,21 @@ snapshots: chai: 5.2.0 tinyrainbow: 1.2.0 - '@vitest/expect@3.0.6': + '@vitest/expect@3.0.7': dependencies: - '@vitest/spy': 3.0.6 - '@vitest/utils': 3.0.6 + '@vitest/spy': 3.0.7 + '@vitest/utils': 3.0.7 chai: 5.2.0 tinyrainbow: 2.0.0 - '@vitest/mocker@3.0.6(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3))': + '@vitest/mocker@3.0.7(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3))': dependencies: - '@vitest/spy': 3.0.6 + '@vitest/spy': 3.0.7 estree-walker: 3.0.3 magic-string: 0.30.17 optionalDependencies: - msw: 2.7.1(@types/node@22.13.5)(typescript@5.7.3) - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + msw: 2.7.3(@types/node@22.13.7)(typescript@5.8.2) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) '@vitest/pretty-format@2.0.5': dependencies: @@ -15190,18 +14857,18 @@ snapshots: dependencies: tinyrainbow: 1.2.0 - '@vitest/pretty-format@3.0.6': + '@vitest/pretty-format@3.0.7': dependencies: tinyrainbow: 2.0.0 - '@vitest/runner@3.0.6': + '@vitest/runner@3.0.7': dependencies: - '@vitest/utils': 3.0.6 + '@vitest/utils': 3.0.7 pathe: 2.0.3 - '@vitest/snapshot@3.0.6': + '@vitest/snapshot@3.0.7': dependencies: - '@vitest/pretty-format': 3.0.6 + '@vitest/pretty-format': 3.0.7 magic-string: 0.30.17 pathe: 2.0.3 @@ -15209,7 +14876,7 @@ snapshots: dependencies: tinyspy: 3.0.2 - '@vitest/spy@3.0.6': + '@vitest/spy@3.0.7': dependencies: tinyspy: 3.0.2 @@ -15226,9 +14893,9 @@ snapshots: loupe: 3.1.3 tinyrainbow: 1.2.0 - '@vitest/utils@3.0.6': + '@vitest/utils@3.0.7': dependencies: - '@vitest/pretty-format': 3.0.6 + '@vitest/pretty-format': 3.0.7 loupe: 3.1.3 tinyrainbow: 2.0.0 @@ -15304,7 +14971,7 @@ snapshots: optionalDependencies: typescript: 5.8.2 - '@vue/language-core@2.2.4(typescript@5.7.3)': + '@vue/language-core@2.2.4(typescript@5.8.2)': dependencies: '@volar/language-core': 2.4.11 '@vue/compiler-dom': 3.5.13 @@ -15315,7 +14982,7 @@ snapshots: muggle-string: 0.4.1 path-browserify: 1.0.1 optionalDependencies: - typescript: 5.7.3 + typescript: 5.8.2 '@vue/reactivity@3.5.13': dependencies: @@ -15333,21 +15000,21 @@ snapshots: '@vue/shared': 3.5.13 csstype: 3.1.3 - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3))': + '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2))': dependencies: '@vue/compiler-ssr': 3.5.13 '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.13(typescript@5.8.2) '@vue/shared@3.5.13': {} - '@vue/test-utils@2.4.1(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.3)))(vue@3.5.13(typescript@5.7.3))': + '@vue/test-utils@2.4.1(@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.8.2)))(vue@3.5.13(typescript@5.8.2))': dependencies: js-beautify: 1.14.9 - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.13(typescript@5.8.2) vue-component-type-helpers: 1.8.4 optionalDependencies: - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.3)) + '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.2)) '@webgpu/types@0.1.38': {} @@ -16197,7 +15864,7 @@ snapshots: chownr@2.0.0: {} - chromatic@11.25.2: {} + chromatic@11.26.1: {} ci-info@3.7.1: {} @@ -16580,6 +16247,52 @@ snapshots: untildify: 4.0.0 yauzl: 2.10.0 + cypress@14.1.0: + dependencies: + '@cypress/request': 3.0.7 + '@cypress/xvfb': 1.2.4(supports-color@8.1.1) + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.3 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.3.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + ci-info: 4.1.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.3 + commander: 6.2.1 + common-tags: 1.8.2 + dayjs: 1.11.10 + debug: 4.4.0(supports-color@8.1.1) + enquirer: 2.3.6 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1(supports-color@8.1.1) + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0(enquirer@2.3.6) + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.8 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + process: 0.11.10 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.6.3 + supports-color: 8.1.1 + tmp: 0.2.3 + tree-kill: 1.2.2 + untildify: 4.0.0 + yauzl: 2.10.0 + dashdash@1.14.1: dependencies: assert-plus: 1.0.0 @@ -17079,34 +16792,6 @@ snapshots: transitivePeerDependencies: - supports-color - esbuild@0.24.2: - optionalDependencies: - '@esbuild/aix-ppc64': 0.24.2 - '@esbuild/android-arm': 0.24.2 - '@esbuild/android-arm64': 0.24.2 - '@esbuild/android-x64': 0.24.2 - '@esbuild/darwin-arm64': 0.24.2 - '@esbuild/darwin-x64': 0.24.2 - '@esbuild/freebsd-arm64': 0.24.2 - '@esbuild/freebsd-x64': 0.24.2 - '@esbuild/linux-arm': 0.24.2 - '@esbuild/linux-arm64': 0.24.2 - '@esbuild/linux-ia32': 0.24.2 - '@esbuild/linux-loong64': 0.24.2 - '@esbuild/linux-mips64el': 0.24.2 - '@esbuild/linux-ppc64': 0.24.2 - '@esbuild/linux-riscv64': 0.24.2 - '@esbuild/linux-s390x': 0.24.2 - '@esbuild/linux-x64': 0.24.2 - '@esbuild/netbsd-arm64': 0.24.2 - '@esbuild/netbsd-x64': 0.24.2 - '@esbuild/openbsd-arm64': 0.24.2 - '@esbuild/openbsd-x64': 0.24.2 - '@esbuild/sunos-x64': 0.24.2 - '@esbuild/win32-arm64': 0.24.2 - '@esbuild/win32-ia32': 0.24.2 - '@esbuild/win32-x64': 0.24.2 - esbuild@0.25.0: optionalDependencies: '@esbuild/aix-ppc64': 0.25.0 @@ -17182,11 +16867,11 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1): dependencies: debug: 3.2.7(supports-color@8.1.1) optionalDependencies: - '@typescript-eslint/parser': 8.24.1(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/parser': 8.25.0(eslint@9.20.1)(typescript@5.8.2) eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: @@ -17221,7 +16906,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint@9.20.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint@9.20.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -17232,7 +16917,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.20.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.24.1(eslint@9.20.1)(typescript@5.7.3))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.25.0(eslint@9.20.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint@9.20.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -17244,7 +16929,7 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.24.1(eslint@9.20.1)(typescript@5.7.3) + '@typescript-eslint/parser': 8.25.0(eslint@9.20.1)(typescript@5.8.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack @@ -18044,7 +17729,7 @@ snapshots: webidl-conversions: 7.0.0 whatwg-mimetype: 3.0.0 - happy-dom@17.1.4: + happy-dom@17.1.8: dependencies: webidl-conversions: 7.0.0 whatwg-mimetype: 3.0.0 @@ -18098,7 +17783,7 @@ snapshots: dependencies: function-bind: 1.1.2 - hast-util-to-html@9.0.4: + hast-util-to-html@9.0.5: dependencies: '@types/hast': 3.0.4 '@types/unist': 3.0.2 @@ -18107,7 +17792,7 @@ snapshots: hast-util-whitespace: 3.0.0 html-void-elements: 3.0.0 mdast-util-to-hast: 13.2.0 - property-information: 6.5.0 + property-information: 7.0.0 space-separated-tokens: 2.0.2 stringify-entities: 4.0.4 zwitch: 2.0.4 @@ -19832,17 +19517,17 @@ snapshots: optionalDependencies: msgpackr-extract: 3.0.2 - msw-storybook-addon@2.0.4(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3)): + msw-storybook-addon@2.0.4(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2)): dependencies: is-node-process: 1.2.0 - msw: 2.7.1(@types/node@22.13.5)(typescript@5.7.3) + msw: 2.7.3(@types/node@22.13.7)(typescript@5.8.2) - msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3): + msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2): dependencies: '@bundled-es-modules/cookie': 2.0.1 '@bundled-es-modules/statuses': 1.0.1 '@bundled-es-modules/tough-cookie': 0.1.6 - '@inquirer/confirm': 5.0.2(@types/node@22.13.5) + '@inquirer/confirm': 5.0.2(@types/node@22.13.7) '@mswjs/interceptors': 0.37.5 '@open-draft/deferred-promise': 2.2.0 '@open-draft/until': 2.1.0 @@ -19858,7 +19543,7 @@ snapshots: type-fest: 4.26.1 yargs: 17.7.2 optionalDependencies: - typescript: 5.7.3 + typescript: 5.8.2 transitivePeerDependencies: - '@types/node' @@ -20148,7 +19833,7 @@ snapshots: dependencies: mimic-fn: 4.0.0 - oniguruma-to-es@3.1.0: + oniguruma-to-es@3.1.1: dependencies: emoji-regex-xs: 1.0.0 regex: 6.0.1 @@ -20602,6 +20287,12 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + postcss@8.5.3: + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + postgres-array@2.0.0: {} postgres-array@3.0.2: {} @@ -20712,7 +20403,7 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - property-information@6.5.0: {} + property-information@7.0.0: {} proto-list@1.2.4: {} @@ -20893,9 +20584,9 @@ snapshots: transitivePeerDependencies: - supports-color - react-docgen-typescript@2.2.2(typescript@5.7.3): + react-docgen-typescript@2.2.2(typescript@5.8.2): dependencies: - typescript: 5.7.3 + typescript: 5.8.2 react-docgen@7.0.1: dependencies: @@ -21211,7 +20902,7 @@ snapshots: parse-srcset: 1.0.2 postcss: 8.5.2 - sass@1.85.0: + sass@1.85.1: dependencies: chokidar: 3.6.0 immutable: 5.0.3 @@ -21345,14 +21036,14 @@ snapshots: shebang-regex@3.0.0: {} - shiki@3.0.0: + shiki@3.1.0: dependencies: - '@shikijs/core': 3.0.0 - '@shikijs/engine-javascript': 3.0.0 - '@shikijs/engine-oniguruma': 3.0.0 - '@shikijs/langs': 3.0.0 - '@shikijs/themes': 3.0.0 - '@shikijs/types': 3.0.0 + '@shikijs/core': 3.1.0 + '@shikijs/engine-javascript': 3.1.0 + '@shikijs/engine-oniguruma': 3.1.0 + '@shikijs/langs': 3.1.0 + '@shikijs/themes': 3.1.0 + '@shikijs/types': 3.1.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -21608,22 +21299,22 @@ snapshots: dependencies: internal-slot: 1.0.5 - storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/components@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/core-events@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/manager-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/preview-api@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/theming@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/types@8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0): + storybook-addon-misskey-theme@https://codeload.github.com/misskey-dev/storybook-addon-misskey-theme/tar.gz/cf583db098365b2ccc81a82f63ca9c93bc32b640(@storybook/blocks@8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/components@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/core-events@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/manager-api@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/preview-api@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/theming@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(@storybook/types@8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)))(react-dom@19.0.0(react@19.0.0))(react@19.0.0): dependencies: - '@storybook/blocks': 8.5.8(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/components': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/core-events': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/manager-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/preview-api': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/theming': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) - '@storybook/types': 8.5.8(storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/blocks': 8.6.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/components': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/core-events': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/manager-api': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/preview-api': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/theming': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) + '@storybook/types': 8.6.2(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5)) optionalDependencies: react: 19.0.0 react-dom: 19.0.0(react@19.0.0) - storybook@8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5): + storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5): dependencies: - '@storybook/core': 8.5.8(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5) + '@storybook/core': 8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(storybook@8.6.2(bufferutil@4.0.9)(prettier@3.5.2)(utf-8-validate@6.0.5))(utf-8-validate@6.0.5) optionalDependencies: prettier: 3.5.2 transitivePeerDependencies: @@ -21889,7 +21580,7 @@ snapshots: dependencies: real-require: 0.2.0 - three@0.173.0: {} + three@0.174.0: {} throttle-debounce@5.0.2: {} @@ -21994,6 +21685,15 @@ snapshots: normalize-path: 3.0.0 plimit-lit: 1.5.0 + tsc-alias@1.8.11: + dependencies: + chokidar: 3.6.0 + commander: 9.5.0 + globby: 11.1.0 + mylas: 2.1.13 + normalize-path: 3.0.0 + plimit-lit: 1.5.0 + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 @@ -22285,13 +21985,13 @@ snapshots: uuid@9.0.1: {} - v-code-diff@1.13.1(vue@3.5.13(typescript@5.7.3)): + v-code-diff@1.13.1(vue@3.5.13(typescript@5.8.2)): dependencies: diff: 5.2.0 diff-match-patch: 1.0.5 highlight.js: 11.10.0 - vue: 3.5.13(typescript@5.7.3) - vue-demi: 0.14.7(vue@3.5.13(typescript@5.7.3)) + vue: 3.5.13(typescript@5.8.2) + vue-demi: 0.14.7(vue@3.5.13(typescript@5.8.2)) v8-to-istanbul@9.2.0: dependencies: @@ -22325,13 +22025,13 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 - vite-node@3.0.6(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3): + vite-node@3.0.7(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3): dependencies: cac: 6.7.14 debug: 4.4.0(supports-color@8.1.1) es-module-lexer: 1.6.0 pathe: 2.0.3 - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) transitivePeerDependencies: - '@types/node' - jiti @@ -22348,31 +22048,31 @@ snapshots: vite-plugin-turbosnap@1.0.3: {} - vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3): + vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3): dependencies: - esbuild: 0.24.2 - postcss: 8.5.2 + esbuild: 0.25.0 + postcss: 8.5.3 rollup: 4.34.8 optionalDependencies: - '@types/node': 22.13.5 + '@types/node': 22.13.7 fsevents: 2.3.3 - sass: 1.85.0 + sass: 1.85.1 terser: 5.39.0 tsx: 4.19.3 - vitest-fetch-mock@0.4.3(vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)): + vitest-fetch-mock@0.4.4(vitest@3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)): dependencies: - vitest: 3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vitest: 3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) - vitest@3.0.6(@types/debug@4.1.12)(@types/node@22.13.5)(happy-dom@17.1.4)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3): + vitest@3.0.7(@types/debug@4.1.12)(@types/node@22.13.7)(happy-dom@17.1.8)(jsdom@26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5))(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3): dependencies: - '@vitest/expect': 3.0.6 - '@vitest/mocker': 3.0.6(msw@2.7.1(@types/node@22.13.5)(typescript@5.7.3))(vite@6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)) - '@vitest/pretty-format': 3.0.6 - '@vitest/runner': 3.0.6 - '@vitest/snapshot': 3.0.6 - '@vitest/spy': 3.0.6 - '@vitest/utils': 3.0.6 + '@vitest/expect': 3.0.7 + '@vitest/mocker': 3.0.7(msw@2.7.3(@types/node@22.13.7)(typescript@5.8.2))(vite@6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3)) + '@vitest/pretty-format': 3.0.7 + '@vitest/runner': 3.0.7 + '@vitest/snapshot': 3.0.7 + '@vitest/spy': 3.0.7 + '@vitest/utils': 3.0.7 chai: 5.2.0 debug: 4.4.0(supports-color@8.1.1) expect-type: 1.1.0 @@ -22383,13 +22083,13 @@ snapshots: tinyexec: 0.3.2 tinypool: 1.0.2 tinyrainbow: 2.0.0 - vite: 6.1.1(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) - vite-node: 3.0.6(@types/node@22.13.5)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3) + vite: 6.2.0(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) + vite-node: 3.0.7(@types/node@22.13.7)(sass@1.85.1)(terser@5.39.0)(tsx@4.19.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 - '@types/node': 22.13.5 - happy-dom: 17.1.4 + '@types/node': 22.13.7 + happy-dom: 17.1.8 jsdom: 26.0.0(bufferutil@4.0.9)(canvas@3.1.0)(utf-8-validate@6.0.5) transitivePeerDependencies: - jiti @@ -22445,11 +22145,11 @@ snapshots: vue-component-type-helpers@2.2.4: {} - vue-demi@0.14.7(vue@3.5.13(typescript@5.7.3)): + vue-demi@0.14.7(vue@3.5.13(typescript@5.8.2)): dependencies: - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.13(typescript@5.8.2) - vue-docgen-api@4.75.1(vue@3.5.13(typescript@5.7.3)): + vue-docgen-api@4.75.1(vue@3.5.13(typescript@5.8.2)): dependencies: '@babel/parser': 7.25.6 '@babel/types': 7.25.6 @@ -22461,8 +22161,8 @@ snapshots: pug: 3.0.3 recast: 0.23.6 ts-map: 1.0.3 - vue: 3.5.13(typescript@5.7.3) - vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.5.13(typescript@5.7.3)) + vue: 3.5.13(typescript@5.8.2) + vue-inbrowser-compiler-independent-utils: 4.71.1(vue@3.5.13(typescript@5.8.2)) vue-eslint-parser@9.4.3(eslint@9.20.1): dependencies: @@ -22477,35 +22177,35 @@ snapshots: transitivePeerDependencies: - supports-color - vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.5.13(typescript@5.7.3)): + vue-inbrowser-compiler-independent-utils@4.71.1(vue@3.5.13(typescript@5.8.2)): dependencies: - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.13(typescript@5.8.2) vue-template-compiler@2.7.14: dependencies: de-indent: 1.0.2 he: 1.2.0 - vue-tsc@2.2.4(typescript@5.7.3): + vue-tsc@2.2.4(typescript@5.8.2): dependencies: '@volar/typescript': 2.4.11 - '@vue/language-core': 2.2.4(typescript@5.7.3) - typescript: 5.7.3 + '@vue/language-core': 2.2.4(typescript@5.8.2) + typescript: 5.8.2 - vue@3.5.13(typescript@5.7.3): + vue@3.5.13(typescript@5.8.2): dependencies: '@vue/compiler-dom': 3.5.13 '@vue/compiler-sfc': 3.5.13 '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.3)) + '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.8.2)) '@vue/shared': 3.5.13 optionalDependencies: - typescript: 5.7.3 + typescript: 5.8.2 - vuedraggable@4.1.0(vue@3.5.13(typescript@5.7.3)): + vuedraggable@4.1.0(vue@3.5.13(typescript@5.8.2)): dependencies: sortablejs: 1.14.0 - vue: 3.5.13(typescript@5.7.3) + vue: 3.5.13(typescript@5.8.2) w3c-xmlserializer@5.0.0: dependencies: From b8632f389ddba077db54e8a3bc9631b5d86940de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8A=E3=81=95=E3=82=80=E3=81=AE=E3=81=B2=E3=81=A8?= <46447427+samunohito@users.noreply.github.com> Date: Sat, 1 Mar 2025 13:37:11 +0900 Subject: [PATCH 024/649] =?UTF-8?q?chore(ci):=20Renovate=E3=81=8C=E4=BD=9C?= =?UTF-8?q?=E3=81=A3=E3=81=9Fpr=E3=81=AB=E3=83=A9=E3=83=99=E3=83=AB?= =?UTF-8?q?=E3=81=A4=E3=81=91=E3=82=8B=20(#15573)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- renovate.json5 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/renovate.json5 b/renovate.json5 index 6b869de887..395405972d 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -8,6 +8,9 @@ '* 0 * * *', ], prHourlyLimit: 5, + labels: [ + 'dependencies', + ], dependencyDashboardApproval: true, dependencyDashboardAutoclose: true, osvVulnerabilityAlerts: true, From 5d683728f335b3759e492359f3cf33f727ed55ce Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sat, 1 Mar 2025 16:12:42 +0900 Subject: [PATCH 025/649] =?UTF-8?q?=E3=83=87=E3=83=83=E3=83=89=E3=83=AD?= =?UTF-8?q?=E3=83=83=E3=82=AF=E8=A7=A3=E6=B6=88=E3=81=AE=E8=A9=A6=E3=81=BF?= =?UTF-8?q?=20(#15574)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/misskey-dev/misskey/issues/15005 Co-authored-by: 饺子w (Yumechi) <35571479+eternal-flame-AD@users.noreply.github.com> --- .../backend/src/core/activitypub/ApInboxService.ts | 11 ++--------- .../src/core/activitypub/models/ApPersonService.ts | 6 ++++-- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/core/activitypub/ApInboxService.ts b/packages/backend/src/core/activitypub/ApInboxService.ts index 21c7adf7b2..e88f60b806 100644 --- a/packages/backend/src/core/activitypub/ApInboxService.ts +++ b/packages/backend/src/core/activitypub/ApInboxService.ts @@ -507,19 +507,12 @@ export class ApInboxService { return `skip: delete actor ${actor.uri} !== ${uri}`; } - const user = await this.usersRepository.findOneBy({ id: actor.id }); - if (user == null) { - return 'skip: actor not found'; - } else if (user.isDeleted) { - return 'skip: already deleted'; + if (!(await this.usersRepository.update({ id: actor.id, isDeleted: false }, { isDeleted: true })).affected) { + return 'skip: already deleted or actor not found'; } const job = await this.queueService.createDeleteAccountJob(actor); - await this.usersRepository.update(actor.id, { - isDeleted: true, - }); - this.globalEventService.publishInternalEvent('remoteUserUpdated', { id: actor.id }); return `ok: queued ${job.name} ${job.id}`; diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index 6019906add..879f1922ca 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -594,7 +594,9 @@ export class ApPersonService implements OnModuleInit { if (moving) updates.movedAt = new Date(); // Update user - await this.usersRepository.update(exist.id, updates); + if (!(await this.usersRepository.update({ id: exist.id, isDeleted: false }, updates)).affected) { + return 'skip'; + } if (person.publicKey) { await this.userPublickeysRepository.update({ userId: exist.id }, { @@ -699,7 +701,7 @@ export class ApPersonService implements OnModuleInit { @bindThis public async updateFeatured(userId: MiUser['id'], resolver?: Resolver): Promise { - const user = await this.usersRepository.findOneByOrFail({ id: userId }); + const user = await this.usersRepository.findOneByOrFail({ id: userId, isDeleted: false }); if (!this.userEntityService.isRemoteUser(user)) return; if (!user.featured) return; From 7114523d84b5672ed8068a58610996b87837341f Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sat, 1 Mar 2025 17:02:52 +0900 Subject: [PATCH 026/649] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f765ea48e2..ab7eda0154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ - ### Server -- +- Fix: 特定のケースでActivityPubの処理がデッドロックになることがあるのを修正 ## 2025.2.1 From 616cccf2511337fc181d0b6aa693b7091c7ba57b Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 2 Mar 2025 20:06:20 +0900 Subject: [PATCH 027/649] enhance(backend): refine system account (#15530) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip * wip * wip * Update SystemAccountService.ts * Update 1740121393164-system-accounts.js * Update DeleteAccountService.ts * wip * wip * wip * wip * Update 1740121393164-system-accounts.js * Update RepositoryModule.ts * wip * wip * wip * Update ApRendererService.ts * wip * wip * Update SystemAccountService.ts * fix tests * fix tests * fix tests * fix tests * fix tests * fix tests * add print logs * ログが長すぎて出てないかもしれない * fix migration * refactor * fix fed-tests * Update RelayService.ts * merge * Update user.test.ts * chore: emit log * fix: tweak sleep duration * fix: exit 1 * fix: wait for misskey processes to become healthy * fix: longer sleep for user deletion * fix: make sleep longer again * デッドロック解消の試み https://github.com/misskey-dev/misskey/issues/15005 * Revert "デッドロック解消の試み" This reverts commit 266141f66fb584371bbb56ef7eba04e14bcff94d. * wip * Update SystemAccountService.ts --------- Co-authored-by: おさむのひと <46447427+samunohito@users.noreply.github.com> Co-authored-by: zyoshoka <107108195+zyoshoka@users.noreply.github.com> --- .github/workflows/test-federation.yml | 16 ++ CHANGELOG.md | 3 +- cypress/e2e/basic.cy.ts | 2 +- locales/index.d.ts | 4 + locales/ja-JP.yml | 1 + package.json | 4 +- .../1740121393164-system-accounts.js | 37 ++++ .../1740129169650-system-accounts-2.js | 18 ++ .../1740133121105-system-accounts-3.js | 23 +++ packages/backend/src/GlobalModule.ts | 2 +- .../backend/src/core/AbuseReportService.ts | 6 +- .../backend/src/core/AccountMoveService.ts | 14 +- packages/backend/src/core/CoreModule.ts | 24 +-- .../src/core/CreateSystemUserService.ts | 86 --------- .../backend/src/core/DeleteAccountService.ts | 14 +- .../backend/src/core/InstanceActorService.ts | 57 ------ packages/backend/src/core/MetaService.ts | 23 ++- .../backend/src/core/ProxyAccountService.ts | 28 --- packages/backend/src/core/RelayService.ts | 33 +--- packages/backend/src/core/RoleService.ts | 22 +-- packages/backend/src/core/SignupService.ts | 15 +- .../backend/src/core/SystemAccountService.ts | 172 ++++++++++++++++++ packages/backend/src/core/UserListService.ts | 10 +- .../backend/src/core/WebhookTestService.ts | 1 - .../src/core/activitypub/ApRendererService.ts | 43 ++++- .../src/core/activitypub/ApResolverService.ts | 16 +- .../src/core/entities/MetaEntityService.ts | 12 +- .../src/core/entities/UserEntityService.ts | 10 +- packages/backend/src/di-symbols.ts | 1 + packages/backend/src/models/Meta.ts | 26 +-- .../backend/src/models/RepositoryModule.ts | 13 +- packages/backend/src/models/SystemAccount.ts | 31 ++++ packages/backend/src/models/User.ts | 6 - packages/backend/src/models/_.ts | 3 + packages/backend/src/postgres.ts | 2 + .../src/server/NodeinfoServerService.ts | 8 +- .../backend/src/server/api/ApiCallService.ts | 4 +- .../backend/src/server/api/endpoint-list.ts | 1 + .../api/endpoints/admin/accounts/create.ts | 13 +- .../api/endpoints/admin/accounts/delete.ts | 4 - .../src/server/api/endpoints/admin/meta.ts | 8 +- .../api/endpoints/admin/reset-password.ts | 7 +- .../server/api/endpoints/admin/update-meta.ts | 5 - .../endpoints/admin/update-proxy-account.ts | 62 +++++++ .../src/server/api/endpoints/i/move.ts | 9 +- .../src/server/api/endpoints/reset-db.ts | 19 +- packages/backend/src/types.ts | 29 +-- packages/backend/test-federation/compose.yml | 4 + .../test-federation/test/abuse-report.test.ts | 2 +- .../backend/test-federation/test/user.test.ts | 7 +- .../backend/test-federation/test/utils.ts | 2 +- packages/backend/test/misc/mock-resolver.ts | 9 +- .../unit/AbuseReportNotificationService.ts | 6 +- packages/backend/test/unit/FlashService.ts | 6 +- packages/backend/test/unit/RelayService.ts | 27 +-- packages/backend/test/unit/RoleService.ts | 22 ++- .../backend/test/unit/SystemWebhookService.ts | 2 +- .../backend/test/unit/UserSearchService.ts | 2 +- .../backend/test/unit/UserWebhookService.ts | 2 +- .../backend/test/unit/WebhookTestService.ts | 4 +- ...CheckModeratorsActivityProcessorService.ts | 4 +- packages/frontend/src/pages/admin-user.vue | 44 +++-- .../src/pages/admin/modlog.ModLog.vue | 5 + .../frontend/src/pages/admin/settings.vue | 32 ++-- packages/frontend/src/pages/user/home.vue | 3 +- packages/frontend/test/home.test.ts | 2 - packages/misskey-js/etc/misskey-js.api.md | 8 + .../misskey-js/src/autogen/apiClientJSDoc.ts | 11 ++ packages/misskey-js/src/autogen/endpoint.ts | 3 + packages/misskey-js/src/autogen/entities.ts | 2 + packages/misskey-js/src/autogen/types.ts | 66 ++++++- 71 files changed, 783 insertions(+), 439 deletions(-) create mode 100644 packages/backend/migration/1740121393164-system-accounts.js create mode 100644 packages/backend/migration/1740129169650-system-accounts-2.js create mode 100644 packages/backend/migration/1740133121105-system-accounts-3.js delete mode 100644 packages/backend/src/core/CreateSystemUserService.ts delete mode 100644 packages/backend/src/core/InstanceActorService.ts delete mode 100644 packages/backend/src/core/ProxyAccountService.ts create mode 100644 packages/backend/src/core/SystemAccountService.ts create mode 100644 packages/backend/src/models/SystemAccount.ts create mode 100644 packages/backend/src/server/api/endpoints/admin/update-proxy-account.ts diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml index e7b5d7b098..0b71325de3 100644 --- a/.github/workflows/test-federation.yml +++ b/.github/workflows/test-federation.yml @@ -62,14 +62,30 @@ jobs: bash ./setup.sh sudo chmod 644 ./certificates/*.test.key - name: Start servers + id: start_servers + continue-on-error: true # https://github.com/docker/compose/issues/1294#issuecomment-374847206 run: | cd packages/backend/test-federation docker compose up -d --scale tester=0 + - name: Print start_servers error + if: ${{ steps.start_servers.outcome == 'failure' }} + run: | + cd packages/backend/test-federation + docker compose logs | tail -n 300 + exit 1 - name: Test + id: test + continue-on-error: true run: | cd packages/backend/test-federation docker compose run --no-deps tester + - name: Log + if: ${{ steps.test.outcome == 'failure' }} + run: | + cd packages/backend/test-federation + docker compose logs + exit 1 - name: Stop servers run: | cd packages/backend/test-federation diff --git a/CHANGELOG.md b/CHANGELOG.md index ab7eda0154..5e5703537b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ## Unreleased ### General -- +- Enhance: プロキシアカウントをシステムアカウントとして作成するように +- Fix: システムアカウントが削除できる問題を修正 ### Client - diff --git a/cypress/e2e/basic.cy.ts b/cypress/e2e/basic.cy.ts index d2efbf709c..6471f96504 100644 --- a/cypress/e2e/basic.cy.ts +++ b/cypress/e2e/basic.cy.ts @@ -233,7 +233,7 @@ describe('After user setup', () => { cy.get('[data-cy-post-form-text]').type('Hello, Misskey!'); cy.get('[data-cy-open-post-form-submit]').click(); - cy.contains('Hello, Misskey!'); + cy.contains('Hello, Misskey!', { timeout: 15000 }); }); it('open note form with hotkey', () => { diff --git a/locales/index.d.ts b/locales/index.d.ts index 74e3cdeceb..dfdc5a3b37 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -10058,6 +10058,10 @@ export interface Locale extends ILocale { * ギャラリーの投稿を削除 */ "deleteGalleryPost": string; + /** + * プロキシアカウントの説明を更新 + */ + "updateProxyAccountDescription": string; }; "_fileViewer": { /** diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 270b5fc265..c3d6fa5a41 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2664,6 +2664,7 @@ _moderationLogTypes: deletePage: "ページを削除" deleteFlash: "Playを削除" deleteGalleryPost: "ギャラリーの投稿を削除" + updateProxyAccountDescription: "プロキシアカウントの説明を更新" _fileViewer: title: "ファイルの詳細" diff --git a/package.json b/package.json index 201b30ec36..9e154e3ddd 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "build-storybook": "pnpm --filter frontend build-storybook", "build-misskey-js-with-types": "pnpm build-pre && pnpm --filter backend... --filter=!misskey-js build && pnpm --filter backend generate-api-json --no-build && ncp packages/backend/built/api.json packages/misskey-js/generator/api.json && pnpm --filter misskey-js update-autogen-code && pnpm --filter misskey-js build && pnpm --filter misskey-js api", "start": "pnpm check:connect && cd packages/backend && node ./built/boot/entry.js", - "start:test": "cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", + "start:test": "ncp ./.github/misskey/test.yml ./.config/test.yml && cd packages/backend && cross-env NODE_ENV=test node ./built/boot/entry.js", "init": "pnpm migrate", "migrate": "cd packages/backend && pnpm migrate", "revert": "cd packages/backend && pnpm revert", @@ -37,7 +37,7 @@ "cy:open": "pnpm cypress open --browser --e2e --config-file=cypress.config.ts", "cy:run": "pnpm cypress run", "e2e": "pnpm start-server-and-test start:test http://localhost:61812 cy:run", - "e2e-dev-container": "cp ./.config/cypress-devcontainer.yml ./.config/test.yml && pnpm start-server-and-test start:test http://localhost:61812 cy:run", + "e2e-dev-container": "ncp ./.config/cypress-devcontainer.yml ./.config/test.yml && pnpm start-server-and-test start:test http://localhost:61812 cy:run", "jest": "cd packages/backend && pnpm jest", "jest-and-coverage": "cd packages/backend && pnpm jest-and-coverage", "test": "pnpm -r test", diff --git a/packages/backend/migration/1740121393164-system-accounts.js b/packages/backend/migration/1740121393164-system-accounts.js new file mode 100644 index 0000000000..9490cb2b64 --- /dev/null +++ b/packages/backend/migration/1740121393164-system-accounts.js @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SystemAccounts1740121393164 { + name = 'SystemAccounts1740121393164' + + async up(queryRunner) { + await queryRunner.query(`CREATE TABLE "system_account" ("id" character varying(32) NOT NULL, "userId" character varying(32) NOT NULL, "type" character varying(256) NOT NULL, CONSTRAINT "PK_edb56f4aaf9ddd50ee556da97ba" PRIMARY KEY ("id"))`); + await queryRunner.query(`CREATE INDEX "IDX_41a3c87a37aea616ee459369e1" ON "system_account" ("userId") `); + await queryRunner.query(`CREATE UNIQUE INDEX "IDX_c362033aee0ea51011386a5a7e" ON "system_account" ("type") `); + await queryRunner.query(`ALTER TABLE "system_account" ADD CONSTRAINT "FK_41a3c87a37aea616ee459369e12" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`); + + const instanceActor = await queryRunner.query(`SELECT "id" FROM "user" WHERE "username" = 'instance.actor'`); + if (instanceActor.length > 0) { + await queryRunner.query(`INSERT INTO "system_account" ("id", "userId", "type") VALUES ('${instanceActor[0].id}', '${instanceActor[0].id}', 'actor')`); + } + + const relayActor = await queryRunner.query(`SELECT "id" FROM "user" WHERE "username" = 'relay.actor'`); + if (relayActor.length > 0) { + await queryRunner.query(`INSERT INTO "system_account" ("id", "userId", "type") VALUES ('${relayActor[0].id}', '${relayActor[0].id}', 'relay')`); + } + + const meta = await queryRunner.query(`SELECT "proxyAccountId" FROM "meta" ORDER BY "id" DESC LIMIT 1`); + if (!meta && meta.length >= 1 && meta[0].proxyAccountId) { + await queryRunner.query(`INSERT INTO "system_account" ("id", "userId", "type") VALUES ('${meta[0].proxyAccountId}', '${meta[0].proxyAccountId}', 'proxy')`); + } + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "system_account" DROP CONSTRAINT "FK_41a3c87a37aea616ee459369e12"`); + await queryRunner.query(`DROP INDEX "public"."IDX_c362033aee0ea51011386a5a7e"`); + await queryRunner.query(`DROP INDEX "public"."IDX_41a3c87a37aea616ee459369e1"`); + await queryRunner.query(`DROP TABLE "system_account"`); + } +} diff --git a/packages/backend/migration/1740129169650-system-accounts-2.js b/packages/backend/migration/1740129169650-system-accounts-2.js new file mode 100644 index 0000000000..07270855bf --- /dev/null +++ b/packages/backend/migration/1740129169650-system-accounts-2.js @@ -0,0 +1,18 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SystemAccounts21740129169650 { + name = 'SystemAccounts21740129169650' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "proxyAccountId"`); + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "proxyAccountId" character varying(32)`); + await queryRunner.query(`ALTER TABLE "meta" ADD CONSTRAINT "FK_ab1bc0c1e209daa77b8e8d212ad" FOREIGN KEY ("proxyAccountId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`); + } +} diff --git a/packages/backend/migration/1740133121105-system-accounts-3.js b/packages/backend/migration/1740133121105-system-accounts-3.js new file mode 100644 index 0000000000..02f9207cdc --- /dev/null +++ b/packages/backend/migration/1740133121105-system-accounts-3.js @@ -0,0 +1,23 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +export class SystemAccounts31740133121105 { + name = 'SystemAccounts31740133121105' + + async up(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" ADD "rootUserId" character varying(32)`); + await queryRunner.query(`ALTER TABLE "meta" ADD CONSTRAINT "FK_c80e4079d632f95eac06a9d28cc" FOREIGN KEY ("rootUserId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`); + + const users = await queryRunner.query(`SELECT "id" FROM "user" WHERE "isRoot" = true LIMIT 1`); + if (users.length > 0) { + await queryRunner.query(`UPDATE "meta" SET "rootUserId" = $1`, [users[0].id]); + } + } + + async down(queryRunner) { + await queryRunner.query(`ALTER TABLE "meta" DROP CONSTRAINT "FK_c80e4079d632f95eac06a9d28cc"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "rootUserId"`); + } +} diff --git a/packages/backend/src/GlobalModule.ts b/packages/backend/src/GlobalModule.ts index ace7f7841c..5544eeeddd 100644 --- a/packages/backend/src/GlobalModule.ts +++ b/packages/backend/src/GlobalModule.ts @@ -133,7 +133,7 @@ const $meta: Provider = { for (const key in body.after) { (meta as any)[key] = (body.after as any)[key]; } - meta.proxyAccount = null; // joinなカラムは通常取ってこないので + meta.rootUser = null; // joinなカラムは通常取ってこないので break; } default: diff --git a/packages/backend/src/core/AbuseReportService.ts b/packages/backend/src/core/AbuseReportService.ts index 0b022d3b08..846d2c8ebd 100644 --- a/packages/backend/src/core/AbuseReportService.ts +++ b/packages/backend/src/core/AbuseReportService.ts @@ -10,9 +10,9 @@ import { bindThis } from '@/decorators.js'; import type { AbuseUserReportsRepository, MiAbuseUserReport, MiUser, UsersRepository } from '@/models/_.js'; import { AbuseReportNotificationService } from '@/core/AbuseReportNotificationService.js'; import { QueueService } from '@/core/QueueService.js'; -import { InstanceActorService } from '@/core/InstanceActorService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; import { IdService } from './IdService.js'; @Injectable() @@ -27,7 +27,7 @@ export class AbuseReportService { private idService: IdService, private abuseReportNotificationService: AbuseReportNotificationService, private queueService: QueueService, - private instanceActorService: InstanceActorService, + private systemAccountService: SystemAccountService, private apRendererService: ApRendererService, private moderationLogService: ModerationLogService, ) { @@ -136,7 +136,7 @@ export class AbuseReportService { forwarded: true, }); - const actor = await this.instanceActorService.getInstanceActor(); + const actor = await this.systemAccountService.fetch('actor'); const targetUser = await this.usersRepository.findOneByOrFail({ id: report.targetUserId }); const flag = this.apRendererService.renderFlag(actor, targetUser.uri!, report.comment); diff --git a/packages/backend/src/core/AccountMoveService.ts b/packages/backend/src/core/AccountMoveService.ts index 24d11f29ff..0fbb9bcd80 100644 --- a/packages/backend/src/core/AccountMoveService.ts +++ b/packages/backend/src/core/AccountMoveService.ts @@ -20,10 +20,10 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { ApDeliverManagerService } from '@/core/activitypub/ApDeliverManagerService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { ProxyAccountService } from '@/core/ProxyAccountService.js'; import { FederatedInstanceService } from '@/core/FederatedInstanceService.js'; import InstanceChart from '@/core/chart/charts/instance.js'; import PerUserFollowingChart from '@/core/chart/charts/per-user-following.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; @Injectable() export class AccountMoveService { @@ -55,12 +55,12 @@ export class AccountMoveService { private apRendererService: ApRendererService, private apDeliverManagerService: ApDeliverManagerService, private globalEventService: GlobalEventService, - private proxyAccountService: ProxyAccountService, private perUserFollowingChart: PerUserFollowingChart, private federatedInstanceService: FederatedInstanceService, private instanceChart: InstanceChart, private relayService: RelayService, private queueService: QueueService, + private systemAccountService: SystemAccountService, ) { } @@ -126,11 +126,11 @@ export class AccountMoveService { } // follow the new account - const proxy = await this.proxyAccountService.fetch(); + const proxy = await this.systemAccountService.fetch('proxy'); const followings = await this.followingsRepository.findBy({ followeeId: src.id, followerHost: IsNull(), // follower is local - followerId: proxy ? Not(proxy.id) : undefined, + followerId: Not(proxy.id), }); const followJobs = followings.map(following => ({ from: { id: following.followerId }, @@ -250,10 +250,8 @@ export class AccountMoveService { // Have the proxy account follow the new account in the same way as UserListService.push if (this.userEntityService.isRemoteUser(dst)) { - const proxy = await this.proxyAccountService.fetch(); - if (proxy) { - this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: dst.id } }]); - } + const proxy = await this.systemAccountService.fetch('proxy'); + this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: dst.id } }]); } } diff --git a/packages/backend/src/core/CoreModule.ts b/packages/backend/src/core/CoreModule.ts index 734d135648..dc85a23e5b 100644 --- a/packages/backend/src/core/CoreModule.ts +++ b/packages/backend/src/core/CoreModule.ts @@ -24,7 +24,6 @@ import { AppLockService } from './AppLockService.js'; import { AchievementService } from './AchievementService.js'; import { AvatarDecorationService } from './AvatarDecorationService.js'; import { CaptchaService } from './CaptchaService.js'; -import { CreateSystemUserService } from './CreateSystemUserService.js'; import { CustomEmojiService } from './CustomEmojiService.js'; import { DeleteAccountService } from './DeleteAccountService.js'; import { DownloadService } from './DownloadService.js'; @@ -37,7 +36,7 @@ import { HashtagService } from './HashtagService.js'; import { HttpRequestService } from './HttpRequestService.js'; import { IdService } from './IdService.js'; import { ImageProcessingService } from './ImageProcessingService.js'; -import { InstanceActorService } from './InstanceActorService.js'; +import { SystemAccountService } from './SystemAccountService.js'; import { InternalStorageService } from './InternalStorageService.js'; import { MetaService } from './MetaService.js'; import { MfmService } from './MfmService.js'; @@ -69,7 +68,6 @@ import { UserSuspendService } from './UserSuspendService.js'; import { UserAuthService } from './UserAuthService.js'; import { VideoProcessingService } from './VideoProcessingService.js'; import { UserWebhookService } from './UserWebhookService.js'; -import { ProxyAccountService } from './ProxyAccountService.js'; import { UtilityService } from './UtilityService.js'; import { FileInfoService } from './FileInfoService.js'; import { SearchService } from './SearchService.js'; @@ -167,7 +165,6 @@ const $AppLockService: Provider = { provide: 'AppLockService', useExisting: AppL const $AchievementService: Provider = { provide: 'AchievementService', useExisting: AchievementService }; const $AvatarDecorationService: Provider = { provide: 'AvatarDecorationService', useExisting: AvatarDecorationService }; const $CaptchaService: Provider = { provide: 'CaptchaService', useExisting: CaptchaService }; -const $CreateSystemUserService: Provider = { provide: 'CreateSystemUserService', useExisting: CreateSystemUserService }; const $CustomEmojiService: Provider = { provide: 'CustomEmojiService', useExisting: CustomEmojiService }; const $DeleteAccountService: Provider = { provide: 'DeleteAccountService', useExisting: DeleteAccountService }; const $DownloadService: Provider = { provide: 'DownloadService', useExisting: DownloadService }; @@ -180,7 +177,6 @@ const $HashtagService: Provider = { provide: 'HashtagService', useExisting: Hash const $HttpRequestService: Provider = { provide: 'HttpRequestService', useExisting: HttpRequestService }; const $IdService: Provider = { provide: 'IdService', useExisting: IdService }; const $ImageProcessingService: Provider = { provide: 'ImageProcessingService', useExisting: ImageProcessingService }; -const $InstanceActorService: Provider = { provide: 'InstanceActorService', useExisting: InstanceActorService }; const $InternalStorageService: Provider = { provide: 'InternalStorageService', useExisting: InternalStorageService }; const $MetaService: Provider = { provide: 'MetaService', useExisting: MetaService }; const $MfmService: Provider = { provide: 'MfmService', useExisting: MfmService }; @@ -191,7 +187,7 @@ const $NotePiningService: Provider = { provide: 'NotePiningService', useExisting const $NoteReadService: Provider = { provide: 'NoteReadService', useExisting: NoteReadService }; const $NotificationService: Provider = { provide: 'NotificationService', useExisting: NotificationService }; const $PollService: Provider = { provide: 'PollService', useExisting: PollService }; -const $ProxyAccountService: Provider = { provide: 'ProxyAccountService', useExisting: ProxyAccountService }; +const $SystemAccountService: Provider = { provide: 'SystemAccountService', useExisting: SystemAccountService }; const $PushNotificationService: Provider = { provide: 'PushNotificationService', useExisting: PushNotificationService }; const $QueryService: Provider = { provide: 'QueryService', useExisting: QueryService }; const $ReactionService: Provider = { provide: 'ReactionService', useExisting: ReactionService }; @@ -318,7 +314,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting AchievementService, AvatarDecorationService, CaptchaService, - CreateSystemUserService, CustomEmojiService, DeleteAccountService, DownloadService, @@ -331,7 +326,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting HttpRequestService, IdService, ImageProcessingService, - InstanceActorService, InternalStorageService, MetaService, MfmService, @@ -342,7 +336,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting NoteReadService, NotificationService, PollService, - ProxyAccountService, + SystemAccountService, PushNotificationService, QueryService, ReactionService, @@ -465,7 +459,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $AchievementService, $AvatarDecorationService, $CaptchaService, - $CreateSystemUserService, $CustomEmojiService, $DeleteAccountService, $DownloadService, @@ -478,7 +471,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $HttpRequestService, $IdService, $ImageProcessingService, - $InstanceActorService, $InternalStorageService, $MetaService, $MfmService, @@ -489,7 +481,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $NoteReadService, $NotificationService, $PollService, - $ProxyAccountService, + $SystemAccountService, $PushNotificationService, $QueryService, $ReactionService, @@ -613,7 +605,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting AchievementService, AvatarDecorationService, CaptchaService, - CreateSystemUserService, CustomEmojiService, DeleteAccountService, DownloadService, @@ -626,7 +617,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting HttpRequestService, IdService, ImageProcessingService, - InstanceActorService, InternalStorageService, MetaService, MfmService, @@ -637,7 +627,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting NoteReadService, NotificationService, PollService, - ProxyAccountService, + SystemAccountService, PushNotificationService, QueryService, ReactionService, @@ -759,7 +749,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $AchievementService, $AvatarDecorationService, $CaptchaService, - $CreateSystemUserService, $CustomEmojiService, $DeleteAccountService, $DownloadService, @@ -772,7 +761,6 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $HttpRequestService, $IdService, $ImageProcessingService, - $InstanceActorService, $InternalStorageService, $MetaService, $MfmService, @@ -783,7 +771,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting $NoteReadService, $NotificationService, $PollService, - $ProxyAccountService, + $SystemAccountService, $PushNotificationService, $QueryService, $ReactionService, diff --git a/packages/backend/src/core/CreateSystemUserService.ts b/packages/backend/src/core/CreateSystemUserService.ts deleted file mode 100644 index 7ef75edb3c..0000000000 --- a/packages/backend/src/core/CreateSystemUserService.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { randomUUID } from 'node:crypto'; -import { Inject, Injectable } from '@nestjs/common'; -import bcrypt from 'bcryptjs'; -import { IsNull, DataSource } from 'typeorm'; -import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; -import { MiUser } from '@/models/User.js'; -import { MiUserProfile } from '@/models/UserProfile.js'; -import { IdService } from '@/core/IdService.js'; -import { MiUserKeypair } from '@/models/UserKeypair.js'; -import { MiUsedUsername } from '@/models/UsedUsername.js'; -import { DI } from '@/di-symbols.js'; -import { generateNativeUserToken } from '@/misc/token.js'; -import { bindThis } from '@/decorators.js'; - -@Injectable() -export class CreateSystemUserService { - constructor( - @Inject(DI.db) - private db: DataSource, - - private idService: IdService, - ) { - } - - @bindThis - public async createSystemUser(username: string): Promise { - const password = randomUUID(); - - // Generate hash of password - const salt = await bcrypt.genSalt(8); - const hash = await bcrypt.hash(password, salt); - - // Generate secret - const secret = generateNativeUserToken(); - - const keyPair = await genRsaKeyPair(); - - let account!: MiUser; - - // Start transaction - await this.db.transaction(async transactionalEntityManager => { - const exist = await transactionalEntityManager.findOneBy(MiUser, { - usernameLower: username.toLowerCase(), - host: IsNull(), - }); - - if (exist) throw new Error('the user is already exists'); - - account = await transactionalEntityManager.insert(MiUser, { - id: this.idService.gen(), - username: username, - usernameLower: username.toLowerCase(), - host: null, - token: secret, - isRoot: false, - isLocked: true, - isExplorable: false, - isBot: true, - }).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0])); - - await transactionalEntityManager.insert(MiUserKeypair, { - publicKey: keyPair.publicKey, - privateKey: keyPair.privateKey, - userId: account.id, - }); - - await transactionalEntityManager.insert(MiUserProfile, { - userId: account.id, - autoAcceptFollowed: false, - password: hash, - }); - - await transactionalEntityManager.insert(MiUsedUsername, { - createdAt: new Date(), - username: username.toLowerCase(), - }); - }); - - return account; - } -} diff --git a/packages/backend/src/core/DeleteAccountService.ts b/packages/backend/src/core/DeleteAccountService.ts index 7f1b8f3efb..483f14ce7f 100644 --- a/packages/backend/src/core/DeleteAccountService.ts +++ b/packages/backend/src/core/DeleteAccountService.ts @@ -5,7 +5,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Not, IsNull } from 'typeorm'; -import type { FollowingsRepository, MiUser, UsersRepository } from '@/models/_.js'; +import type { FollowingsRepository, MiMeta, MiUser, UsersRepository } from '@/models/_.js'; import { QueueService } from '@/core/QueueService.js'; import { DI } from '@/di-symbols.js'; import { bindThis } from '@/decorators.js'; @@ -13,10 +13,14 @@ import { GlobalEventService } from '@/core/GlobalEventService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; @Injectable() export class DeleteAccountService { constructor( + @Inject(DI.meta) + private meta: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -28,6 +32,7 @@ export class DeleteAccountService { private queueService: QueueService, private globalEventService: GlobalEventService, private moderationLogService: ModerationLogService, + private systemAccountService: SystemAccountService, ) { } @@ -36,8 +41,13 @@ export class DeleteAccountService { id: string; host: string | null; }, moderator?: MiUser): Promise { + if (this.meta.rootUserId === user.id) throw new Error('cannot delete a root account'); + const _user = await this.usersRepository.findOneByOrFail({ id: user.id }); - if (_user.isRoot) throw new Error('cannot delete a root account'); + + if (user.host === null && _user.username.includes('.')) { + throw new Error('cannot delete a system account'); + } if (moderator != null) { this.moderationLogService.log(moderator, 'deleteAccount', { diff --git a/packages/backend/src/core/InstanceActorService.ts b/packages/backend/src/core/InstanceActorService.ts deleted file mode 100644 index 22c47297a3..0000000000 --- a/packages/backend/src/core/InstanceActorService.ts +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Inject, Injectable } from '@nestjs/common'; -import { IsNull, Not } from 'typeorm'; -import type { MiLocalUser } from '@/models/User.js'; -import type { UsersRepository } from '@/models/_.js'; -import { MemorySingleCache } from '@/misc/cache.js'; -import { DI } from '@/di-symbols.js'; -import { CreateSystemUserService } from '@/core/CreateSystemUserService.js'; -import { bindThis } from '@/decorators.js'; - -const ACTOR_USERNAME = 'instance.actor' as const; - -@Injectable() -export class InstanceActorService { - private cache: MemorySingleCache; - - constructor( - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - private createSystemUserService: CreateSystemUserService, - ) { - this.cache = new MemorySingleCache(Infinity); - } - - @bindThis - public async realLocalUsersPresent(): Promise { - return await this.usersRepository.existsBy({ - host: IsNull(), - username: Not(ACTOR_USERNAME), - }); - } - - @bindThis - public async getInstanceActor(): Promise { - const cached = this.cache.get(); - if (cached) return cached; - - const user = await this.usersRepository.findOneBy({ - host: IsNull(), - username: ACTOR_USERNAME, - }) as MiLocalUser | undefined; - - if (user) { - this.cache.set(user); - return user; - } else { - const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as MiLocalUser; - this.cache.set(created); - return created; - } - } -} diff --git a/packages/backend/src/core/MetaService.ts b/packages/backend/src/core/MetaService.ts index 3d88d0aefe..40e7439f5f 100644 --- a/packages/backend/src/core/MetaService.ts +++ b/packages/backend/src/core/MetaService.ts @@ -53,7 +53,7 @@ export class MetaService implements OnApplicationShutdown { case 'metaUpdated': { this.cache = { // TODO: このあたりのデシリアライズ処理は各modelファイル内に関数としてexportしたい ...(body.after), - proxyAccount: null, // joinなカラムは通常取ってこないので + rootUser: null, // joinなカラムは通常取ってこないので }; break; } @@ -113,17 +113,20 @@ export class MetaService implements OnApplicationShutdown { if (before) { await transactionalEntityManager.update(MiMeta, before.id, data); - - const metas = await transactionalEntityManager.find(MiMeta, { - order: { - id: 'DESC', - }, - }); - - return metas[0]; } else { - return await transactionalEntityManager.save(MiMeta, data); + await transactionalEntityManager.save(MiMeta, { + ...data, + id: 'x', + }); } + + const afters = await transactionalEntityManager.find(MiMeta, { + order: { + id: 'DESC', + }, + }); + + return afters[0]; }); if (data.hiddenTags) { diff --git a/packages/backend/src/core/ProxyAccountService.ts b/packages/backend/src/core/ProxyAccountService.ts deleted file mode 100644 index c3ff2a68d3..0000000000 --- a/packages/backend/src/core/ProxyAccountService.ts +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ - -import { Inject, Injectable } from '@nestjs/common'; -import type { MiMeta, UsersRepository } from '@/models/_.js'; -import type { MiLocalUser } from '@/models/User.js'; -import { DI } from '@/di-symbols.js'; -import { bindThis } from '@/decorators.js'; - -@Injectable() -export class ProxyAccountService { - constructor( - @Inject(DI.meta) - private meta: MiMeta, - - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - ) { - } - - @bindThis - public async fetch(): Promise { - if (this.meta.proxyAccountId == null) return null; - return await this.usersRepository.findOneByOrFail({ id: this.meta.proxyAccountId }) as MiLocalUser; - } -} diff --git a/packages/backend/src/core/RelayService.ts b/packages/backend/src/core/RelayService.ts index db32114346..9120de1f9f 100644 --- a/packages/backend/src/core/RelayService.ts +++ b/packages/backend/src/core/RelayService.ts @@ -4,53 +4,34 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import { IsNull } from 'typeorm'; -import type { MiLocalUser, MiUser } from '@/models/User.js'; -import type { RelaysRepository, UsersRepository } from '@/models/_.js'; +import type { MiUser } from '@/models/User.js'; +import type { RelaysRepository } from '@/models/_.js'; import { IdService } from '@/core/IdService.js'; import { MemorySingleCache } from '@/misc/cache.js'; import type { MiRelay } from '@/models/Relay.js'; import { QueueService } from '@/core/QueueService.js'; -import { CreateSystemUserService } from '@/core/CreateSystemUserService.js'; import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import { DI } from '@/di-symbols.js'; import { deepClone } from '@/misc/clone.js'; import { bindThis } from '@/decorators.js'; - -const ACTOR_USERNAME = 'relay.actor' as const; +import { SystemAccountService } from '@/core/SystemAccountService.js'; @Injectable() export class RelayService { private relaysCache: MemorySingleCache; constructor( - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - @Inject(DI.relaysRepository) private relaysRepository: RelaysRepository, private idService: IdService, private queueService: QueueService, - private createSystemUserService: CreateSystemUserService, + private systemAccountService: SystemAccountService, private apRendererService: ApRendererService, ) { this.relaysCache = new MemorySingleCache(1000 * 60 * 10); // 10m } - @bindThis - private async getRelayActor(): Promise { - const user = await this.usersRepository.findOneBy({ - host: IsNull(), - username: ACTOR_USERNAME, - }); - - if (user) return user as MiLocalUser; - - const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME); - return created as MiLocalUser; - } - @bindThis public async addRelay(inbox: string): Promise { const relay = await this.relaysRepository.insertOne({ @@ -59,8 +40,8 @@ export class RelayService { status: 'requesting', }); - const relayActor = await this.getRelayActor(); - const follow = await this.apRendererService.renderFollowRelay(relay, relayActor); + const relayActor = await this.systemAccountService.fetch('relay'); + const follow = this.apRendererService.renderFollowRelay(relay, relayActor); const activity = this.apRendererService.addContext(follow); this.queueService.deliver(relayActor, activity, relay.inbox, false); @@ -77,7 +58,7 @@ export class RelayService { throw new Error('relay not found'); } - const relayActor = await this.getRelayActor(); + const relayActor = await this.systemAccountService.fetch('relay'); const follow = this.apRendererService.renderFollowRelay(relay, relayActor); const undo = this.apRendererService.renderUndo(follow, relayActor); const activity = this.apRendererService.addContext(undo); diff --git a/packages/backend/src/core/RoleService.ts b/packages/backend/src/core/RoleService.ts index 5af6b05942..01f3e0c116 100644 --- a/packages/backend/src/core/RoleService.ts +++ b/packages/backend/src/core/RoleService.ts @@ -101,7 +101,6 @@ export const DEFAULT_POLICIES: RolePolicies = { @Injectable() export class RoleService implements OnApplicationShutdown, OnModuleInit { - private rootUserIdCache: MemorySingleCache; private rolesCache: MemorySingleCache; private roleAssignmentByUserIdCache: MemoryKVCache; private notificationService: NotificationService; @@ -137,7 +136,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { private moderationLogService: ModerationLogService, private fanoutTimelineService: FanoutTimelineService, ) { - this.rootUserIdCache = new MemorySingleCache(1000 * 60 * 60 * 24 * 7); // 1week. rootユーザのIDは不変なので長めに this.rolesCache = new MemorySingleCache(1000 * 60 * 60); // 1h this.roleAssignmentByUserIdCache = new MemoryKVCache(1000 * 60 * 5); // 5m @@ -406,15 +404,15 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { } @bindThis - public async isModerator(user: { id: MiUser['id']; isRoot: MiUser['isRoot'] } | null): Promise { + public async isModerator(user: { id: MiUser['id'] } | null): Promise { if (user == null) return false; - return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isModerator || r.isAdministrator); + return (this.meta.rootUserId === user.id) || (await this.getUserRoles(user.id)).some(r => r.isModerator || r.isAdministrator); } @bindThis - public async isAdministrator(user: { id: MiUser['id']; isRoot: MiUser['isRoot'] } | null): Promise { + public async isAdministrator(user: { id: MiUser['id'] } | null): Promise { if (user == null) return false; - return user.isRoot || (await this.getUserRoles(user.id)).some(r => r.isAdministrator); + return (this.meta.rootUserId === user.id) || (await this.getUserRoles(user.id)).some(r => r.isAdministrator); } @bindThis @@ -463,16 +461,8 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit { .map(a => a.userId), ); - if (includeRoot) { - const rootUserId = await this.rootUserIdCache.fetch(async () => { - const it = await this.usersRepository.createQueryBuilder('users') - .select('id') - .where({ isRoot: true }) - .getRawOne<{ id: string }>(); - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - return it!.id; - }); - resultSet.add(rootUserId); + if (includeRoot && this.meta.rootUserId) { + resultSet.add(this.meta.rootUserId); } return [...resultSet].sort((x, y) => x.localeCompare(y)); diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts index d2f09ea15d..5462cb0b13 100644 --- a/packages/backend/src/core/SignupService.ts +++ b/packages/backend/src/core/SignupService.ts @@ -16,11 +16,12 @@ import { MiUserKeypair } from '@/models/UserKeypair.js'; import { MiUsedUsername } from '@/models/UsedUsername.js'; import { generateNativeUserToken } from '@/misc/token.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { InstanceActorService } from '@/core/InstanceActorService.js'; import { bindThis } from '@/decorators.js'; import UsersChart from '@/core/chart/charts/users.js'; import { UtilityService } from '@/core/UtilityService.js'; import { UserService } from '@/core/UserService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; +import { MetaService } from '@/core/MetaService.js'; @Injectable() export class SignupService { @@ -41,7 +42,8 @@ export class SignupService { private userService: UserService, private userEntityService: UserEntityService, private idService: IdService, - private instanceActorService: InstanceActorService, + private systemAccountService: SystemAccountService, + private metaService: MetaService, private usersChart: UsersChart, ) { } @@ -86,9 +88,7 @@ export class SignupService { throw new Error('USED_USERNAME'); } - const isTheFirstUser = !await this.instanceActorService.realLocalUsersPresent(); - - if (!opts.ignorePreservedUsernames && !isTheFirstUser) { + if (!opts.ignorePreservedUsernames && this.meta.rootUserId != null) { const isPreserved = this.meta.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase()); if (isPreserved) { throw new Error('USED_USERNAME'); @@ -129,7 +129,6 @@ export class SignupService { usernameLower: username.toLowerCase(), host: this.utilityService.toPunyNullable(host), token: secret, - isRoot: isTheFirstUser, })); await transactionalEntityManager.save(new MiUserKeypair({ @@ -153,6 +152,10 @@ export class SignupService { this.usersChart.update(account, true); this.userService.notifySystemWebhook(account, 'userCreated'); + if (this.meta.rootUserId == null) { + await this.metaService.update({ rootUserId: account.id }); + } + return { account, secret }; } } diff --git a/packages/backend/src/core/SystemAccountService.ts b/packages/backend/src/core/SystemAccountService.ts new file mode 100644 index 0000000000..1e050c3054 --- /dev/null +++ b/packages/backend/src/core/SystemAccountService.ts @@ -0,0 +1,172 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { randomUUID } from 'node:crypto'; +import { Inject, Injectable } from '@nestjs/common'; +import { DataSource, IsNull } from 'typeorm'; +import bcrypt from 'bcryptjs'; +import { MiLocalUser, MiUser } from '@/models/User.js'; +import { MiSystemAccount, MiUsedUsername, MiUserKeypair, MiUserProfile, type UsersRepository, type SystemAccountsRepository } from '@/models/_.js'; +import type { MiMeta, UserProfilesRepository } from '@/models/_.js'; +import { MemoryKVCache } from '@/misc/cache.js'; +import { DI } from '@/di-symbols.js'; +import { bindThis } from '@/decorators.js'; +import { generateNativeUserToken } from '@/misc/token.js'; +import { IdService } from '@/core/IdService.js'; +import { genRsaKeyPair } from '@/misc/gen-key-pair.js'; + +export const SYSTEM_ACCOUNT_TYPES = ['actor', 'relay', 'proxy'] as const; + +@Injectable() +export class SystemAccountService { + private cache: MemoryKVCache; + + constructor( + @Inject(DI.db) + private db: DataSource, + + @Inject(DI.meta) + private meta: MiMeta, + + @Inject(DI.systemAccountsRepository) + private systemAccountsRepository: SystemAccountsRepository, + + @Inject(DI.usersRepository) + private usersRepository: UsersRepository, + + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + + private idService: IdService, + ) { + this.cache = new MemoryKVCache(1000 * 60 * 10); // 10m + } + + @bindThis + public async list(): Promise { + const accounts = await this.systemAccountsRepository.findBy({}); + + return accounts; + } + + @bindThis + public async fetch(type: typeof SYSTEM_ACCOUNT_TYPES[number]): Promise { + const cached = this.cache.get(type); + if (cached) return cached; + + const systemAccount = await this.systemAccountsRepository.findOne({ + where: { type: type }, + relations: ['user'], + }); + + if (systemAccount) { + this.cache.set(type, systemAccount.user as MiLocalUser); + return systemAccount.user as MiLocalUser; + } else { + const created = await this.createCorrespondingUser(type, { + username: `system.${type}`, // NOTE: (できれば避けたいが) . が含まれるかどうかでシステムアカウントかどうかを判定している処理もあるので変えないように + name: this.meta.name, + }); + this.cache.set(type, created); + return created; + } + } + + @bindThis + private async createCorrespondingUser(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: { + username: MiUser['username']; + name?: MiUser['name']; + }): Promise { + const password = randomUUID(); + + // Generate hash of password + const salt = await bcrypt.genSalt(8); + const hash = await bcrypt.hash(password, salt); + + // Generate secret + const secret = generateNativeUserToken(); + + const keyPair = await genRsaKeyPair(); + + let account!: MiUser; + + // Start transaction + await this.db.transaction(async transactionalEntityManager => { + const exist = await transactionalEntityManager.findOneBy(MiUser, { + usernameLower: extra.username.toLowerCase(), + host: IsNull(), + }); + + if (exist) { + account = exist; + return; + } + + account = await transactionalEntityManager.insert(MiUser, { + id: this.idService.gen(), + username: extra.username, + usernameLower: extra.username.toLowerCase(), + host: null, + token: secret, + isLocked: true, + isExplorable: false, + isBot: true, + name: extra.name, + }).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0])); + + await transactionalEntityManager.insert(MiUserKeypair, { + publicKey: keyPair.publicKey, + privateKey: keyPair.privateKey, + userId: account.id, + }); + + await transactionalEntityManager.insert(MiUserProfile, { + userId: account.id, + autoAcceptFollowed: false, + password: hash, + }); + + await transactionalEntityManager.insert(MiUsedUsername, { + createdAt: new Date(), + username: extra.username.toLowerCase(), + }); + + await transactionalEntityManager.insert(MiSystemAccount, { + id: this.idService.gen(), + userId: account.id, + type: type, + }); + }); + + return account as MiLocalUser; + } + + @bindThis + public async updateCorrespondingUserProfile(type: typeof SYSTEM_ACCOUNT_TYPES[number], extra: { + name?: string; + description?: MiUserProfile['description']; + }): Promise { + const user = await this.fetch(type); + + const updates = {} as Partial; + if (extra.name !== undefined) updates.name = extra.name; + + if (Object.keys(updates).length > 0) { + await this.usersRepository.update(user.id, updates); + } + + const profileUpdates = {} as Partial; + if (extra.description !== undefined) profileUpdates.description = extra.description; + + if (Object.keys(profileUpdates).length > 0) { + await this.userProfilesRepository.update(user.id, profileUpdates); + } + + const updated = await this.usersRepository.findOneByOrFail({ id: user.id }) as MiLocalUser; + this.cache.set(type, updated); + + return updated; + } +} diff --git a/packages/backend/src/core/UserListService.ts b/packages/backend/src/core/UserListService.ts index 6333356fe9..f0a8768c8f 100644 --- a/packages/backend/src/core/UserListService.ts +++ b/packages/backend/src/core/UserListService.ts @@ -15,11 +15,11 @@ import type { GlobalEvents } from '@/core/GlobalEventService.js'; import { GlobalEventService } from '@/core/GlobalEventService.js'; import { DI } from '@/di-symbols.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { ProxyAccountService } from '@/core/ProxyAccountService.js'; import { bindThis } from '@/decorators.js'; import { QueueService } from '@/core/QueueService.js'; import { RedisKVCache } from '@/misc/cache.js'; import { RoleService } from '@/core/RoleService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; @Injectable() export class UserListService implements OnApplicationShutdown, OnModuleInit { @@ -43,8 +43,8 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit { private userEntityService: UserEntityService, private idService: IdService, private globalEventService: GlobalEventService, - private proxyAccountService: ProxyAccountService, private queueService: QueueService, + private systemAccountService: SystemAccountService, ) { this.membersCache = new RedisKVCache>(this.redisClient, 'userListMembers', { lifetime: 1000 * 60 * 30, // 30m @@ -111,10 +111,8 @@ export class UserListService implements OnApplicationShutdown, OnModuleInit { // このインスタンス内にこのリモートユーザーをフォローしているユーザーがいなくても投稿を受け取るためにダミーのユーザーがフォローしたということにする if (this.userEntityService.isRemoteUser(target)) { - const proxy = await this.proxyAccountService.fetch(); - if (proxy) { - this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: target.id } }]); - } + const proxy = await this.systemAccountService.fetch('proxy'); + this.queueService.createFollowJob([{ from: { id: proxy.id }, to: { id: target.id } }]); } } diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 555a39f71c..f83dec67bf 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -73,7 +73,6 @@ function generateDummyUser(override?: Partial): MiUser { isLocked: false, isBot: false, isCat: true, - isRoot: false, isExplorable: true, isHibernated: false, isDeleted: false, diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index 8688015aff..83a095cdea 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -23,7 +23,7 @@ import { MfmService } from '@/core/MfmService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { MiUserKeypair } from '@/models/UserKeypair.js'; -import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository } from '@/models/_.js'; +import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository, MiMeta } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { IdService } from '@/core/IdService.js'; @@ -39,6 +39,9 @@ export class ApRendererService { @Inject(DI.config) private config: Config, + @Inject(DI.meta) + private meta: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -186,7 +189,7 @@ export class ApRendererService { url: emoji.publicUrl || emoji.originalUrl, }, _misskey_license: { - freeText: emoji.license + freeText: emoji.license, }, }; } @@ -255,6 +258,38 @@ export class ApRendererService { }; } + @bindThis + public renderIdenticon(user: MiLocalUser): IApImage { + return { + type: 'Image', + url: this.userEntityService.getIdenticonUrl(user), + sensitive: false, + name: null, + }; + } + + @bindThis + public renderSystemAvatar(user: MiLocalUser): IApImage { + if (this.meta.iconUrl == null) return this.renderIdenticon(user); + return { + type: 'Image', + url: this.meta.iconUrl, + sensitive: false, + name: null, + }; + } + + @bindThis + public renderSystemBanner(): IApImage | null { + if (this.meta.bannerUrl == null) return null; + return { + type: 'Image', + url: this.meta.bannerUrl, + sensitive: false, + name: null, + }; + } + @bindThis public renderKey(user: MiLocalUser, key: MiUserKeypair, postfix?: string): IKey { return { @@ -503,8 +538,8 @@ export class ApRendererService { _misskey_requireSigninToViewContents: user.requireSigninToViewContents, _misskey_makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore, _misskey_makeNotesHiddenBefore: user.makeNotesHiddenBefore, - icon: avatar ? this.renderImage(avatar) : null, - image: banner ? this.renderImage(banner) : null, + icon: avatar ? this.renderImage(avatar) : isSystem ? this.renderSystemAvatar(user) : this.renderIdenticon(user), + image: banner ? this.renderImage(banner) : isSystem ? this.renderSystemBanner() : null, tag, manuallyApprovesFollowers: user.isLocked, discoverable: user.isExplorable, diff --git a/packages/backend/src/core/activitypub/ApResolverService.ts b/packages/backend/src/core/activitypub/ApResolverService.ts index fb963294cb..2534899ad1 100644 --- a/packages/backend/src/core/activitypub/ApResolverService.ts +++ b/packages/backend/src/core/activitypub/ApResolverService.ts @@ -6,7 +6,6 @@ import { Inject, Injectable } from '@nestjs/common'; import { IsNull, Not } from 'typeorm'; import type { MiLocalUser, MiRemoteUser } from '@/models/User.js'; -import { InstanceActorService } from '@/core/InstanceActorService.js'; import type { NotesRepository, PollsRepository, NoteReactionsRepository, UsersRepository, FollowRequestsRepository, MiMeta } from '@/models/_.js'; import type { Config } from '@/config.js'; import { HttpRequestService } from '@/core/HttpRequestService.js'; @@ -15,13 +14,14 @@ import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; import { LoggerService } from '@/core/LoggerService.js'; import type Logger from '@/logger.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; +import { IdentifiableError } from '@/misc/identifiable-error.js'; import { isCollectionOrOrderedCollection } from './type.js'; import { ApDbResolverService } from './ApDbResolverService.js'; import { ApRendererService } from './ApRendererService.js'; import { ApRequestService } from './ApRequestService.js'; -import type { IObject, ICollection, IOrderedCollection } from './type.js'; -import { IdentifiableError } from '@/misc/identifiable-error.js'; import { FetchAllowSoftFailMask } from './misc/check-against-url.js'; +import type { IObject, ICollection, IOrderedCollection } from './type.js'; export class Resolver { private history: Set; @@ -37,7 +37,7 @@ export class Resolver { private noteReactionsRepository: NoteReactionsRepository, private followRequestsRepository: FollowRequestsRepository, private utilityService: UtilityService, - private instanceActorService: InstanceActorService, + private systemAccountService: SystemAccountService, private apRequestService: ApRequestService, private httpRequestService: HttpRequestService, private apRendererService: ApRendererService, @@ -105,7 +105,7 @@ export class Resolver { } if (this.config.signToActivityPubGet && !this.user) { - this.user = await this.instanceActorService.getInstanceActor(); + this.user = await this.systemAccountService.fetch('actor'); } const object = (this.user @@ -119,7 +119,7 @@ export class Resolver { ) { throw new IdentifiableError('72180409-793c-4973-868e-5a118eb5519b', 'invalid response'); } - + return object; } @@ -202,7 +202,7 @@ export class ApResolverService { private followRequestsRepository: FollowRequestsRepository, private utilityService: UtilityService, - private instanceActorService: InstanceActorService, + private systemAccountService: SystemAccountService, private apRequestService: ApRequestService, private httpRequestService: HttpRequestService, private apRendererService: ApRendererService, @@ -222,7 +222,7 @@ export class ApResolverService { this.noteReactionsRepository, this.followRequestsRepository, this.utilityService, - this.instanceActorService, + this.systemAccountService, this.apRequestService, this.httpRequestService, this.apRendererService, diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 7ad6071ceb..08717bd066 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -11,8 +11,7 @@ import type { MiMeta } from '@/models/Meta.js'; import type { AdsRepository } from '@/models/_.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import { bindThis } from '@/decorators.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { InstanceActorService } from '@/core/InstanceActorService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; @@ -29,8 +28,7 @@ export class MetaEntityService { @Inject(DI.adsRepository) private adsRepository: AdsRepository, - private userEntityService: UserEntityService, - private instanceActorService: InstanceActorService, + private systemAccountService: SystemAccountService, ) { } @bindThis @@ -149,14 +147,14 @@ export class MetaEntityService { const packed = await this.pack(instance); - const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null; + const proxyAccount = await this.systemAccountService.fetch('proxy'); const packDetailed: Packed<'MetaDetailed'> = { ...packed, cacheRemoteFiles: instance.cacheRemoteFiles, cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles, - requireSetup: !await this.instanceActorService.realLocalUsersPresent(), - proxyAccountName: proxyAccount ? proxyAccount.username : null, + requireSetup: this.meta.rootUserId == null, + proxyAccountName: proxyAccount.username, features: { localTimeline: instance.policies.ltlAvailable, globalTimeline: instance.policies.gtlAvailable, diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index fbd3892dd4..69f698d9cb 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -28,6 +28,7 @@ import type { FollowingsRepository, FollowRequestsRepository, MiFollowing, + MiMeta, MiUserNotePining, MiUserProfile, MutingsRepository, @@ -100,6 +101,9 @@ export class UserEntityService implements OnModuleInit { @Inject(DI.config) private config: Config, + @Inject(DI.meta) + private meta: MiMeta, + @Inject(DI.redis) private redisClient: Redis.Redis, @@ -381,7 +385,11 @@ export class UserEntityService implements OnModuleInit { @bindThis public getIdenticonUrl(user: MiUser): string { - return `${this.config.url}/identicon/${user.username.toLowerCase()}@${user.host ?? this.config.host}`; + if ((user.host == null || user.host === this.config.host) && user.username.includes('.') && this.meta.iconUrl) { // ローカルのシステムアカウントの場合 + return this.meta.iconUrl; + } else { + return `${this.config.url}/identicon/${user.username.toLowerCase()}@${user.host ?? this.config.host}`; + } } @bindThis diff --git a/packages/backend/src/di-symbols.ts b/packages/backend/src/di-symbols.ts index e599fc7b37..a306aac1a1 100644 --- a/packages/backend/src/di-symbols.ts +++ b/packages/backend/src/di-symbols.ts @@ -74,6 +74,7 @@ export const DI = { registryItemsRepository: Symbol('registryItemsRepository'), webhooksRepository: Symbol('webhooksRepository'), systemWebhooksRepository: Symbol('systemWebhooksRepository'), + systemAccountsRepository: Symbol('systemAccountsRepository'), adsRepository: Symbol('adsRepository'), passwordResetRequestsRepository: Symbol('passwordResetRequestsRepository'), retentionAggregationsRepository: Symbol('retentionAggregationsRepository'), diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index 9df2f74984..1fbf5371bc 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm'; +import { Entity, Column, PrimaryColumn, ManyToOne } from 'typeorm'; import { id } from './util/id.js'; import { MiUser } from './User.js'; @@ -15,6 +15,18 @@ export class MiMeta { }) public id: string; + @Column({ + ...id(), + nullable: true, + }) + public rootUserId: MiUser['id'] | null; + + @ManyToOne(type => MiUser, { + onDelete: 'SET NULL', + nullable: true, + }) + public rootUser: MiUser | null; + @Column('varchar', { length: 1024, nullable: true, }) @@ -172,18 +184,6 @@ export class MiMeta { }) public cacheRemoteSensitiveFiles: boolean; - @Column({ - ...id(), - nullable: true, - }) - public proxyAccountId: MiUser['id'] | null; - - @ManyToOne(type => MiUser, { - onDelete: 'SET NULL', - }) - @JoinColumn() - public proxyAccount: MiUser | null; - @Column('boolean', { default: false, }) diff --git a/packages/backend/src/models/RepositoryModule.ts b/packages/backend/src/models/RepositoryModule.ts index ea0f88baba..04a9df6cfb 100644 --- a/packages/backend/src/models/RepositoryModule.ts +++ b/packages/backend/src/models/RepositoryModule.ts @@ -3,7 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import type { Provider } from '@nestjs/common'; import { Module } from '@nestjs/common'; import { DI } from '@/di-symbols.js'; import { @@ -63,6 +62,7 @@ import { MiRoleAssignment, MiSignin, MiSwSubscription, + MiSystemAccount, MiSystemWebhook, MiUsedUsername, MiUser, @@ -77,8 +77,9 @@ import { MiUserProfile, MiUserPublickey, MiUserSecurityKey, - MiWebhook + MiWebhook, } from './_.js'; +import type { Provider } from '@nestjs/common'; import type { DataSource } from 'typeorm'; const $usersRepository: Provider = { @@ -285,6 +286,12 @@ const $swSubscriptionsRepository: Provider = { inject: [DI.db], }; +const $systemAccountsRepository: Provider = { + provide: DI.systemAccountsRepository, + useFactory: (db: DataSource) => db.getRepository(MiSystemAccount), + inject: [DI.db], +}; + const $hashtagsRepository: Provider = { provide: DI.hashtagsRepository, useFactory: (db: DataSource) => db.getRepository(MiHashtag).extend(miRepository as MiRepository), @@ -532,6 +539,7 @@ const $reversiGamesRepository: Provider = { $renoteMutingsRepository, $blockingsRepository, $swSubscriptionsRepository, + $systemAccountsRepository, $hashtagsRepository, $abuseUserReportsRepository, $abuseReportNotificationRecipientRepository, @@ -603,6 +611,7 @@ const $reversiGamesRepository: Provider = { $renoteMutingsRepository, $blockingsRepository, $swSubscriptionsRepository, + $systemAccountsRepository, $hashtagsRepository, $abuseUserReportsRepository, $abuseReportNotificationRecipientRepository, diff --git a/packages/backend/src/models/SystemAccount.ts b/packages/backend/src/models/SystemAccount.ts new file mode 100644 index 0000000000..f32880b81d --- /dev/null +++ b/packages/backend/src/models/SystemAccount.ts @@ -0,0 +1,31 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Column, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn } from 'typeorm'; +import { Serialized } from '@/types.js'; +import { id } from './util/id.js'; +import { MiUser } from './User.js'; + +@Entity('system_account') +@Index(['type'], { unique: true }) +export class MiSystemAccount { + @PrimaryColumn(id()) + public id: string; + + @Index() + @Column(id()) + public userId: MiUser['id']; + + @ManyToOne(type => MiUser, { + onDelete: 'CASCADE', + }) + @JoinColumn() + public user: MiUser | null; + + @Column('varchar', { + length: 256, + }) + public type: string; +} diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index 549d78a22c..630240efde 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -184,12 +184,6 @@ export class MiUser { }) public isCat: boolean; - @Column('boolean', { - default: false, - comment: 'Whether the User is the root.', - }) - public isRoot: boolean; - @Index() @Column('boolean', { default: true, diff --git a/packages/backend/src/models/_.ts b/packages/backend/src/models/_.ts index c72bdaa727..fa15760c00 100644 --- a/packages/backend/src/models/_.ts +++ b/packages/backend/src/models/_.ts @@ -56,6 +56,7 @@ import { MiRegistryItem } from '@/models/RegistryItem.js'; import { MiRelay } from '@/models/Relay.js'; import { MiSignin } from '@/models/Signin.js'; import { MiSwSubscription } from '@/models/SwSubscription.js'; +import { MiSystemAccount } from '@/models/SystemAccount.js'; import { MiUsedUsername } from '@/models/UsedUsername.js'; import { MiUser } from '@/models/User.js'; import { MiUserIp } from '@/models/UserIp.js'; @@ -171,6 +172,7 @@ export { MiRelay, MiSignin, MiSwSubscription, + MiSystemAccount, MiUsedUsername, MiUser, MiUserIp, @@ -242,6 +244,7 @@ export type RegistryItemsRepository = Repository & MiRepository< export type RelaysRepository = Repository & MiRepository; export type SigninsRepository = Repository & MiRepository; export type SwSubscriptionsRepository = Repository & MiRepository; +export type SystemAccountsRepository = Repository & MiRepository; export type UsedUsernamesRepository = Repository & MiRepository; export type UsersRepository = Repository & MiRepository; export type UserIpsRepository = Repository & MiRepository; diff --git a/packages/backend/src/postgres.ts b/packages/backend/src/postgres.ts index 8a0b7d97d7..043332d4b5 100644 --- a/packages/backend/src/postgres.ts +++ b/packages/backend/src/postgres.ts @@ -82,6 +82,7 @@ import { MiReversiGame } from '@/models/ReversiGame.js'; import { Config } from '@/config.js'; import MisskeyLogger from '@/logger.js'; import { bindThis } from '@/decorators.js'; +import { MiSystemAccount } from './models/SystemAccount.js'; pg.types.setTypeParser(20, Number); @@ -206,6 +207,7 @@ export const entities = [ MiEmoji, MiHashtag, MiSwSubscription, + MiSystemAccount, MiAbuseUserReport, MiAbuseReportNotificationRecipient, MiRegistrationTicket, diff --git a/packages/backend/src/server/NodeinfoServerService.ts b/packages/backend/src/server/NodeinfoServerService.ts index 9a641007ee..239ef82dec 100644 --- a/packages/backend/src/server/NodeinfoServerService.ts +++ b/packages/backend/src/server/NodeinfoServerService.ts @@ -9,11 +9,11 @@ import type { Config } from '@/config.js'; import { MetaService } from '@/core/MetaService.js'; import { MAX_NOTE_TEXT_LENGTH } from '@/const.js'; import { MemorySingleCache } from '@/misc/cache.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { bindThis } from '@/decorators.js'; import NotesChart from '@/core/chart/charts/notes.js'; import UsersChart from '@/core/chart/charts/users.js'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; import type { FastifyInstance, FastifyPluginOptions } from 'fastify'; const nodeinfo2_1path = '/nodeinfo/2.1'; @@ -26,7 +26,7 @@ export class NodeinfoServerService { @Inject(DI.config) private config: Config, - private userEntityService: UserEntityService, + private systemAccountService: SystemAccountService, private metaService: MetaService, private notesChart: NotesChart, private usersChart: UsersChart, @@ -70,7 +70,7 @@ export class NodeinfoServerService { const activeHalfyear = null; const activeMonth = null; - const proxyAccount = meta.proxyAccountId ? await this.userEntityService.pack(meta.proxyAccountId).catch(() => null) : null; + const proxyAccount = await this.systemAccountService.fetch('proxy'); const basePolicies = { ...DEFAULT_POLICIES, ...meta.policies }; @@ -123,7 +123,7 @@ export class NodeinfoServerService { maxNoteTextLength: MAX_NOTE_TEXT_LENGTH, enableEmail: meta.enableEmail, enableServiceWorker: meta.enableServiceWorker, - proxyAccountName: proxyAccount ? proxyAccount.username : null, + proxyAccountName: proxyAccount.username, themeColor: meta.themeColor ?? '#86b300', }, }; diff --git a/packages/backend/src/server/api/ApiCallService.ts b/packages/backend/src/server/api/ApiCallService.ts index aad833f126..9399aa61b0 100644 --- a/packages/backend/src/server/api/ApiCallService.ts +++ b/packages/backend/src/server/api/ApiCallService.ts @@ -371,7 +371,7 @@ export class ApiCallService implements OnApplicationShutdown { } } - if ((ep.meta.requireModerator || ep.meta.requireAdmin) && !user!.isRoot) { + if ((ep.meta.requireModerator || ep.meta.requireAdmin) && (this.meta.rootUserId !== user!.id)) { const myRoles = await this.roleService.getUserRoles(user!.id); if (ep.meta.requireModerator && !myRoles.some(r => r.isModerator || r.isAdministrator)) { throw new ApiError({ @@ -391,7 +391,7 @@ export class ApiCallService implements OnApplicationShutdown { } } - if (ep.meta.requireRolePolicy != null && !user!.isRoot) { + if (ep.meta.requireRolePolicy != null && (this.meta.rootUserId !== user!.id)) { const myRoles = await this.roleService.getUserRoles(user!.id); const policies = await this.roleService.getUserPolicies(user!.id); if (!policies[ep.meta.requireRolePolicy] && !myRoles.some(r => r.isAdministrator)) { diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 28f7cfea04..560d3f6587 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -100,6 +100,7 @@ export * as 'admin/unset-user-banner' from './endpoints/admin/unset-user-banner. export * as 'admin/unsuspend-user' from './endpoints/admin/unsuspend-user.js'; export * as 'admin/update-abuse-user-report' from './endpoints/admin/update-abuse-user-report.js'; export * as 'admin/update-meta' from './endpoints/admin/update-meta.js'; +export * as 'admin/update-proxy-account' from './endpoints/admin/update-proxy-account.js'; export * as 'admin/update-user-note' from './endpoints/admin/update-user-note.js'; export * as 'announcements' from './endpoints/announcements.js'; export * as 'announcements/show' from './endpoints/announcements/show.js'; diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts index d30131a62f..06047b58a6 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts @@ -4,12 +4,10 @@ */ import { Inject, Injectable } from '@nestjs/common'; -import { IsNull } from 'typeorm'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { UsersRepository } from '@/models/_.js'; +import type { MiMeta, UsersRepository } from '@/models/_.js'; import { SignupService } from '@/core/SignupService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { InstanceActorService } from '@/core/InstanceActorService.js'; import { localUsernameSchema, passwordSchema } from '@/models/User.js'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; @@ -62,18 +60,19 @@ export default class extends Endpoint { // eslint- @Inject(DI.config) private config: Config, + @Inject(DI.meta) + private serverSettings: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, private userEntityService: UserEntityService, private signupService: SignupService, - private instanceActorService: InstanceActorService, ) { super(meta, paramDef, async (ps, _me, token) => { const me = _me ? await this.usersRepository.findOneByOrFail({ id: _me.id }) : null; - const realUsers = await this.instanceActorService.realLocalUsersPresent(); - if (!realUsers && me == null && token == null) { + if (this.serverSettings.rootUserId == null && me == null && token == null) { // 初回セットアップの場合 if (this.config.setupPassword != null) { // 初期パスワードが設定されている場合 @@ -85,7 +84,7 @@ export default class extends Endpoint { // eslint- // 初期パスワードが設定されていないのに初期パスワードが入力された場合 throw new ApiError(meta.errors.wrongInitialPassword); } - } else if ((realUsers && !me?.isRoot) || token !== null) { + } else if ((this.serverSettings.rootUserId != null && (this.serverSettings.rootUserId !== me?.id)) || token !== null) { // 初回セットアップではなく、管理者でない場合 or 外部トークンを使用している場合 throw new ApiError(meta.errors.accessDenied); } diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts index ece1984cff..d04f52dd64 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/delete.ts @@ -42,10 +42,6 @@ export default class extends Endpoint { // eslint- throw new Error('user not found'); } - if (user.isRoot) { - throw new Error('cannot delete a root account'); - } - await this.deleteAccoountService.deleteAccount(user, me); }); } diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index 9d5691a427..53e2b2b237 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -9,6 +9,7 @@ import { MetaService } from '@/core/MetaService.js'; import type { Config } from '@/config.js'; import { DI } from '@/di-symbols.js'; import { DEFAULT_POLICIES } from '@/core/RoleService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; export const meta = { tags: ['meta'], @@ -237,7 +238,7 @@ export const meta = { }, proxyAccountId: { type: 'string', - optional: false, nullable: true, + optional: false, nullable: false, format: 'id', }, email: { @@ -545,10 +546,13 @@ export default class extends Endpoint { // eslint- private config: Config, private metaService: MetaService, + private systemAccountService: SystemAccountService, ) { super(meta, paramDef, async () => { const instance = await this.metaService.fetch(true); + const proxy = await this.systemAccountService.fetch('proxy'); + return { maintainerName: instance.maintainerName, maintainerEmail: instance.maintainerEmail, @@ -613,7 +617,7 @@ export default class extends Endpoint { // eslint- sensitiveMediaDetectionSensitivity: instance.sensitiveMediaDetectionSensitivity, setSensitiveFlagAutomatically: instance.setSensitiveFlagAutomatically, enableSensitiveMediaDetectionForVideos: instance.enableSensitiveMediaDetectionForVideos, - proxyAccountId: instance.proxyAccountId, + proxyAccountId: proxy.id, email: instance.email, smtpSecure: instance.smtpSecure, smtpHost: instance.smtpHost, diff --git a/packages/backend/src/server/api/endpoints/admin/reset-password.ts b/packages/backend/src/server/api/endpoints/admin/reset-password.ts index 53db096c1d..fc246631c2 100644 --- a/packages/backend/src/server/api/endpoints/admin/reset-password.ts +++ b/packages/backend/src/server/api/endpoints/admin/reset-password.ts @@ -6,7 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import bcrypt from 'bcryptjs'; import { Endpoint } from '@/server/api/endpoint-base.js'; -import type { UsersRepository, UserProfilesRepository } from '@/models/_.js'; +import type { UsersRepository, UserProfilesRepository, MiMeta } from '@/models/_.js'; import { DI } from '@/di-symbols.js'; import { secureRndstr } from '@/misc/secure-rndstr.js'; import { ModerationLogService } from '@/core/ModerationLogService.js'; @@ -43,6 +43,9 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( + @Inject(DI.meta) + private serverSettings: MiMeta, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, @@ -58,7 +61,7 @@ export default class extends Endpoint { // eslint- throw new Error('user not found'); } - if (user.isRoot) { + if (this.serverSettings.rootUserId === user.id) { throw new Error('cannot reset password of root'); } diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index 45c012cb0a..bc05587668 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -89,7 +89,6 @@ export const paramDef = { sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] }, setSensitiveFlagAutomatically: { type: 'boolean' }, enableSensitiveMediaDetectionForVideos: { type: 'boolean' }, - proxyAccountId: { type: 'string', format: 'misskey:id', nullable: true }, maintainerName: { type: 'string', nullable: true }, maintainerEmail: { type: 'string', nullable: true }, langs: { @@ -394,10 +393,6 @@ export default class extends Endpoint { // eslint- set.enableSensitiveMediaDetectionForVideos = ps.enableSensitiveMediaDetectionForVideos; } - if (ps.proxyAccountId !== undefined) { - set.proxyAccountId = ps.proxyAccountId; - } - if (ps.maintainerName !== undefined) { set.maintainerName = ps.maintainerName; } diff --git a/packages/backend/src/server/api/endpoints/admin/update-proxy-account.ts b/packages/backend/src/server/api/endpoints/admin/update-proxy-account.ts new file mode 100644 index 0000000000..6c9612c71a --- /dev/null +++ b/packages/backend/src/server/api/endpoints/admin/update-proxy-account.ts @@ -0,0 +1,62 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Injectable } from '@nestjs/common'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { + descriptionSchema, +} from '@/models/User.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { ModerationLogService } from '@/core/ModerationLogService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; + +export const meta = { + tags: ['admin'], + + requireCredential: true, + requireModerator: true, + kind: 'write:admin:account', + + res: { + type: 'object', + nullable: false, optional: false, + ref: 'UserDetailed', + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + description: { ...descriptionSchema, nullable: true }, + }, +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private userEntityService: UserEntityService, + private moderationLogService: ModerationLogService, + private systemAccountService: SystemAccountService, + ) { + super(meta, paramDef, async (ps, me) => { + const proxy = await this.systemAccountService.updateCorrespondingUserProfile('proxy', { + description: ps.description, + }); + + const updated = await this.userEntityService.pack(proxy.id, proxy, { + schema: 'MeDetailed', + }); + + if (ps.description !== undefined) { + this.moderationLogService.log(me, 'updateProxyAccountDescription', { + before: null, //TODO + after: ps.description, + }); + } + + return updated; + }); + } +} diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts index 1bd641232c..7852b5a2e1 100644 --- a/packages/backend/src/server/api/endpoints/i/move.ts +++ b/packages/backend/src/server/api/endpoints/i/move.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Injectable } from '@nestjs/common'; +import { Inject, Injectable } from '@nestjs/common'; import ms from 'ms'; import { Endpoint } from '@/server/api/endpoint-base.js'; @@ -19,6 +19,8 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import * as Acct from '@/misc/acct.js'; +import { DI } from '@/di-symbols.js'; +import { MiMeta } from '@/models/_.js'; export const meta = { tags: ['users'], @@ -81,6 +83,9 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( + @Inject(DI.meta) + private serverSettings: MiMeta, + private remoteUserResolveService: RemoteUserResolveService, private apiLoggerService: ApiLoggerService, private accountMoveService: AccountMoveService, @@ -92,7 +97,7 @@ export default class extends Endpoint { // eslint- // check parameter if (!ps.moveToAccount) throw new ApiError(meta.errors.noSuchUser); // abort if user is the root - if (me.isRoot) throw new ApiError(meta.errors.rootForbidden); + if (this.serverSettings.rootUserId === me.id) throw new ApiError(meta.errors.rootForbidden); // abort if user has already moved if (me.movedToUri) throw new ApiError(meta.errors.alreadyMoved); diff --git a/packages/backend/src/server/api/endpoints/reset-db.ts b/packages/backend/src/server/api/endpoints/reset-db.ts index 67d5fabd86..552362b64a 100644 --- a/packages/backend/src/server/api/endpoints/reset-db.ts +++ b/packages/backend/src/server/api/endpoints/reset-db.ts @@ -6,9 +6,12 @@ import { Inject, Injectable } from '@nestjs/common'; import { DataSource } from 'typeorm'; import * as Redis from 'ioredis'; +import { LoggerService } from '@/core/LoggerService.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { DI } from '@/di-symbols.js'; import { resetDb } from '@/misc/reset-db.js'; +import { MetaService } from '@/core/MetaService.js'; +import { GlobalEventService } from '@/core/GlobalEventService.js'; export const meta = { tags: ['non-productive'], @@ -36,13 +39,27 @@ export default class extends Endpoint { // eslint- @Inject(DI.redis) private redisClient: Redis.Redis, + + private loggerService: LoggerService, + private metaService: MetaService, + private globalEventService: GlobalEventService, ) { super(meta, paramDef, async (ps, me) => { if (process.env.NODE_ENV !== 'test') throw new Error('NODE_ENV is not a test'); - await redisClient.flushdb(); + const logger = this.loggerService.getLogger('reset-db'); + logger.info('---- Resetting database...'); + + await this.redisClient.flushdb(); await resetDb(this.db); + // DIコンテナで管理しているmetaのインスタンスには上記のリセット処理が届かないため、 + // 初期値を流して明示的にリフレッシュする + const meta = await this.metaService.fetch(true); + this.globalEventService.publishInternalEvent('metaUpdated', { after: meta }); + + logger.info('---- Database reset complete.'); + await new Promise(resolve => setTimeout(resolve, 1000)); }); } diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index bf409031c8..c6b1035554 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -122,6 +122,7 @@ export const moderationLogTypes = [ 'deletePage', 'deleteFlash', 'deleteGalleryPost', + 'updateProxyAccountDescription', ] as const; export type ModerationLogPayloads = { @@ -374,25 +375,29 @@ export type ModerationLogPayloads = { postUserUsername: string; post: any; }; + updateProxyAccountDescription: { + before: string | null; + after: string | null; + }; }; export type Serialized = { [K in keyof T]: - T[K] extends Date - ? string - : T[K] extends (Date | null) - ? (string | null) - : T[K] extends Record - ? Serialized - : T[K] extends (Record | null) + T[K] extends Date + ? string + : T[K] extends (Date | null) + ? (string | null) + : T[K] extends Record + ? Serialized + : T[K] extends (Record | null) ? (Serialized | null) - : T[K] extends (Record | undefined) + : T[K] extends (Record | undefined) ? (Serialized | undefined) - : T[K]; + : T[K]; }; export type FilterUnionByProperty< - Union, - Property extends string | number | symbol, - Condition + Union, + Property extends string | number | symbol, + Condition, > = Union extends Record ? Union : never; diff --git a/packages/backend/test-federation/compose.yml b/packages/backend/test-federation/compose.yml index a5a7223982..ed39109aab 100644 --- a/packages/backend/test-federation/compose.yml +++ b/packages/backend/test-federation/compose.yml @@ -20,8 +20,12 @@ services: depends_on: a.test: condition: service_healthy + misskey.a.test: + condition: service_healthy b.test: condition: service_healthy + misskey.b.test: + condition: service_healthy environment: - NODE_ENV=development - NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/rootCA.crt diff --git a/packages/backend/test-federation/test/abuse-report.test.ts b/packages/backend/test-federation/test/abuse-report.test.ts index b54d6222b4..ddc8e4f9d0 100644 --- a/packages/backend/test-federation/test/abuse-report.test.ts +++ b/packages/backend/test-federation/test/abuse-report.test.ts @@ -35,7 +35,7 @@ describe('Abuse report', () => { const reportsInB = await bModerator.client.request('admin/abuse-user-reports', {}); const reportInB = reportsInB.filter(report => report.comment.includes(comment))[0]; // NOTE: reporter is not Alice, and is not moderator in A - strictEqual(reportInB.reporter.url, 'https://a.test/@instance.actor'); + strictEqual(reportInB.reporter.url, 'https://a.test/@system.actor'); strictEqual(reportInB.targetUserId, bob.id); // NOTE: cannot forward multiple times diff --git a/packages/backend/test-federation/test/user.test.ts b/packages/backend/test-federation/test/user.test.ts index 76605e61d4..83dcb8df44 100644 --- a/packages/backend/test-federation/test/user.test.ts +++ b/packages/backend/test-federation/test/user.test.ts @@ -37,6 +37,7 @@ describe('User', () => { 'id', 'host', 'avatarUrl', + 'avatarBlurhash', 'instance', 'badgeRoles', 'url', @@ -379,7 +380,8 @@ describe('User', () => { strictEqual(followers.length, 1); // followed by Bob await alice.client.request('i/delete-account', { password: alice.password }); - await sleep(); + // NOTE: user deletion query is slow + await sleep(4000); const following = await bob.client.request('users/following', { userId: bob.id }); strictEqual(following.length, 0); // no following relation @@ -477,7 +479,8 @@ describe('User', () => { strictEqual(followers.length, 1); // followed by Bob await aAdmin.client.request('admin/suspend-user', { userId: alice.id }); - await sleep(); + // NOTE: user deletion query is slow + await sleep(4000); const following = await bob.client.request('users/following', { userId: bob.id }); strictEqual(following.length, 0); // no following relation diff --git a/packages/backend/test-federation/test/utils.ts b/packages/backend/test-federation/test/utils.ts index db8da5025a..2779eb7e81 100644 --- a/packages/backend/test-federation/test/utils.ts +++ b/packages/backend/test-federation/test/utils.ts @@ -36,7 +36,7 @@ export type Request = < type Host = 'a.test' | 'b.test'; -export async function sleep(ms = 200): Promise { +export async function sleep(ms = 250): Promise { return new Promise(resolve => setTimeout(resolve, ms)); } diff --git a/packages/backend/test/misc/mock-resolver.ts b/packages/backend/test/misc/mock-resolver.ts index c8f3db8aac..53ff4feb7e 100644 --- a/packages/backend/test/misc/mock-resolver.ts +++ b/packages/backend/test/misc/mock-resolver.ts @@ -7,14 +7,10 @@ import type { Config } from '@/config.js'; import type { ApDbResolverService } from '@/core/activitypub/ApDbResolverService.js'; import type { ApRendererService } from '@/core/activitypub/ApRendererService.js'; import type { ApRequestService } from '@/core/activitypub/ApRequestService.js'; -import { Resolver } from '@/core/activitypub/ApResolverService.js'; import type { IObject } from '@/core/activitypub/type.js'; import type { HttpRequestService } from '@/core/HttpRequestService.js'; -import type { InstanceActorService } from '@/core/InstanceActorService.js'; import type { LoggerService } from '@/core/LoggerService.js'; -import type { MetaService } from '@/core/MetaService.js'; import type { UtilityService } from '@/core/UtilityService.js'; -import { bindThis } from '@/decorators.js'; import type { FollowRequestsRepository, MiMeta, @@ -23,6 +19,9 @@ import type { PollsRepository, UsersRepository, } from '@/models/_.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; +import { bindThis } from '@/decorators.js'; +import { Resolver } from '@/core/activitypub/ApResolverService.js'; type MockResponse = { type: string; @@ -43,7 +42,7 @@ export class MockResolver extends Resolver { {} as NoteReactionsRepository, {} as FollowRequestsRepository, {} as UtilityService, - {} as InstanceActorService, + {} as SystemAccountService, {} as ApRequestService, {} as HttpRequestService, {} as ApRendererService, diff --git a/packages/backend/test/unit/AbuseReportNotificationService.ts b/packages/backend/test/unit/AbuseReportNotificationService.ts index 1326003c5e..6d555326fb 100644 --- a/packages/backend/test/unit/AbuseReportNotificationService.ts +++ b/packages/backend/test/unit/AbuseReportNotificationService.ts @@ -149,9 +149,9 @@ describe('AbuseReportNotificationService', () => { }); beforeEach(async () => { - root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); - alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false }); - bob = await createUser({ username: 'bob', usernameLower: 'bob', isRoot: false }); + root = await createUser({ username: 'root', usernameLower: 'root' }); + alice = await createUser({ username: 'alice', usernameLower: 'alice' }); + bob = await createUser({ username: 'bob', usernameLower: 'bob' }); systemWebhook1 = await createWebhook(); systemWebhook2 = await createWebhook(); diff --git a/packages/backend/test/unit/FlashService.ts b/packages/backend/test/unit/FlashService.ts index 12ffaf3421..f2d9832f50 100644 --- a/packages/backend/test/unit/FlashService.ts +++ b/packages/backend/test/unit/FlashService.ts @@ -79,9 +79,9 @@ describe('FlashService', () => { userProfilesRepository = app.get(DI.userProfilesRepository); idService = app.get(IdService); - root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); - alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false }); - bob = await createUser({ username: 'bob', usernameLower: 'bob', isRoot: false }); + root = await createUser({ username: 'root', usernameLower: 'root' }); + alice = await createUser({ username: 'alice', usernameLower: 'alice' }); + bob = await createUser({ username: 'bob', usernameLower: 'bob' }); }); afterEach(async () => { diff --git a/packages/backend/test/unit/RelayService.ts b/packages/backend/test/unit/RelayService.ts index 3b3d212c30..074430dd31 100644 --- a/packages/backend/test/unit/RelayService.ts +++ b/packages/backend/test/unit/RelayService.ts @@ -3,24 +3,21 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { UtilityService } from '@/core/UtilityService.js'; - process.env.NODE_ENV = 'test'; import { jest } from '@jest/globals'; -import { ModuleMocker } from 'jest-mock'; import { Test } from '@nestjs/testing'; -import { GlobalModule } from '@/GlobalModule.js'; -import { RelayService } from '@/core/RelayService.js'; -import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; -import { CreateSystemUserService } from '@/core/CreateSystemUserService.js'; -import { UserEntityService } from '@/core/entities/UserEntityService.js'; -import { QueueService } from '@/core/QueueService.js'; -import { IdService } from '@/core/IdService.js'; -import type { RelaysRepository } from '@/models/_.js'; -import { DI } from '@/di-symbols.js'; +import { ModuleMocker } from 'jest-mock'; import type { TestingModule } from '@nestjs/testing'; import type { MockFunctionMetadata } from 'jest-mock'; +import { ApRendererService } from '@/core/activitypub/ApRendererService.js'; +import { UserEntityService } from '@/core/entities/UserEntityService.js'; +import { IdService } from '@/core/IdService.js'; +import { QueueService } from '@/core/QueueService.js'; +import { RelayService } from '@/core/RelayService.js'; +import { SystemAccountService } from '@/core/SystemAccountService.js'; +import { GlobalModule } from '@/GlobalModule.js'; +import { UtilityService } from '@/core/UtilityService.js'; const moduleMocker = new ModuleMocker(global); @@ -28,8 +25,6 @@ describe('RelayService', () => { let app: TestingModule; let relayService: RelayService; let queueService: jest.Mocked; - let relaysRepository: RelaysRepository; - let userEntityService: UserEntityService; beforeAll(async () => { app = await Test.createTestingModule({ @@ -38,10 +33,10 @@ describe('RelayService', () => { ], providers: [ IdService, - CreateSystemUserService, ApRendererService, RelayService, UserEntityService, + SystemAccountService, UtilityService, ], }) @@ -61,8 +56,6 @@ describe('RelayService', () => { relayService = app.get(RelayService); queueService = app.get(QueueService) as jest.Mocked; - relaysRepository = app.get(DI.relaysRepository); - userEntityService = app.get(UserEntityService); }); afterAll(async () => { diff --git a/packages/backend/test/unit/RoleService.ts b/packages/backend/test/unit/RoleService.ts index 9c1b1008d6..553ff0982a 100644 --- a/packages/backend/test/unit/RoleService.ts +++ b/packages/backend/test/unit/RoleService.ts @@ -57,6 +57,12 @@ describe('RoleService', () => { return await usersRepository.findOneByOrFail(x.identifiers[0]); } + async function createRoot(data: Partial = {}) { + const user = await createUser(data); + meta.rootUserId = user.id; + return user; + } + async function createRole(data: Partial = {}) { const x = await rolesRepository.insert({ id: genAidx(Date.now()), @@ -279,7 +285,7 @@ describe('RoleService', () => { describe('getModeratorIds', () => { test('includeAdmins = false, includeRoot = false, excludeExpire = false', async () => { const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -305,7 +311,7 @@ describe('RoleService', () => { test('includeAdmins = false, includeRoot = false, excludeExpire = true', async () => { const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -331,7 +337,7 @@ describe('RoleService', () => { test('includeAdmins = true, includeRoot = false, excludeExpire = false', async () => { const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -357,7 +363,7 @@ describe('RoleService', () => { test('includeAdmins = true, includeRoot = false, excludeExpire = true', async () => { const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -383,7 +389,7 @@ describe('RoleService', () => { test('includeAdmins = false, includeRoot = true, excludeExpire = false', async () => { const [adminUser1, adminUser2, modeUser1, modeUser2, normalUser1, normalUser2, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -409,7 +415,7 @@ describe('RoleService', () => { test('root has moderator role', async () => { const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -433,7 +439,7 @@ describe('RoleService', () => { test('root has administrator role', async () => { const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); @@ -457,7 +463,7 @@ describe('RoleService', () => { test('root has moderator role(expire)', async () => { const [adminUser1, modeUser1, normalUser1, rootUser] = await Promise.all([ - createUser(), createUser(), createUser(), createUser({ isRoot: true }), + createUser(), createUser(), createUser(), createRoot(), ]); const role1 = await createRole({ name: 'admin', isAdministrator: true }); diff --git a/packages/backend/test/unit/SystemWebhookService.ts b/packages/backend/test/unit/SystemWebhookService.ts index fee4acb305..61187e9f2a 100644 --- a/packages/backend/test/unit/SystemWebhookService.ts +++ b/packages/backend/test/unit/SystemWebhookService.ts @@ -97,7 +97,7 @@ describe('SystemWebhookService', () => { } async function beforeEachImpl() { - root = await createUser({ isRoot: true, username: 'root', usernameLower: 'root' }); + root = await createUser({ username: 'root', usernameLower: 'root' }); } async function afterEachImpl() { diff --git a/packages/backend/test/unit/UserSearchService.ts b/packages/backend/test/unit/UserSearchService.ts index 7ea325d420..66a7f39ff1 100644 --- a/packages/backend/test/unit/UserSearchService.ts +++ b/packages/backend/test/unit/UserSearchService.ts @@ -113,7 +113,7 @@ describe('UserSearchService', () => { }); beforeEach(async () => { - root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); + root = await createUser({ username: 'root', usernameLower: 'root' }); alice = await createUser({ username: 'Alice', usernameLower: 'alice' }); alyce = await createUser({ username: 'Alyce', usernameLower: 'alyce' }); alycia = await createUser({ username: 'Alycia', usernameLower: 'alycia' }); diff --git a/packages/backend/test/unit/UserWebhookService.ts b/packages/backend/test/unit/UserWebhookService.ts index db8f96df28..a2a85e9489 100644 --- a/packages/backend/test/unit/UserWebhookService.ts +++ b/packages/backend/test/unit/UserWebhookService.ts @@ -91,7 +91,7 @@ describe('UserWebhookService', () => { } async function beforeEachImpl() { - root = await createUser({ isRoot: true, username: 'root', usernameLower: 'root' }); + root = await createUser({ username: 'root', usernameLower: 'root' }); } async function afterEachImpl() { diff --git a/packages/backend/test/unit/WebhookTestService.ts b/packages/backend/test/unit/WebhookTestService.ts index be84ae9b84..45bc932469 100644 --- a/packages/backend/test/unit/WebhookTestService.ts +++ b/packages/backend/test/unit/WebhookTestService.ts @@ -88,8 +88,8 @@ describe('WebhookTestService', () => { }); beforeEach(async () => { - root = await createUser({ username: 'root', usernameLower: 'root', isRoot: true }); - alice = await createUser({ username: 'alice', usernameLower: 'alice', isRoot: false }); + root = await createUser({ username: 'root', usernameLower: 'root' }); + alice = await createUser({ username: 'alice', usernameLower: 'alice' }); userWebhookService.fetchWebhooks.mockReturnValue(Promise.resolve([ { id: 'dummy-webhook', active: true, userId: alice.id } as MiWebhook, diff --git a/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts b/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts index d96e6b916a..07618e7762 100644 --- a/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts +++ b/packages/backend/test/unit/queue/processors/CheckModeratorsActivityProcessorService.ts @@ -316,7 +316,7 @@ describe('CheckModeratorsActivityProcessorService', () => { createUser({}, { email: 'user2@example.com', emailVerified: false }), createUser({}, { email: null, emailVerified: false }), createUser({}, { email: 'user4@example.com', emailVerified: true }), - createUser({ isRoot: true }, { email: 'root@example.com', emailVerified: true }), + createUser({}, { email: 'root@example.com', emailVerified: true }), ]); mockModeratorRole([user1, user2, user3, root]); @@ -349,7 +349,7 @@ describe('CheckModeratorsActivityProcessorService', () => { createUser({}, { email: 'user2@example.com', emailVerified: false }), createUser({}, { email: null, emailVerified: false }), createUser({}, { email: 'user4@example.com', emailVerified: true }), - createUser({ isRoot: true }, { email: 'root@example.com', emailVerified: true }), + createUser({}, { email: 'root@example.com', emailVerified: true }), ]); mockModeratorRole([user1, user2, user3, root]); diff --git a/packages/frontend/src/pages/admin-user.vue b/packages/frontend/src/pages/admin-user.vue index fa08c213e2..578945bf07 100644 --- a/packages/frontend/src/pages/admin-user.vue +++ b/packages/frontend/src/pages/admin-user.vue @@ -22,7 +22,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ i18n.ts.isSystemAccount }} + {{ i18n.ts.isSystemAccount }} {{ i18n.ts.instanceInfo }} @@ -37,21 +37,23 @@ SPDX-License-Identifier: AGPL-3.0-only --> - - - - - - - - - - - - + - + @@ -92,7 +94,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> - +
{{ i18n.ts.suspend }} @@ -252,6 +254,7 @@ const ap = ref(null); const moderator = ref(false); const silenced = ref(false); const suspended = ref(false); +const isSystem = ref(false); const moderationNote = ref(''); const filesPagination = { endpoint: 'admin/drive/files' as const, @@ -288,6 +291,7 @@ function createFetcher() { silenced.value = info.value.isSilenced; suspended.value = info.value.isSuspended; moderationNote.value = info.value.moderationNote; + isSystem.value = user.value.host == null && user.value.username.includes('.'); watch(moderationNote, async () => { await misskeyApi('admin/update-user-note', { userId: user.value.id, text: moderationNote.value }); @@ -507,7 +511,15 @@ watch(user, () => { const headerActions = computed(() => []); -const headerTabs = computed(() => [{ +const headerTabs = computed(() => isSystem.value ? [{ + key: 'overview', + title: i18n.ts.overview, + icon: 'ti ti-info-circle', +}, { + key: 'raw', + title: 'Raw', + icon: 'ti ti-code', +}] : [{ key: 'overview', title: i18n.ts.overview, icon: 'ti ti-info-circle', diff --git a/packages/frontend/src/pages/admin/modlog.ModLog.vue b/packages/frontend/src/pages/admin/modlog.ModLog.vue index 1e144394fb..9bbe5f2e42 100644 --- a/packages/frontend/src/pages/admin/modlog.ModLog.vue +++ b/packages/frontend/src/pages/admin/modlog.ModLog.vue @@ -170,6 +170,11 @@ SPDX-License-Identifier: AGPL-3.0-only
+
raw diff --git a/packages/frontend/src/pages/admin/settings.vue b/packages/frontend/src/pages/admin/settings.vue index ea7603a45a..aed593fc54 100644 --- a/packages/frontend/src/pages/admin/settings.vue +++ b/packages/frontend/src/pages/admin/settings.vue @@ -238,15 +238,17 @@ SPDX-License-Identifier: AGPL-3.0-only +
{{ i18n.ts.proxyAccountDescription }} - - - - - {{ i18n.ts.selectAccount }} + + + +
@@ -256,7 +258,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/global/SearchKeyword.vue b/packages/frontend/src/components/global/SearchKeyword.vue new file mode 100644 index 0000000000..27a284faf0 --- /dev/null +++ b/packages/frontend/src/components/global/SearchKeyword.vue @@ -0,0 +1,14 @@ + + + + + + + diff --git a/packages/frontend/src/components/global/SearchLabel.vue b/packages/frontend/src/components/global/SearchLabel.vue new file mode 100644 index 0000000000..27a284faf0 --- /dev/null +++ b/packages/frontend/src/components/global/SearchLabel.vue @@ -0,0 +1,14 @@ + + + + + + + diff --git a/packages/frontend/src/components/global/SearchMarker.vue b/packages/frontend/src/components/global/SearchMarker.vue new file mode 100644 index 0000000000..c5ec626cf4 --- /dev/null +++ b/packages/frontend/src/components/global/SearchMarker.vue @@ -0,0 +1,116 @@ + + + + + + + diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index 0252bf0252..ebbad3e5b8 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -3,8 +3,6 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import type { App } from 'vue'; - import Mfm from './global/MkMfm.js'; import MkA from './global/MkA.vue'; import MkAcct from './global/MkAcct.vue'; @@ -26,6 +24,11 @@ import MkSpacer from './global/MkSpacer.vue'; import MkFooterSpacer from './global/MkFooterSpacer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue'; import MkLazy from './global/MkLazy.vue'; +import SearchMarker from './global/SearchMarker.vue'; +import SearchLabel from './global/SearchLabel.vue'; +import SearchKeyword from './global/SearchKeyword.vue'; + +import type { App } from 'vue'; export default function(app: App) { for (const [key, value] of Object.entries(components)) { @@ -55,6 +58,9 @@ export const components = { MkFooterSpacer: MkFooterSpacer, MkStickyContainer: MkStickyContainer, MkLazy: MkLazy, + SearchMarker: SearchMarker, + SearchLabel: SearchLabel, + SearchKeyword: SearchKeyword, }; declare module '@vue/runtime-core' { @@ -80,5 +86,8 @@ declare module '@vue/runtime-core' { MkFooterSpacer: typeof MkFooterSpacer; MkStickyContainer: typeof MkStickyContainer; MkLazy: typeof MkLazy; + SearchMarker: typeof SearchMarker; + SearchLabel: typeof SearchLabel; + SearchKeyword: typeof SearchKeyword; } } diff --git a/packages/frontend/src/pages/settings/2fa.vue b/packages/frontend/src/pages/settings/2fa.vue index 776f59dda3..806599e801 100644 --- a/packages/frontend/src/pages/settings/2fa.vue +++ b/packages/frontend/src/pages/settings/2fa.vue @@ -4,74 +4,82 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/pages/settings/appearance.vue b/packages/frontend/src/pages/settings/appearance.vue new file mode 100644 index 0000000000..465c2a38c2 --- /dev/null +++ b/packages/frontend/src/pages/settings/appearance.vue @@ -0,0 +1,287 @@ + + + + + diff --git a/packages/frontend/src/pages/settings/avatar-decoration.vue b/packages/frontend/src/pages/settings/avatar-decoration.vue index 9fca306f9f..79be2b9b1e 100644 --- a/packages/frontend/src/pages/settings/avatar-decoration.vue +++ b/packages/frontend/src/pages/settings/avatar-decoration.vue @@ -4,44 +4,46 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/pages/settings/import-export.vue b/packages/frontend/src/pages/settings/import-export.vue index 5acbc50756..6b67a9a1a8 100644 --- a/packages/frontend/src/pages/settings/import-export.vue +++ b/packages/frontend/src/pages/settings/import-export.vue @@ -4,118 +4,143 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 41e475eade..2e453aeb8f 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -8,11 +8,11 @@ SPDX-License-Identifier: AGPL-3.0-only ref="buttonEl" v-ripple="canToggle" class="_button" - :class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle, [$style.small]: defaultStore.state.reactionsDisplaySize === 'small', [$style.large]: defaultStore.state.reactionsDisplaySize === 'large' }]" + :class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle, [$style.small]: prefer.s.reactionsDisplaySize === 'small', [$style.large]: prefer.s.reactionsDisplaySize === 'large' }]" @click="toggleReaction()" @contextmenu.prevent.stop="menu" > - + {{ count }} @@ -30,11 +30,11 @@ import { useTooltip } from '@/scripts/use-tooltip.js'; import { $i } from '@/account.js'; import MkReactionEffect from '@/components/MkReactionEffect.vue'; import { claimAchievement } from '@/scripts/achievements.js'; -import { defaultStore } from '@/store.js'; import { i18n } from '@/i18n.js'; import * as sound from '@/scripts/sound.js'; import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js'; import { customEmojisMap } from '@/custom-emojis.js'; +import { prefer } from '@/preferences.js'; const props = defineProps<{ reaction: string; @@ -90,7 +90,7 @@ async function toggleReaction() { } }); } else { - if (defaultStore.state.confirmOnReact) { + if (prefer.s.confirmOnReact) { const confirm = await os.confirm({ type: 'question', text: i18n.tsx.reactAreYouSure({ emoji: props.reaction.replace('@.', '') }), @@ -135,7 +135,7 @@ async function menu(ev) { } function anime() { - if (document.hidden || !defaultStore.state.animation || buttonEl.value == null) return; + if (document.hidden || !prefer.s.animation || buttonEl.value == null) return; const rect = buttonEl.value.getBoundingClientRect(); const x = rect.left + 16; diff --git a/packages/frontend/src/components/MkReactionsViewer.vue b/packages/frontend/src/components/MkReactionsViewer.vue index 63b202f9f3..bb60db8d34 100644 --- a/packages/frontend/src/components/MkReactionsViewer.vue +++ b/packages/frontend/src/components/MkReactionsViewer.vue @@ -5,11 +5,11 @@ SPDX-License-Identifier: AGPL-3.0-only From 161706c5e2f39347989b499b799aa12bad30b677 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:01:20 +0900 Subject: [PATCH 216/649] New Crowdin updates (#15680) * New translations ja-jp.yml (Czech) * New translations ja-jp.yml (English) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Russian) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Portuguese) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (English) * New translations ja-jp.yml (Japanese, Kansai) * New translations ja-jp.yml (Romanian) * New translations ja-jp.yml (French) * New translations ja-jp.yml (Spanish) * New translations ja-jp.yml (Arabic) * New translations ja-jp.yml (Czech) * New translations ja-jp.yml (German) * New translations ja-jp.yml (Greek) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Dutch) * New translations ja-jp.yml (Norwegian) * New translations ja-jp.yml (Polish) * New translations ja-jp.yml (Slovak) * New translations ja-jp.yml (Swedish) * New translations ja-jp.yml (Ukrainian) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Vietnamese) * New translations ja-jp.yml (Indonesian) * New translations ja-jp.yml (Bengali) * New translations ja-jp.yml (Thai) * New translations ja-jp.yml (Uzbek) * New translations ja-jp.yml (Lao) * New translations ja-jp.yml (Korean (Gyeongsang)) --- locales/ar-SA.yml | 1 + locales/bn-BD.yml | 1 + locales/ca-ES.yml | 3 +-- locales/cs-CZ.yml | 5 +++++ locales/de-DE.yml | 3 +-- locales/el-GR.yml | 1 + locales/en-US.yml | 9 ++++----- locales/es-ES.yml | 3 +-- locales/fr-FR.yml | 3 +-- locales/id-ID.yml | 3 +-- locales/it-IT.yml | 3 +-- locales/ja-KS.yml | 3 +-- locales/ko-GS.yml | 1 + locales/ko-KR.yml | 3 +-- locales/lo-LA.yml | 1 + locales/nl-NL.yml | 1 + locales/no-NO.yml | 1 + locales/pl-PL.yml | 1 + locales/pt-PT.yml | 3 +-- locales/ro-RO.yml | 1 + locales/ru-RU.yml | 1 + locales/sk-SK.yml | 1 + locales/sv-SE.yml | 1 + locales/th-TH.yml | 3 +-- locales/uk-UA.yml | 1 + locales/uz-UZ.yml | 1 + locales/vi-VN.yml | 1 + locales/zh-CN.yml | 3 +-- locales/zh-TW.yml | 3 +-- 29 files changed, 36 insertions(+), 29 deletions(-) diff --git a/locales/ar-SA.yml b/locales/ar-SA.yml index 4966007061..5e936da80c 100644 --- a/locales/ar-SA.yml +++ b/locales/ar-SA.yml @@ -1013,6 +1013,7 @@ flip: "اقلب" lastNDays: "آخر {n} أيام" surrender: "ألغِ" postForm: "أنشئ ملاحظة" +information: "عن" _delivery: stop: "مُعلّق" _initialAccountSetting: diff --git a/locales/bn-BD.yml b/locales/bn-BD.yml index 6aea5a1999..36d142bd0b 100644 --- a/locales/bn-BD.yml +++ b/locales/bn-BD.yml @@ -853,6 +853,7 @@ renotes: "রিনোট" sourceCode: "সোর্স কোড" flip: "উল্টান" postForm: "নোট লিখুন" +information: "আপনার সম্পর্কে" _delivery: stop: "স্থগিত করা হয়েছে" _type: diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 44fb48f5f5..23b958252a 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -1334,6 +1334,7 @@ paste: "Pegar" emojiPalette: "Calaix d'emojis" postForm: "Formulari de publicació" textCount: "Nombre de caràcters " +information: "Informació" _emojiPalette: palettes: "Calaixos d'emojis" enableSyncBetweenDevicesForPalettes: "Activa la sincronització dels calaixos d'emojis entre dispositius" @@ -2673,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Assegura't que qui distribueix aquest recurs és fiable abans d'instal·lar-ho." _plugin: title: "Vols instal·lar aquest afegit?" - metaTitle: "Informació de l'afegit " _theme: title: "Vols instal·lar aquest tema?" - metaTitle: "Informació del tema" _meta: base: "Paleta de colors base" _vendorInfo: diff --git a/locales/cs-CZ.yml b/locales/cs-CZ.yml index a509280862..11ad97c3a5 100644 --- a/locales/cs-CZ.yml +++ b/locales/cs-CZ.yml @@ -169,6 +169,9 @@ addAccount: "Přidat účet" reloadAccountsList: "Obnovit list účtů" loginFailed: "Přihlášení se nezdařilo." showOnRemote: "Více na původním profilu" +continueOnRemote: "Pokračujte na původní profil" +chooseServerOnMisskeyHub: "Vyberete si server z Misskey Hubu" +inputHostName: "Zadejte doménu" general: "Obecně" wallpaper: "Obrázek na pozadí" setWallpaper: "Nastavení obrázku na pozadí" @@ -193,6 +196,7 @@ perHour: "za hodinu" perDay: "za den" stopActivityDelivery: "Přestat zasílat aktivitu" blockThisInstance: "Blokovat tuto instanci" +silenceThisInstance: "Utišit tuto instanci" operations: "Operace" software: "Software" version: "Verze" @@ -1099,6 +1103,7 @@ flip: "Otočit" lastNDays: "Posledních {n} dnů" surrender: "Zrušit" postForm: "Formulář pro odeslání" +information: "Informace" _delivery: stop: "Suspendováno" _type: diff --git a/locales/de-DE.yml b/locales/de-DE.yml index db692d65e5..c6cc416638 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -1309,6 +1309,7 @@ availableRoles: "Verfügbare Rollen" federationSpecified: "Dieser Server arbeitet mit Whitelist-Föderation. Er kann nicht mit anderen als den vom Administrator angegebenen Servern interagieren." federationDisabled: "Föderation ist auf diesem Server deaktiviert. Es ist nicht möglich, mit Benutzern auf anderen Servern zu interagieren." postForm: "Notizfenster" +information: "Über" _settings: webhook: "Webhook" _accountSettings: @@ -2524,10 +2525,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Überprüfe vor Installation die Vertrauenswürdigkeit des Vertreibers." _plugin: title: "Möchtest du dieses Plugin installieren?" - metaTitle: "Plugininformation" _theme: title: "Möchten du dieses Farbschema installieren?" - metaTitle: "Farbschemainfo" _meta: base: "Farbschemavorlage" _vendorInfo: diff --git a/locales/el-GR.yml b/locales/el-GR.yml index be81a824c7..727565ae21 100644 --- a/locales/el-GR.yml +++ b/locales/el-GR.yml @@ -289,6 +289,7 @@ icon: "Εικονίδιο" replies: "Απάντηση" renotes: "Κοινοποίηση σημειώματος" postForm: "Φόρμα δημοσίευσης" +information: "Πληροφορίες" _email: _follow: title: "Έχετε ένα νέο ακόλουθο" diff --git a/locales/en-US.yml b/locales/en-US.yml index 0d2a29edca..79805e65e1 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1317,7 +1317,7 @@ unmarkAsSensitiveConfirm: "Do you want to remove the sensitive designation for t preferences: "Preferences" accessibility: "Accessibility" preferencesProfile: "Preferences profile" -copyPreferenceId: "Copy the proference ID" +copyPreferenceId: "Copy the preference ID" resetToDefaultValue: "Revert to default" overrideByAccount: "Override by the account" untitled: "Untitled" @@ -1334,6 +1334,7 @@ paste: "Paste" emojiPalette: "Emoji palette" postForm: "Posting form" textCount: "Character count" +information: "About" _emojiPalette: palettes: "Palette" enableSyncBetweenDevicesForPalettes: "Enable palette sync between devices" @@ -2673,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Make sure the distributor of this resource is trustworthy before installation." _plugin: title: "Do you want to install this plugin?" - metaTitle: "Plugin information" _theme: title: "Do you want to install this theme?" - metaTitle: "Theme information" _meta: base: "Base color scheme" _vendorInfo: @@ -2877,8 +2876,8 @@ _selfXssPrevention: description2: "If you do not understand exactly what you are trying to paste, %cstop working right now and close this window." description3: "For more information, please refer to this. {link}" _followRequest: - recieved: "Received application" - sent: "Sent application" + recieved: "Received request" + sent: "Sent request" _remoteLookupErrors: _federationNotAllowed: title: "Unable to communicate with this server" diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 4933b41ddb..cd96d348c3 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -1300,6 +1300,7 @@ target: "Para" federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador." federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores" postForm: "Formulario" +information: "Información" _settings: webhook: "Webhook" _accountSettings: @@ -2521,10 +2522,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Asegúrate de que el distribuidor de este recurso es de confianza antes de proceder a la instalación." _plugin: title: "¿Quieres instalar este plugin?" - metaTitle: "Información del plugin" _theme: title: "¿Quieres instalar este tema?" - metaTitle: "Información del tema" _meta: base: "Esquema de color base" _vendorInfo: diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml index 6d3a3bb882..4bdcd89422 100644 --- a/locales/fr-FR.yml +++ b/locales/fr-FR.yml @@ -1278,6 +1278,7 @@ lockdown: "Verrouiller" pleaseSelectAccount: "Sélectionner un compte" availableRoles: "Rôles disponibles" postForm: "Formulaire de publication" +information: "Informations" _abuseUserReport: forward: "Transférer" forwardDescription: "Transférer le signalement vers une instance distante en tant qu'anonyme." @@ -2295,10 +2296,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Veuillez confirmer que le distributeur est fiable avant l'installation." _plugin: title: "Voulez-vous installer cette extension ?" - metaTitle: "Informations sur l'extension" _theme: title: "Voulez-vous installer ce thème ?" - metaTitle: "Informations sur le thème" _meta: base: "Palette de couleurs de base" _vendorInfo: diff --git a/locales/id-ID.yml b/locales/id-ID.yml index 62ddc35cad..9a291ca381 100644 --- a/locales/id-ID.yml +++ b/locales/id-ID.yml @@ -1262,6 +1262,7 @@ modified: "Diubah" thereAreNChanges: "Ada {n} perubahan" prohibitedWordsForNameOfUser: "Kata yang dilarang untuk nama pengguna" postForm: "Buat catatan" +information: "Informasi" _settings: webhook: "Webhook" _abuseUserReport: @@ -2492,10 +2493,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Pastikan sumber dari sumber daya ini terpercaya sebelum melakukan pemasangan." _plugin: title: "Apakah kamu ingin memasang plugin ini?" - metaTitle: "Informasi plugin" _theme: title: "Apakah kamu ingin memasang tema ini?" - metaTitle: "Informasi tema" _meta: base: "Skema warna dasar" _vendorInfo: diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 7a39a8c0e6..4d17d0bf7b 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1334,6 +1334,7 @@ paste: "Incolla" emojiPalette: "Tavolozza emoji" postForm: "Finestra di pubblicazione" textCount: "Il numero di caratteri" +information: "Informazioni" _emojiPalette: palettes: "Tavolozza" enableSyncBetweenDevicesForPalettes: "Attiva la sincronizzazione tra dispositivi" @@ -2673,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Prima di installare, assicurati che la fonte sia affidabile." _plugin: title: "Vuoi davvero installare questo componente aggiuntivo?" - metaTitle: "Informazioni sul componente aggiuntivo" _theme: title: "Vuoi davvero installare questa variazione grafica?" - metaTitle: "Informazioni sulla variazione grafica" _meta: base: "Combinazione base di colori" _vendorInfo: diff --git a/locales/ja-KS.yml b/locales/ja-KS.yml index ae45379086..9c0bff4f95 100644 --- a/locales/ja-KS.yml +++ b/locales/ja-KS.yml @@ -1312,6 +1312,7 @@ federationDisabled: "このサーバーは連合が無効化されてるで。 confirmOnReact: "ツッコむときに確認とる" reactAreYouSure: "\" {emoji} \" でツッコむ?" postForm: "投稿フォーム" +information: "情報" _settings: webhook: "Webhook" _accountSettings: @@ -2610,10 +2611,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "配ってるとこが信頼できるか確認した上でインストールしてな。" _plugin: title: "このプラグイン、インストールする?" - metaTitle: "プラグイン情報" _theme: title: "このテーマインストールする?" - metaTitle: "テーマ情報" _meta: base: "" _vendorInfo: diff --git a/locales/ko-GS.yml b/locales/ko-GS.yml index ce83ef0e07..8ff11d35d9 100644 --- a/locales/ko-GS.yml +++ b/locales/ko-GS.yml @@ -655,6 +655,7 @@ replies: "답하기" renotes: "리노트" attach: "옇기" surrender: "아이예" +information: "정보" _delivery: stop: "고만 보내예" _type: diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 798c371bc2..4a02b0c64a 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1330,6 +1330,7 @@ preferenceSyncConflictChoiceDevice: "장치 설정값" paste: "붙여넣기" emojiPalette: "이모지 팔레트" postForm: "글 입력란" +information: "정보" _emojiPalette: palettes: "팔레트" paletteForMain: "메인으로 사용할 팔레트" @@ -2650,10 +2651,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "제공자를 신뢰할 수 있는 경우에만 설치하십시오." _plugin: title: "이 플러그인을 설치하시겠습니까?" - metaTitle: "플러그인 정보" _theme: title: "이 테마를 설치하시겠습니까?" - metaTitle: "테마 정보" _meta: base: "기본 컬러 스키마" _vendorInfo: diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 06acda44be..52b5a28fb2 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -394,6 +394,7 @@ searchByGoogle: "ຄົ້ນຫາ" file: "ໄຟລ໌" replies: "ຕອບ​ກັບ" renotes: "Renote" +information: "ກ່ຽວກັບ" _delivery: stop: "ໂຈະ" _type: diff --git a/locales/nl-NL.yml b/locales/nl-NL.yml index 320b9d62ba..e2f6017f20 100644 --- a/locales/nl-NL.yml +++ b/locales/nl-NL.yml @@ -462,6 +462,7 @@ loggedInAsBot: "Momenteel als bot ingelogd" icon: "Avatar" replies: "Antwoord" renotes: "Herdelen" +information: "Over" _delivery: stop: "Opgeschort" _type: diff --git a/locales/no-NO.yml b/locales/no-NO.yml index c1b145cab4..7981360c41 100644 --- a/locales/no-NO.yml +++ b/locales/no-NO.yml @@ -463,6 +463,7 @@ icon: "Avatar" replies: "Svar" renotes: "Renote" surrender: "Avbryt" +information: "Informasjon" _delivery: stop: "Suspendert" _initialAccountSetting: diff --git a/locales/pl-PL.yml b/locales/pl-PL.yml index a4538ee7b2..21b715714d 100644 --- a/locales/pl-PL.yml +++ b/locales/pl-PL.yml @@ -1045,6 +1045,7 @@ lastNDays: "W ciągu ostatnich {n} dni" surrender: "Odrzuć" gameRetry: "Spróbuj ponownie" postForm: "Formularz tworzenia wpisu" +information: "Informacje" _delivery: stop: "Zawieszono" _type: diff --git a/locales/pt-PT.yml b/locales/pt-PT.yml index 4511ce662f..2f46eda784 100644 --- a/locales/pt-PT.yml +++ b/locales/pt-PT.yml @@ -1302,6 +1302,7 @@ pleaseSelectAccount: "Selecione uma conta" availableRoles: "Cargos disponíveis" acknowledgeNotesAndEnable: "Ative após compreender as precauções." postForm: "Campo de postagem" +information: "Informações" _settings: webhook: "Webhook" _accountSettings: @@ -2598,10 +2599,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "Tenha certeza de que o distribuidor desse recurso é confiável antes da instalação." _plugin: title: "Deseja instalar esse plugin?" - metaTitle: "Informações do plugin" _theme: title: "Deseja instalar esse tema?" - metaTitle: "Informações do tema" _meta: base: "Paleta de cores base" _vendorInfo: diff --git a/locales/ro-RO.yml b/locales/ro-RO.yml index 0d43e174a7..5d1459480d 100644 --- a/locales/ro-RO.yml +++ b/locales/ro-RO.yml @@ -646,6 +646,7 @@ show: "Arată" icon: "Avatar" replies: "Răspunde" renotes: "Re-notează" +information: "Despre" _delivery: stop: "Suspendat" _type: diff --git a/locales/ru-RU.yml b/locales/ru-RU.yml index 2a200deac0..33a09d198a 100644 --- a/locales/ru-RU.yml +++ b/locales/ru-RU.yml @@ -1182,6 +1182,7 @@ alwaysConfirmFollow: "Всегда подтверждать подписку" inquiry: "Связаться" messageToFollower: "Сообщение подписчикам" postForm: "Форма отправки" +information: "Описание" _settings: webhook: "Вебхук" _delivery: diff --git a/locales/sk-SK.yml b/locales/sk-SK.yml index 7ae264081f..cc8ef9298a 100644 --- a/locales/sk-SK.yml +++ b/locales/sk-SK.yml @@ -918,6 +918,7 @@ sourceCode: "Zdrojový kód" flip: "Preklopiť" lastNDays: "Posledných {n} dní" postForm: "Napísať poznámku" +information: "Informácie" _delivery: stop: "Zmrazené" _type: diff --git a/locales/sv-SE.yml b/locales/sv-SE.yml index 91413e3bc7..c740ab1c0c 100644 --- a/locales/sv-SE.yml +++ b/locales/sv-SE.yml @@ -562,6 +562,7 @@ inquiry: "Kontakt" tryAgain: "Försök igen senare" signinWithPasskey: "Logga in med nyckel" unknownWebAuthnKey: "Okänd nyckel" +information: "Om" _delivery: stop: "Suspenderad" _type: diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 939b0d7269..784e9049dd 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -1293,6 +1293,7 @@ prohibitedWordsForNameOfUserDescription: "หากมีสตริงใด yourNameContainsProhibitedWords: "ชื่อของคุณนั้นมีคำที่ต้องห้าม" yourNameContainsProhibitedWordsDescription: "ถ้าหากคุณต้องการใช้ชื่อนี้ กรุณาติดต่อผู้ดูแลระบบของเซิร์ฟเวอร์นะค่ะ" postForm: "แบบฟอร์มการโพสต์" +information: "เกี่ยวกับ" _settings: webhook: "Webhook" _abuseUserReport: @@ -2572,10 +2573,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "โปรดตรวจสอบให้แน่ใจว่าแหล่งแจกหน่ายมีความน่าเชื่อถือก่อนทำการติดตั้ง" _plugin: title: "ต้องการติดตั้งปลั๊กอินนี้ใช่ไหม?" - metaTitle: "ข้อมูลส่วนเสริม" _theme: title: "ต้องการติดตั้งธีมนี้ใช่ไหม?" - metaTitle: "ข้อมูลธีม" _meta: base: "โทนสีพื้นฐาน" _vendorInfo: diff --git a/locales/uk-UA.yml b/locales/uk-UA.yml index 3e068127f5..a63e39eff4 100644 --- a/locales/uk-UA.yml +++ b/locales/uk-UA.yml @@ -910,6 +910,7 @@ sourceCode: "Вихідний код" flip: "Перевернути" lastNDays: "Останні {n} днів" postForm: "Створення нотатки" +information: "Інформація" _delivery: stop: "Призупинено" _type: diff --git a/locales/uz-UZ.yml b/locales/uz-UZ.yml index c70802e417..d5b7d4b770 100644 --- a/locales/uz-UZ.yml +++ b/locales/uz-UZ.yml @@ -841,6 +841,7 @@ icon: "Avatar" replies: "Javob berish" renotes: "Qayta qayd etish" flip: "Teskari" +information: "Haqida" _delivery: stop: "To'xtatilgan" _type: diff --git a/locales/vi-VN.yml b/locales/vi-VN.yml index d2107eaba4..8edcebcd08 100644 --- a/locales/vi-VN.yml +++ b/locales/vi-VN.yml @@ -1120,6 +1120,7 @@ cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải lastNDays: "{n} ngày trước" surrender: "Từ chối" postForm: "Mẫu đăng" +information: "Giới thiệu" _delivery: stop: "Đã vô hiệu hóa" _type: diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 444ba8bc52..ad3eebfebd 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1334,6 +1334,7 @@ paste: "粘贴" emojiPalette: "表情符号调色板" postForm: "投稿窗口" textCount: "字数" +information: "关于" _emojiPalette: palettes: "调色板" enableSyncBetweenDevicesForPalettes: "启用调色板的设备间同步" @@ -2673,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "请在安装前确保来源可靠" _plugin: title: "要安装此插件吗?" - metaTitle: "插件信息" _theme: title: "要安装此主题吗?" - metaTitle: "主题信息" _meta: base: "基本配色方案" _vendorInfo: diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 2ea4ae8168..0de267688c 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1334,6 +1334,7 @@ paste: "貼上" emojiPalette: "表情符號調色盤" postForm: "發文視窗" textCount: "字數" +information: "關於" _emojiPalette: palettes: "調色盤" enableSyncBetweenDevicesForPalettes: "啟用裝置與裝置之間的調色盤同步化" @@ -2673,10 +2674,8 @@ _externalResourceInstaller: checkVendorBeforeInstall: "安裝前請確認提供者是可信賴的。" _plugin: title: "要安裝此外掛嘛?" - metaTitle: "外掛資訊" _theme: title: "要安裝此佈景主題嗎?" - metaTitle: "佈景主題資訊" _meta: base: "基本配色方案" _vendorInfo: From 070749bdc8750dbda6ccbb43f2c25514a659051c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Mar 2025 04:03:25 +0000 Subject: [PATCH 217/649] Bump version to 2025.3.2-beta.6 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 142de7513f..51422b3638 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.3.2-beta.5", + "version": "2025.3.2-beta.6", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 1c5ae12a9f..b66f202876 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.3.2-beta.5", + "version": "2025.3.2-beta.6", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From 8b6d90b7a45422f0c5dd05678c7a4ca8d83b7fe5 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 20 Mar 2025 13:16:08 +0900 Subject: [PATCH 218/649] =?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/MkAnimBg.vue | 2 +- .../frontend/src/pages/install-extensions.vue | 74 ++++++++++--------- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/packages/frontend/src/components/MkAnimBg.vue b/packages/frontend/src/components/MkAnimBg.vue index 2938645557..e57fbcdee3 100644 --- a/packages/frontend/src/components/MkAnimBg.vue +++ b/packages/frontend/src/components/MkAnimBg.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> + + diff --git a/packages/frontend/src/pages/install-extensions.vue b/packages/frontend/src/pages/install-extensions.vue index 47c49e547a..40d58027de 100644 --- a/packages/frontend/src/pages/install-extensions.vue +++ b/packages/frontend/src/pages/install-extensions.vue @@ -4,46 +4,43 @@ SPDX-License-Identifier: AGPL-3.0-only --> + + diff --git a/packages/frontend/src/di.ts b/packages/frontend/src/di.ts index e9b2c2b650..4977cdbd62 100644 --- a/packages/frontend/src/di.ts +++ b/packages/frontend/src/di.ts @@ -11,4 +11,5 @@ export const DI = { router: Symbol() as InjectionKey, mock: Symbol() as InjectionKey, pageMetadata: Symbol() as InjectionKey>>, + viewId: Symbol() as InjectionKey, }; diff --git a/packages/frontend/src/utility/random-id.ts b/packages/frontend/src/utility/random-id.ts new file mode 100644 index 0000000000..4e5943a97f --- /dev/null +++ b/packages/frontend/src/utility/random-id.ts @@ -0,0 +1,15 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +const CHARS = 'abcdefghijklmnopqrstuvwxyz'; // CSSのなどで使われることもあるのでa-z以外使うな + +export function randomId(length = 32, characters = CHARS) { + let result = ''; + const charactersLength = characters.length; + for ( let i = 0; i < length; i++ ) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); + } + return result; +} From c02f0b3b33c833056254b170af8620e9750ae22f Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 20 Mar 2025 18:59:10 +0900 Subject: [PATCH 232/649] Update eslint.config.js --- packages/frontend/eslint.config.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/frontend/eslint.config.js b/packages/frontend/eslint.config.js index e3fba65197..05ac002b53 100644 --- a/packages/frontend/eslint.config.js +++ b/packages/frontend/eslint.config.js @@ -56,7 +56,9 @@ export default [ // open ... window.openと衝突 or 紛らわしい // fetch ... window.fetchと衝突 or 紛らわしい // location ... window.locationと衝突 or 紛らわしい - 'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location'], + // document ... window.documentと衝突 or 紛らわしい + // history ... window.historyと衝突 or 紛らわしい + 'id-denylist': ['warn', 'window', 'e', 'close', 'open', 'fetch', 'location', 'document', 'history'], 'no-restricted-globals': [ 'error', { @@ -75,6 +77,10 @@ export default [ 'name': 'location', 'message': 'Use `window.location`.', }, + { + 'name': 'document', + 'message': 'Use `window.document`.', + }, { 'name': 'history', 'message': 'Use `window.history`.', From 6015254e59ba0526efbfa139c89546458663ccbd Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 20 Mar 2025 19:00:09 +0900 Subject: [PATCH 233/649] lint fixes --- packages/frontend/.storybook/fake-utils.ts | 2 +- packages/frontend/.storybook/preview.ts | 6 ++-- packages/frontend/src/boot/common.ts | 30 +++++++++---------- packages/frontend/src/boot/main-boot.ts | 6 ++-- .../frontend/src/components/MkAnalogClock.vue | 2 +- .../src/components/MkAutocomplete.vue | 4 +-- packages/frontend/src/components/MkButton.vue | 2 +- .../frontend/src/components/MkCaptcha.vue | 6 ++-- .../frontend/src/components/MkContextMenu.vue | 4 +-- .../src/components/MkCropperDialog.vue | 2 +- packages/frontend/src/components/MkFolder.vue | 2 +- .../src/components/MkImgWithBlurhash.vue | 4 +-- .../src/components/MkInstanceStats.vue | 2 +- .../frontend/src/components/MkMediaAudio.vue | 2 +- .../frontend/src/components/MkMediaList.vue | 6 ++-- .../frontend/src/components/MkMediaVideo.vue | 8 ++--- packages/frontend/src/components/MkMenu.vue | 16 +++++----- .../frontend/src/components/MkMiniChart.vue | 2 +- .../src/components/MkNotifications.vue | 2 +- .../frontend/src/components/MkPagination.vue | 2 +- packages/frontend/src/components/MkRange.vue | 8 ++--- .../components/MkReactionsViewer.reaction.vue | 2 +- .../src/components/MkRetentionLineChart.vue | 2 +- .../frontend/src/components/MkTagCloud.vue | 4 +-- .../MkVisitorDashboard.ActiveUsersChart.vue | 2 +- packages/frontend/src/components/MkWindow.vue | 2 +- .../components/global/MkPageHeader.tabs.vue | 2 +- .../src/components/global/MkPageHeader.vue | 4 +-- .../src/components/global/RouterView.vue | 6 ++-- .../src/components/global/SearchMarker.vue | 2 +- packages/frontend/src/directives/hotkey.ts | 4 +-- packages/frontend/src/directives/panel.ts | 2 +- packages/frontend/src/directives/tooltip.ts | 2 +- .../frontend/src/directives/user-preview.ts | 4 +-- packages/frontend/src/instance.ts | 2 +- packages/frontend/src/os.ts | 4 +-- .../frontend/src/pages/admin/_header_.vue | 2 +- .../frontend/src/pages/admin/overview.pie.vue | 2 +- packages/frontend/src/pages/auth.form.vue | 2 +- .../src/pages/drop-and-fusion.game.vue | 2 +- packages/frontend/src/pages/oauth.vue | 18 +++++------ .../src/pages/settings/2fa.qrdialog.vue | 2 +- packages/frontend/src/preferences.ts | 6 ++-- packages/frontend/src/preferences/utility.ts | 4 +-- packages/frontend/src/server-context.ts | 2 +- packages/frontend/src/stream.ts | 6 ++-- packages/frontend/src/theme.ts | 12 ++++---- packages/frontend/src/ui/_common_/common.vue | 2 +- packages/frontend/src/ui/_common_/navbar.vue | 4 +-- packages/frontend/src/ui/classic.vue | 6 ++-- packages/frontend/src/ui/deck.vue | 4 +-- packages/frontend/src/ui/minimum.vue | 4 +-- packages/frontend/src/ui/universal.vue | 12 ++++---- packages/frontend/src/ui/visitor.vue | 4 +-- packages/frontend/src/ui/zen.vue | 4 +-- packages/frontend/src/use/use-note-capture.ts | 2 +- packages/frontend/src/use/use-tooltip.ts | 4 +-- packages/frontend/src/utility/focus-trap.ts | 4 +-- packages/frontend/src/utility/focus.ts | 4 +-- packages/frontend/src/utility/fullscreen.ts | 4 +-- packages/frontend/src/utility/hotkey.ts | 6 ++-- packages/frontend/src/utility/init-chart.ts | 2 +- packages/frontend/src/utility/physics.ts | 2 +- packages/frontend/src/utility/select-file.ts | 2 +- .../frontend/src/utility/snowfall-effect.ts | 6 ++-- packages/frontend/src/utility/sound.ts | 4 +-- .../frontend/src/utility/sticky-sidebar.ts | 2 +- .../src/utility/upload/isWebpSupported.ts | 2 +- packages/frontend/src/widgets/WidgetRss.vue | 2 +- .../frontend/src/widgets/WidgetRssTicker.vue | 2 +- packages/frontend/test/scroll.test.ts | 12 ++++---- 71 files changed, 160 insertions(+), 160 deletions(-) diff --git a/packages/frontend/.storybook/fake-utils.ts b/packages/frontend/.storybook/fake-utils.ts index c777cbbe72..44e2263ca0 100644 --- a/packages/frontend/.storybook/fake-utils.ts +++ b/packages/frontend/.storybook/fake-utils.ts @@ -131,7 +131,7 @@ export function imageDataUrl(options?: { alpha?: number, } }, seed?: string): string { - const canvas = document.createElement('canvas'); + const canvas = window.document.createElement('canvas'); canvas.width = options?.size?.width ?? 100; canvas.height = options?.size?.height ?? 100; diff --git a/packages/frontend/.storybook/preview.ts b/packages/frontend/.storybook/preview.ts index 3f6bfb62ff..269bc4fb9a 100644 --- a/packages/frontend/.storybook/preview.ts +++ b/packages/frontend/.storybook/preview.ts @@ -23,9 +23,9 @@ let misskeyOS = null; function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) { unobserve(); - const theme = themes[document.documentElement.dataset.misskeyTheme]; + const theme = themes[window.document.documentElement.dataset.misskeyTheme]; if (theme) { - applyTheme(themes[document.documentElement.dataset.misskeyTheme]); + applyTheme(themes[window.document.documentElement.dataset.misskeyTheme]); } else { applyTheme(themes['l-light']); } @@ -42,7 +42,7 @@ function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) { } } }); - observer.observe(document.documentElement, { + observer.observe(window.document.documentElement, { attributes: true, attributeFilter: ['data-misskey-theme'], }); diff --git a/packages/frontend/src/boot/common.ts b/packages/frontend/src/boot/common.ts index 75b74b41f8..9a505ca9f8 100644 --- a/packages/frontend/src/boot/common.ts +++ b/packages/frontend/src/boot/common.ts @@ -95,7 +95,7 @@ export async function common(createVue: () => App) { //#endregion // タッチデバイスでCSSの:hoverを機能させる - document.addEventListener('touchend', () => {}, { passive: true }); + window.document.addEventListener('touchend', () => {}, { passive: true }); // URLに#pswpを含む場合は取り除く if (window.location.hash === '#pswp') { @@ -110,13 +110,13 @@ export async function common(createVue: () => App) { // If mobile, insert the viewport meta tag if (['smartphone', 'tablet'].includes(deviceKind)) { - const viewport = document.getElementsByName('viewport').item(0); + const viewport = window.document.getElementsByName('viewport').item(0); viewport.setAttribute('content', `${viewport.getAttribute('content')}, minimum-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover`); } //#region Set lang attr - const html = document.documentElement; + const html = window.document.documentElement; html.setAttribute('lang', lang); //#endregion @@ -155,7 +155,7 @@ export async function common(createVue: () => App) { ); }, { immediate: miLocalStorage.getItem('theme') == null }); - document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light'; + window.document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light'; const darkTheme = prefer.model('darkTheme'); const lightTheme = prefer.model('lightTheme'); @@ -201,20 +201,20 @@ export async function common(createVue: () => App) { }, { immediate: true }); watch(prefer.r.useBlurEffectForModal, v => { - document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none'); + window.document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none'); }, { immediate: true }); watch(prefer.r.useBlurEffect, v => { if (v) { - document.documentElement.style.removeProperty('--MI-blur'); + window.document.documentElement.style.removeProperty('--MI-blur'); } else { - document.documentElement.style.setProperty('--MI-blur', 'none'); + window.document.documentElement.style.setProperty('--MI-blur', 'none'); } }, { immediate: true }); // Keep screen on - const onVisibilityChange = () => document.addEventListener('visibilitychange', () => { - if (document.visibilityState === 'visible') { + const onVisibilityChange = () => window.document.addEventListener('visibilitychange', () => { + if (window.document.visibilityState === 'visible') { navigator.wakeLock.request('screen'); } }); @@ -224,7 +224,7 @@ export async function common(createVue: () => App) { .catch(() => { // On WebKit-based browsers, user activation is required to send wake lock request // https://webkit.org/blog/13862/the-user-activation-api/ - document.addEventListener( + window.document.addEventListener( 'click', () => navigator.wakeLock.request('screen').then(onVisibilityChange), { once: true }, @@ -233,7 +233,7 @@ export async function common(createVue: () => App) { } if (prefer.s.makeEveryTextElementsSelectable) { - document.documentElement.classList.add('forceSelectableAll'); + window.document.documentElement.classList.add('forceSelectableAll'); } //#region Fetch user @@ -278,16 +278,16 @@ export async function common(createVue: () => App) { const rootEl = ((): HTMLElement => { const MISSKEY_MOUNT_DIV_ID = 'misskey_app'; - const currentRoot = document.getElementById(MISSKEY_MOUNT_DIV_ID); + const currentRoot = window.document.getElementById(MISSKEY_MOUNT_DIV_ID); if (currentRoot) { console.warn('multiple import detected'); return currentRoot; } - const root = document.createElement('div'); + const root = window.document.createElement('div'); root.id = MISSKEY_MOUNT_DIV_ID; - document.body.appendChild(root); + window.document.body.appendChild(root); return root; })(); @@ -330,7 +330,7 @@ export async function common(createVue: () => App) { } function removeSplash() { - const splash = document.getElementById('splash'); + const splash = window.document.getElementById('splash'); if (splash) { splash.style.opacity = '0'; splash.style.pointerEvents = 'none'; diff --git a/packages/frontend/src/boot/main-boot.ts b/packages/frontend/src/boot/main-boot.ts index f7360a7340..134490e317 100644 --- a/packages/frontend/src/boot/main-boot.ts +++ b/packages/frontend/src/boot/main-boot.ts @@ -398,7 +398,7 @@ export async function mainBoot() { let lastVisibilityChangedAt = Date.now(); function claimPlainLucky() { - if (document.visibilityState !== 'visible') { + if (window.document.visibilityState !== 'visible') { if (justPlainLuckyTimer != null) window.clearTimeout(justPlainLuckyTimer); return; } @@ -413,7 +413,7 @@ export async function mainBoot() { window.addEventListener('visibilitychange', () => { const now = Date.now(); - if (document.visibilityState === 'visible') { + if (window.document.visibilityState === 'visible') { // タブを高速で切り替えたら取得処理が何度も走るのを防ぐ if ((now - lastVisibilityChangedAt) < 1000 * 10) { justPlainLuckyTimer = window.setTimeout(claimPlainLucky, 1000 * 10); @@ -554,7 +554,7 @@ export async function mainBoot() { mainRouter.push('/search'); }, } as const satisfies Keymap; - document.addEventListener('keydown', makeHotkey(keymap), { passive: false }); + window.document.addEventListener('keydown', makeHotkey(keymap), { passive: false }); initializeSw(); } diff --git a/packages/frontend/src/components/MkAnalogClock.vue b/packages/frontend/src/components/MkAnalogClock.vue index b39bca5b27..eac1ea9534 100644 --- a/packages/frontend/src/components/MkAnalogClock.vue +++ b/packages/frontend/src/components/MkAnalogClock.vue @@ -192,7 +192,7 @@ function tick() { tick(); function calcColors() { - const computedStyle = getComputedStyle(document.documentElement); + const computedStyle = getComputedStyle(window.document.documentElement); const dark = tinycolor(computedStyle.getPropertyValue('--MI_THEME-bg')).isDark(); const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); majorGraduationColor.value = dark ? 'rgba(255, 255, 255, 0.3)' : 'rgba(0, 0, 0, 0.3)'; diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 5b747a2a1a..03cf107231 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -359,7 +359,7 @@ onMounted(() => { props.textarea.addEventListener('keydown', onKeydown); - document.body.addEventListener('mousedown', onMousedown); + window.document.body.addEventListener('mousedown', onMousedown); nextTick(() => { exec(); @@ -375,7 +375,7 @@ onMounted(() => { onBeforeUnmount(() => { props.textarea.removeEventListener('keydown', onKeydown); - document.body.removeEventListener('mousedown', onMousedown); + window.document.body.removeEventListener('mousedown', onMousedown); }); diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index c81edc2a73..5e89dfba12 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -92,7 +92,7 @@ function onMousedown(evt: MouseEvent): void { const target = evt.target! as HTMLElement; const rect = target.getBoundingClientRect(); - const ripple = document.createElement('div'); + const ripple = window.document.createElement('div'); ripple.classList.add(ripples.value!.dataset.childrenClass!); ripple.style.top = (evt.clientY - rect.top - 1).toString() + 'px'; ripple.style.left = (evt.clientX - rect.left - 1).toString() + 'px'; diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue index e4f953bda8..30940a34a9 100644 --- a/packages/frontend/src/components/MkCaptcha.vue +++ b/packages/frontend/src/components/MkCaptcha.vue @@ -112,7 +112,7 @@ watch(() => [props.instanceUrl, props.sitekey, props.secretKey], async () => { if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') { available.value = true; } else if (src.value !== null) { - (document.getElementById(scriptId.value) ?? document.head.appendChild(Object.assign(document.createElement('script'), { + (window.document.getElementById(scriptId.value) ?? window.document.head.appendChild(Object.assign(window.document.createElement('script'), { async: true, id: scriptId.value, src: src.value, @@ -149,7 +149,7 @@ async function requestRender() { if (captcha.value.render && captchaEl.value instanceof Element && props.sitekey) { // reCAPTCHAのレンダリング重複判定を回避するため、captchaEl配下に仮のdivを用意する. // (同じdivに対して複数回renderを呼び出すとreCAPTCHAはエラーを返すので) - const elem = document.createElement('div'); + const elem = window.document.createElement('div'); captchaEl.value.appendChild(elem); captchaWidgetId.value = captcha.value.render(elem, { @@ -174,7 +174,7 @@ async function requestRender() { function clearWidget() { if (props.provider === 'mcaptcha') { - const container = document.getElementById('mcaptcha__widget-container'); + const container = window.document.getElementById('mcaptcha__widget-container'); if (container) { container.innerHTML = ''; } diff --git a/packages/frontend/src/components/MkContextMenu.vue b/packages/frontend/src/components/MkContextMenu.vue index e47dba4bae..9c6397a72c 100644 --- a/packages/frontend/src/components/MkContextMenu.vue +++ b/packages/frontend/src/components/MkContextMenu.vue @@ -68,11 +68,11 @@ onMounted(() => { rootEl.value.style.left = `${left}px`; } - document.body.addEventListener('mousedown', onMousedown); + window.document.body.addEventListener('mousedown', onMousedown); }); onBeforeUnmount(() => { - document.body.removeEventListener('mousedown', onMousedown); + window.document.body.removeEventListener('mousedown', onMousedown); }); function onMousedown(evt: Event) { diff --git a/packages/frontend/src/components/MkCropperDialog.vue b/packages/frontend/src/components/MkCropperDialog.vue index bd2e6a9cbc..ba21394cbc 100644 --- a/packages/frontend/src/components/MkCropperDialog.vue +++ b/packages/frontend/src/components/MkCropperDialog.vue @@ -122,7 +122,7 @@ onMounted(() => { cropper = new Cropper(imgEl.value!, { }); - const computedStyle = getComputedStyle(document.documentElement); + const computedStyle = getComputedStyle(window.document.documentElement); const selection = cropper.getCropperSelection()!; selection.themeColor = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index b13972f66d..afa09e3125 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -116,7 +116,7 @@ function toggle() { } onMounted(() => { - const computedStyle = getComputedStyle(document.documentElement); + const computedStyle = getComputedStyle(window.document.documentElement); const parentBg = getBgColor(rootEl.value?.parentElement) ?? 'transparent'; const myBg = computedStyle.getPropertyValue('--MI_THEME-panel'); bgSame.value = parentBg === myBg; diff --git a/packages/frontend/src/components/MkImgWithBlurhash.vue b/packages/frontend/src/components/MkImgWithBlurhash.vue index 420e5e392f..e3a0a371b4 100644 --- a/packages/frontend/src/components/MkImgWithBlurhash.vue +++ b/packages/frontend/src/components/MkImgWithBlurhash.vue @@ -55,7 +55,7 @@ import { extractAvgColorFromBlurhash } from '@@/js/extract-avg-color-from-blurha const canvasPromise = new Promise(resolve => { // テスト環境で Web Worker インスタンスは作成できない if (import.meta.env.MODE === 'test') { - const canvas = document.createElement('canvas'); + const canvas = window.document.createElement('canvas'); canvas.width = 64; canvas.height = 64; resolve(canvas); @@ -70,7 +70,7 @@ const canvasPromise = new Promise(resol ); resolve(workers); } else { - const canvas = document.createElement('canvas'); + const canvas = window.document.createElement('canvas'); canvas.width = 64; canvas.height = 64; resolve(canvas); diff --git a/packages/frontend/src/components/MkInstanceStats.vue b/packages/frontend/src/components/MkInstanceStats.vue index 76bec9bc66..90391005bc 100644 --- a/packages/frontend/src/components/MkInstanceStats.vue +++ b/packages/frontend/src/components/MkInstanceStats.vue @@ -126,7 +126,7 @@ function createDoughnut(chartEl, tooltip, data) { labels: data.map(x => x.name), datasets: [{ backgroundColor: data.map(x => x.color), - borderColor: getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'), + borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'), borderWidth: 2, hoverOffset: 0, data: data.map(x => x.value), diff --git a/packages/frontend/src/components/MkMediaAudio.vue b/packages/frontend/src/components/MkMediaAudio.vue index db6deb161a..b7052ad918 100644 --- a/packages/frontend/src/components/MkMediaAudio.vue +++ b/packages/frontend/src/components/MkMediaAudio.vue @@ -148,7 +148,7 @@ const keymap = { // PlayerElもしくはその子要素にフォーカスがあるかどうか function hasFocus() { if (!playerEl.value) return false; - return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement); + return playerEl.value === window.document.activeElement || playerEl.value.contains(window.document.activeElement); } const playerEl = useTemplateRef('playerEl'); diff --git a/packages/frontend/src/components/MkMediaList.vue b/packages/frontend/src/components/MkMediaList.vue index 44a9d14a46..ae15776041 100644 --- a/packages/frontend/src/components/MkMediaList.vue +++ b/packages/frontend/src/components/MkMediaList.vue @@ -48,7 +48,7 @@ const props = defineProps<{ const gallery = useTemplateRef('gallery'); const pswpZIndex = os.claimZIndex('middle'); -document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); +window.document.documentElement.style.setProperty('--mk-pswp-root-z-index', pswpZIndex.toString()); const count = computed(() => props.mediaList.filter(media => previewable(media)).length); let lightbox: PhotoSwipeLightbox | null = null; @@ -166,7 +166,7 @@ onMounted(() => { className: 'pswp__alt-text-container', appendTo: 'wrapper', onInit: (el, pswp) => { - const textBox = document.createElement('p'); + const textBox = window.document.createElement('p'); textBox.className = 'pswp__alt-text _acrylic'; el.appendChild(textBox); @@ -178,7 +178,7 @@ onMounted(() => { }); lightbox.on('afterInit', () => { - activeEl = document.activeElement instanceof HTMLElement ? document.activeElement : null; + activeEl = window.document.activeElement instanceof HTMLElement ? window.document.activeElement : null; focusParent(activeEl, true, true); lightbox?.pswp?.element?.focus({ preventScroll: true, diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index 5475e703a5..629679a971 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -171,7 +171,7 @@ const keymap = { // PlayerElもしくはその子要素にフォーカスがあるかどうか function hasFocus() { if (!playerEl.value) return false; - return playerEl.value === document.activeElement || playerEl.value.contains(document.activeElement); + return playerEl.value === window.document.activeElement || playerEl.value.contains(window.document.activeElement); } // eslint-disable-next-line vue/no-setup-props-reactivity-loss @@ -216,7 +216,7 @@ function showMenu(ev: MouseEvent) { '2.0x': 2, }, }, - ...(document.pictureInPictureEnabled ? [{ + ...(window.document.pictureInPictureEnabled ? [{ text: i18n.ts._mediaControls.pip, icon: 'ti ti-picture-in-picture', action: togglePictureInPicture, @@ -384,8 +384,8 @@ function toggleFullscreen() { function togglePictureInPicture() { if (videoEl.value) { - if (document.pictureInPictureElement) { - document.exitPictureInPicture(); + if (window.document.pictureInPictureElement) { + window.document.exitPictureInPicture(); } else { videoEl.value.requestPictureInPicture(); } diff --git a/packages/frontend/src/components/MkMenu.vue b/packages/frontend/src/components/MkMenu.vue index e380d0bc37..a84bd9b256 100644 --- a/packages/frontend/src/components/MkMenu.vue +++ b/packages/frontend/src/components/MkMenu.vue @@ -358,10 +358,10 @@ function switchItem(item: MenuSwitch & { ref: any }) { function focusUp() { if (disposed) return; - if (!itemsEl.value?.contains(document.activeElement)) return; + if (!itemsEl.value?.contains(window.document.activeElement)) return; const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable); - const activeIndex = focusableElements.findIndex(el => el === document.activeElement); + const activeIndex = focusableElements.findIndex(el => el === window.document.activeElement); const targetIndex = (activeIndex !== -1 && activeIndex !== 0) ? (activeIndex - 1) : (focusableElements.length - 1); const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value; @@ -370,10 +370,10 @@ function focusUp() { function focusDown() { if (disposed) return; - if (!itemsEl.value?.contains(document.activeElement)) return; + if (!itemsEl.value?.contains(window.document.activeElement)) return; const focusableElements = Array.from(itemsEl.value.children).filter(isFocusable); - const activeIndex = focusableElements.findIndex(el => el === document.activeElement); + const activeIndex = focusableElements.findIndex(el => el === window.document.activeElement); const targetIndex = (activeIndex !== -1 && activeIndex !== (focusableElements.length - 1)) ? (activeIndex + 1) : 0; const targetElement = focusableElements.at(targetIndex) ?? itemsEl.value; @@ -400,9 +400,9 @@ const onGlobalMousedown = (ev: MouseEvent) => { const setupHandlers = () => { if (!isNestingMenu) { - document.addEventListener('focusin', onGlobalFocusin, { passive: true }); + window.document.addEventListener('focusin', onGlobalFocusin, { passive: true }); } - document.addEventListener('mousedown', onGlobalMousedown, { passive: true }); + window.document.addEventListener('mousedown', onGlobalMousedown, { passive: true }); }; let disposed = false; @@ -410,9 +410,9 @@ let disposed = false; const disposeHandlers = () => { disposed = true; if (!isNestingMenu) { - document.removeEventListener('focusin', onGlobalFocusin); + window.document.removeEventListener('focusin', onGlobalFocusin); } - document.removeEventListener('mousedown', onGlobalMousedown); + window.document.removeEventListener('mousedown', onGlobalMousedown); }; onMounted(() => { diff --git a/packages/frontend/src/components/MkMiniChart.vue b/packages/frontend/src/components/MkMiniChart.vue index 7ea585ecc2..98bd471438 100644 --- a/packages/frontend/src/components/MkMiniChart.vue +++ b/packages/frontend/src/components/MkMiniChart.vue @@ -48,7 +48,7 @@ const polygonPoints = ref(''); const headX = ref(null); const headY = ref(null); const clock = ref(null); -const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent')); +const accent = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-accent')); const color = accent.toRgbString(); function draw(): void { diff --git a/packages/frontend/src/components/MkNotifications.vue b/packages/frontend/src/components/MkNotifications.vue index 08fc846327..21f1967bfa 100644 --- a/packages/frontend/src/components/MkNotifications.vue +++ b/packages/frontend/src/components/MkNotifications.vue @@ -59,7 +59,7 @@ const pagination = computed(() => prefer.r.useGroupedNotifications.value ? { function onNotification(notification) { const isMuted = props.excludeTypes ? props.excludeTypes.includes(notification.type) : false; - if (isMuted || document.visibilityState === 'visible') { + if (isMuted || window.document.visibilityState === 'visible') { useStream().send('readNotification'); } diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index 6a1a91a9f4..ab8bda403b 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -142,7 +142,7 @@ const { } = prefer.r; const contentEl = computed(() => props.pagination.pageEl ?? rootEl.value); -const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : document.body); +const scrollableElement = computed(() => contentEl.value ? getScrollContainer(contentEl.value) : window.document.body); const visibility = useDocumentVisibility(); diff --git a/packages/frontend/src/components/MkRange.vue b/packages/frontend/src/components/MkRange.vue index 118dbbe15a..734b624541 100644 --- a/packages/frontend/src/components/MkRange.vue +++ b/packages/frontend/src/components/MkRange.vue @@ -151,9 +151,9 @@ function onMousedown(ev: MouseEvent | TouchEvent) { closed: () => dispose(), }); - const style = document.createElement('style'); - style.appendChild(document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }')); - document.head.appendChild(style); + const style = window.document.createElement('style'); + style.appendChild(window.document.createTextNode('* { cursor: grabbing !important; } body * { pointer-events: none !important; }')); + window.document.head.appendChild(style); const thumbWidth = getThumbWidth(); @@ -172,7 +172,7 @@ function onMousedown(ev: MouseEvent | TouchEvent) { let beforeValue = finalValue.value; const onMouseup = () => { - document.head.removeChild(style); + window.document.head.removeChild(style); tooltipForDragShowing.value = false; window.removeEventListener('mousemove', onDrag); window.removeEventListener('touchmove', onDrag); diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue index 590b0f6f19..9d941a949a 100644 --- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue +++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue @@ -136,7 +136,7 @@ async function menu(ev) { } function anime() { - if (document.hidden || !prefer.s.animation || buttonEl.value == null) return; + if (window.document.hidden || !prefer.s.animation || buttonEl.value == null) return; const rect = buttonEl.value.getBoundingClientRect(); const x = rect.left + 16; diff --git a/packages/frontend/src/components/MkRetentionLineChart.vue b/packages/frontend/src/components/MkRetentionLineChart.vue index 60b3f17b14..ba66ffecc0 100644 --- a/packages/frontend/src/components/MkRetentionLineChart.vue +++ b/packages/frontend/src/components/MkRetentionLineChart.vue @@ -44,7 +44,7 @@ onMounted(async () => { const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; - const accent = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-accent')); + const accent = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-accent')); const color = accent.toHex(); if (chartEl.value == null) return; diff --git a/packages/frontend/src/components/MkTagCloud.vue b/packages/frontend/src/components/MkTagCloud.vue index 8ad9e14015..9d541c8acb 100644 --- a/packages/frontend/src/components/MkTagCloud.vue +++ b/packages/frontend/src/components/MkTagCloud.vue @@ -20,7 +20,7 @@ import tinycolor from 'tinycolor2'; const loaded = !!window.TagCanvas; const SAFE_FOR_HTML_ID = 'abcdefghijklmnopqrstuvwxyz'; -const computedStyle = getComputedStyle(document.documentElement); +const computedStyle = getComputedStyle(window.document.documentElement); const idForCanvas = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const idForTags = Array.from({ length: 16 }, () => SAFE_FOR_HTML_ID[Math.floor(Math.random() * SAFE_FOR_HTML_ID.length)]).join(''); const available = ref(false); @@ -57,7 +57,7 @@ onMounted(() => { if (loaded) { available.value = true; } else { - document.head.appendChild(Object.assign(document.createElement('script'), { + window.document.head.appendChild(Object.assign(window.document.createElement('script'), { async: true, src: '/client-assets/tagcanvas.min.js', })).addEventListener('load', () => available.value = true); diff --git a/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue b/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue index 2c2c515032..79c9e739c4 100644 --- a/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue +++ b/packages/frontend/src/components/MkVisitorDashboard.ActiveUsersChart.vue @@ -61,7 +61,7 @@ async function renderChart() { const vLineColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; - const computedStyle = getComputedStyle(document.documentElement); + const computedStyle = getComputedStyle(window.document.documentElement); const accent = tinycolor(computedStyle.getPropertyValue('--MI_THEME-accent')).toHexString(); const colorRead = accent; diff --git a/packages/frontend/src/components/MkWindow.vue b/packages/frontend/src/components/MkWindow.vue index 98ec448a8e..e5ac791d0b 100644 --- a/packages/frontend/src/components/MkWindow.vue +++ b/packages/frontend/src/components/MkWindow.vue @@ -240,7 +240,7 @@ function onHeaderMousedown(evt: MouseEvent | TouchEvent) { const main = rootEl.value; if (main == null) return; - if (!contains(main, document.activeElement)) main.focus(); + if (!contains(main, window.document.activeElement)) main.focus(); const position = main.getBoundingClientRect(); diff --git a/packages/frontend/src/components/global/MkPageHeader.tabs.vue b/packages/frontend/src/components/global/MkPageHeader.tabs.vue index 81adc07f26..358a17d3e8 100644 --- a/packages/frontend/src/components/global/MkPageHeader.tabs.vue +++ b/packages/frontend/src/components/global/MkPageHeader.tabs.vue @@ -170,7 +170,7 @@ onMounted(() => { if (props.rootEl) { ro2 = new ResizeObserver((entries, observer) => { - if (document.body.contains(el.value as HTMLElement)) { + if (window.document.body.contains(el.value as HTMLElement)) { nextTick(() => renderTab()); } }); diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 59bf80cfca..d5680b8413 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -108,7 +108,7 @@ function onTabClick(): void { const calcBg = () => { const rawBg = 'var(--MI_THEME-bg)'; - const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); + const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); tinyBg.setAlpha(0.85); bg.value = tinyBg.toRgbString(); }; @@ -122,7 +122,7 @@ onMounted(() => { if (el.value && el.value.parentElement) { narrow.value = el.value.parentElement.offsetWidth < 500; ro = new ResizeObserver((entries, observer) => { - if (el.value && el.value.parentElement && document.body.contains(el.value as HTMLElement)) { + if (el.value && el.value.parentElement && window.document.body.contains(el.value as HTMLElement)) { narrow.value = el.value.parentElement.offsetWidth < 500; } }); diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 45cb1e3bd5..1c0c35f34e 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -48,7 +48,7 @@ onMounted(() => { }); // view-transition-newなどのにはcss varが使えず、v-bindできないため直接スタイルを生成 -const viewTransitionStylesTag = document.createElement('style'); +const viewTransitionStylesTag = window.document.createElement('style'); viewTransitionStylesTag.textContent = ` @keyframes ${viewId}-old { to { transform: scale(0.95); opacity: 0; } @@ -89,8 +89,8 @@ router.useListener('change', ({ resolved }) => { } // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (prefer.s.animation && document.startViewTransition) { - document.startViewTransition(() => new Promise((res) => { + if (prefer.s.animation && window.document.startViewTransition) { + window.document.startViewTransition(() => new Promise((res) => { _(); nextTick(() => { res(); diff --git a/packages/frontend/src/components/global/SearchMarker.vue b/packages/frontend/src/components/global/SearchMarker.vue index 66a78cb7fd..061ce3f47d 100644 --- a/packages/frontend/src/components/global/SearchMarker.vue +++ b/packages/frontend/src/components/global/SearchMarker.vue @@ -42,7 +42,7 @@ const highlighted = ref(props.markerId === searchMarkerId.value); function checkChildren() { if (props.children?.includes(searchMarkerId.value)) { - const el = document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`); + const el = window.document.querySelector(`[data-in-app-search-marker-id="${searchMarkerId.value}"]`); highlighted.value = el == null; } } diff --git a/packages/frontend/src/directives/hotkey.ts b/packages/frontend/src/directives/hotkey.ts index 75e022e98f..63637ab2ba 100644 --- a/packages/frontend/src/directives/hotkey.ts +++ b/packages/frontend/src/directives/hotkey.ts @@ -13,7 +13,7 @@ export default { el._keyHandler = makeHotkey(binding.value); if (el._hotkey_global) { - document.addEventListener('keydown', el._keyHandler, { passive: false }); + window.document.addEventListener('keydown', el._keyHandler, { passive: false }); } else { el.addEventListener('keydown', el._keyHandler, { passive: false }); } @@ -21,7 +21,7 @@ export default { unmounted(el) { if (el._hotkey_global) { - document.removeEventListener('keydown', el._keyHandler); + window.document.removeEventListener('keydown', el._keyHandler); } else { el.removeEventListener('keydown', el._keyHandler); } diff --git a/packages/frontend/src/directives/panel.ts b/packages/frontend/src/directives/panel.ts index 17916fb6d3..0af19e6ca3 100644 --- a/packages/frontend/src/directives/panel.ts +++ b/packages/frontend/src/directives/panel.ts @@ -10,7 +10,7 @@ export default { mounted(src, binding, vn) { const parentBg = getBgColor(src.parentElement) ?? 'transparent'; - const myBg = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'); + const myBg = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'); if (parentBg === myBg) { src.style.backgroundColor = 'var(--MI_THEME-bg)'; diff --git a/packages/frontend/src/directives/tooltip.ts b/packages/frontend/src/directives/tooltip.ts index 068186dfa0..750acd0588 100644 --- a/packages/frontend/src/directives/tooltip.ts +++ b/packages/frontend/src/directives/tooltip.ts @@ -47,7 +47,7 @@ export default { } self.show = () => { - if (!document.body.contains(el)) return; + if (!window.document.body.contains(el)) return; if (self._close) return; if (self.text == null) return; diff --git a/packages/frontend/src/directives/user-preview.ts b/packages/frontend/src/directives/user-preview.ts index 43a93a0865..94deea82c7 100644 --- a/packages/frontend/src/directives/user-preview.ts +++ b/packages/frontend/src/directives/user-preview.ts @@ -31,7 +31,7 @@ export class UserPreview { } private show() { - if (!document.body.contains(this.el)) return; + if (!window.document.body.contains(this.el)) return; if (this.promise) return; const showing = ref(true); @@ -58,7 +58,7 @@ export class UserPreview { }; this.checkTimer = window.setInterval(() => { - if (!document.body.contains(this.el)) { + if (!window.document.body.contains(this.el)) { window.clearTimeout(this.showTimer); window.clearTimeout(this.hideTimer); this.close(); diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts index c694d49c8a..e75e3dfd34 100644 --- a/packages/frontend/src/instance.ts +++ b/packages/frontend/src/instance.ts @@ -12,7 +12,7 @@ import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERR // TODO: 他のタブと永続化されたstateを同期 //#region loader -const providedMetaEl = document.getElementById('misskey_meta'); +const providedMetaEl = window.document.getElementById('misskey_meta'); let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null; let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0; diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index eed929432c..7f4f7c5be3 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -675,7 +675,7 @@ export function popupMenu(items: MenuItem[], src?: HTMLElement | EventTarget | n src = null; } - let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(document.activeElement); + let returnFocusTo = getHTMLElementOrNull(src) ?? getHTMLElementOrNull(window.document.activeElement); return new Promise(resolve => nextTick(() => { const { dispose } = popup(MkPopupMenu, { items, @@ -704,7 +704,7 @@ export function contextMenu(items: MenuItem[], ev: MouseEvent): Promise { return Promise.resolve(); } - let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(document.activeElement); + let returnFocusTo = getHTMLElementOrNull(ev.currentTarget ?? ev.target) ?? getHTMLElementOrNull(window.document.activeElement); ev.preventDefault(); return new Promise(resolve => nextTick(() => { const { dispose } = popup(MkContextMenu, { diff --git a/packages/frontend/src/pages/admin/_header_.vue b/packages/frontend/src/pages/admin/_header_.vue index 819ca2c127..0af56e1b15 100644 --- a/packages/frontend/src/pages/admin/_header_.vue +++ b/packages/frontend/src/pages/admin/_header_.vue @@ -120,7 +120,7 @@ function onTabClick(tab: Tab, ev: MouseEvent): void { const calcBg = () => { const rawBg = pageMetadata.value.bg ?? 'var(--MI_THEME-bg)'; - const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); + const tinyBg = tinycolor(rawBg.startsWith('var(') ? getComputedStyle(window.document.documentElement).getPropertyValue(rawBg.slice(4, -1)) : rawBg); tinyBg.setAlpha(0.85); bg.value = tinyBg.toRgbString(); }; diff --git a/packages/frontend/src/pages/admin/overview.pie.vue b/packages/frontend/src/pages/admin/overview.pie.vue index 32dd981ca9..86c5eff4da 100644 --- a/packages/frontend/src/pages/admin/overview.pie.vue +++ b/packages/frontend/src/pages/admin/overview.pie.vue @@ -41,7 +41,7 @@ onMounted(() => { labels: props.data.map(x => x.name), datasets: [{ backgroundColor: props.data.map(x => x.color), - borderColor: getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-panel'), + borderColor: getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-panel'), borderWidth: 2, hoverOffset: 0, data: props.data.map(x => x.value), diff --git a/packages/frontend/src/pages/auth.form.vue b/packages/frontend/src/pages/auth.form.vue index 1917293c06..5b1fd1a386 100644 --- a/packages/frontend/src/pages/auth.form.vue +++ b/packages/frontend/src/pages/auth.form.vue @@ -38,7 +38,7 @@ const emit = defineEmits<{ const app = computed(() => props.session.app); const name = computed(() => { - const el = document.createElement('div'); + const el = window.document.createElement('div'); el.textContent = app.value.name; return el.innerHTML; }); diff --git a/packages/frontend/src/pages/drop-and-fusion.game.vue b/packages/frontend/src/pages/drop-and-fusion.game.vue index 3b1a845f5b..b8b0d6aef6 100644 --- a/packages/frontend/src/pages/drop-and-fusion.game.vue +++ b/packages/frontend/src/pages/drop-and-fusion.game.vue @@ -875,7 +875,7 @@ function loadImage(url: string) { function getGameImageDriveFile() { return new Promise(res => { - const dcanvas = document.createElement('canvas'); + const dcanvas = window.document.createElement('canvas'); dcanvas.width = game.GAME_WIDTH; dcanvas.height = game.GAME_HEIGHT; const ctx = dcanvas.getContext('2d'); diff --git a/packages/frontend/src/pages/oauth.vue b/packages/frontend/src/pages/oauth.vue index 49664c8b08..04bb1661cf 100644 --- a/packages/frontend/src/pages/oauth.vue +++ b/packages/frontend/src/pages/oauth.vue @@ -27,42 +27,42 @@ import MkPageWithAnimBg from '@/components/MkPageWithAnimBg.vue'; import { definePage } from '@/page.js'; import MkAuthConfirm from '@/components/MkAuthConfirm.vue'; -const transactionIdMeta = document.querySelector('meta[name="misskey:oauth:transaction-id"]'); +const transactionIdMeta = window.document.querySelector('meta[name="misskey:oauth:transaction-id"]'); if (transactionIdMeta) { transactionIdMeta.remove(); } -const name = document.querySelector('meta[name="misskey:oauth:client-name"]')?.content; -const logo = document.querySelector('meta[name="misskey:oauth:client-logo"]')?.content; -const permissions = document.querySelector('meta[name="misskey:oauth:scope"]')?.content.split(' ').filter((p): p is typeof Misskey.permissions[number] => (Misskey.permissions as readonly string[]).includes(p)) ?? []; +const name = window.document.querySelector('meta[name="misskey:oauth:client-name"]')?.content; +const logo = window.document.querySelector('meta[name="misskey:oauth:client-logo"]')?.content; +const permissions = window.document.querySelector('meta[name="misskey:oauth:scope"]')?.content.split(' ').filter((p): p is typeof Misskey.permissions[number] => (Misskey.permissions as readonly string[]).includes(p)) ?? []; function doPost(token: string, decision: 'accept' | 'deny') { - const form = document.createElement('form'); + const form = window.document.createElement('form'); form.action = '/oauth/decision'; form.method = 'post'; form.acceptCharset = 'utf-8'; - const loginToken = document.createElement('input'); + const loginToken = window.document.createElement('input'); loginToken.type = 'hidden'; loginToken.name = 'login_token'; loginToken.value = token; form.appendChild(loginToken); - const transactionId = document.createElement('input'); + const transactionId = window.document.createElement('input'); transactionId.type = 'hidden'; transactionId.name = 'transaction_id'; transactionId.value = transactionIdMeta?.content ?? ''; form.appendChild(transactionId); if (decision === 'deny') { - const cancel = document.createElement('input'); + const cancel = window.document.createElement('input'); cancel.type = 'hidden'; cancel.name = 'cancel'; cancel.value = 'cancel'; form.appendChild(cancel); } - document.body.appendChild(form); + window.document.body.appendChild(form); form.submit(); } diff --git a/packages/frontend/src/pages/settings/2fa.qrdialog.vue b/packages/frontend/src/pages/settings/2fa.qrdialog.vue index a13f1a7813..03f973a33e 100644 --- a/packages/frontend/src/pages/settings/2fa.qrdialog.vue +++ b/packages/frontend/src/pages/settings/2fa.qrdialog.vue @@ -160,7 +160,7 @@ async function tokenDone() { function downloadBackupCodes() { if (backupCodes.value !== undefined) { const txtBlob = new Blob([backupCodes.value.join('\n')], { type: 'text/plain' }); - const dummya = document.createElement('a'); + const dummya = window.document.createElement('a'); dummya.href = URL.createObjectURL(txtBlob); dummya.download = `${$i.username}@${hostname}` + (port !== '' ? `_${port}` : '') + '-2fa-backup-codes.txt'; dummya.click(); diff --git a/packages/frontend/src/preferences.ts b/packages/frontend/src/preferences.ts index 7681333910..73c89e23af 100644 --- a/packages/frontend/src/preferences.ts +++ b/packages/frontend/src/preferences.ts @@ -125,8 +125,8 @@ function syncBetweenTabs() { window.setInterval(syncBetweenTabs, 5000); -document.addEventListener('visibilitychange', () => { - if (document.visibilityState === 'visible') { +window.document.addEventListener('visibilitychange', () => { + if (window.document.visibilityState === 'visible') { syncBetweenTabs(); } }); @@ -136,7 +136,7 @@ let latestBackupAt = 0; window.setInterval(() => { if ($i == null) return; if (!store.s.enablePreferencesAutoCloudBackup) return; - if (document.visibilityState !== 'visible') return; // 同期されていない古い値がバックアップされるのを防ぐ + if (window.document.visibilityState !== 'visible') return; // 同期されていない古い値がバックアップされるのを防ぐ if (prefer.profile.modifiedAt <= latestBackupAt) return; cloudBackup().then(() => { diff --git a/packages/frontend/src/preferences/utility.ts b/packages/frontend/src/preferences/utility.ts index bf3dfa157f..7229b7348e 100644 --- a/packages/frontend/src/preferences/utility.ts +++ b/packages/frontend/src/preferences/utility.ts @@ -106,14 +106,14 @@ async function renameProfile() { function exportCurrentProfile() { const p = prefer.profile; const txtBlob = new Blob([JSON.stringify(p)], { type: 'text/plain' }); - const dummya = document.createElement('a'); + const dummya = window.document.createElement('a'); dummya.href = URL.createObjectURL(txtBlob); dummya.download = `${p.name || p.id}.misskeypreferences`; dummya.click(); } function importProfile() { - const input = document.createElement('input'); + const input = window.document.createElement('input'); input.type = 'file'; input.accept = '.misskeypreferences'; input.onchange = async () => { diff --git a/packages/frontend/src/server-context.ts b/packages/frontend/src/server-context.ts index e79d3fa314..744bfa4b7b 100644 --- a/packages/frontend/src/server-context.ts +++ b/packages/frontend/src/server-context.ts @@ -5,7 +5,7 @@ import * as Misskey from 'misskey-js'; -const providedContextEl = document.getElementById('misskey_clientCtx'); +const providedContextEl = window.document.getElementById('misskey_clientCtx'); export type ServerContext = { clip?: Misskey.entities.Clip; diff --git a/packages/frontend/src/stream.ts b/packages/frontend/src/stream.ts index c97d7d4071..25544d9d88 100644 --- a/packages/frontend/src/stream.ts +++ b/packages/frontend/src/stream.ts @@ -29,10 +29,10 @@ export function useStream(): Misskey.IStream { timeoutHeartBeat = window.setTimeout(heartbeat, HEART_BEAT_INTERVAL); // send heartbeat right now when last send time is over HEART_BEAT_INTERVAL - document.addEventListener('visibilitychange', () => { + window.document.addEventListener('visibilitychange', () => { if ( !stream - || document.visibilityState !== 'visible' + || window.document.visibilityState !== 'visible' || Date.now() - lastHeartbeatCall < HEART_BEAT_INTERVAL ) return; heartbeat(); @@ -42,7 +42,7 @@ export function useStream(): Misskey.IStream { } function heartbeat(): void { - if (stream != null && document.visibilityState === 'visible') { + if (stream != null && window.document.visibilityState === 'visible') { stream.heartbeat(); } lastHeartbeatCall = Date.now(); diff --git a/packages/frontend/src/theme.ts b/packages/frontend/src/theme.ts index 970d143b97..cd44fff0c4 100644 --- a/packages/frontend/src/theme.ts +++ b/packages/frontend/src/theme.ts @@ -68,10 +68,10 @@ let timeout: number | null = null; export function applyTheme(theme: Theme, persist = true) { if (timeout) window.clearTimeout(timeout); - document.documentElement.classList.add('_themeChanging_'); + window.document.documentElement.classList.add('_themeChanging_'); timeout = window.setTimeout(() => { - document.documentElement.classList.remove('_themeChanging_'); + window.document.documentElement.classList.remove('_themeChanging_'); // 色計算など再度行えるようにクライアント全体に通知 globalEvents.emit('themeChanged'); @@ -79,7 +79,7 @@ export function applyTheme(theme: Theme, persist = true) { const colorScheme = theme.base === 'dark' ? 'dark' : 'light'; - document.documentElement.dataset.colorScheme = colorScheme; + window.document.documentElement.dataset.colorScheme = colorScheme; // Deep copy const _theme = deepClone(theme); @@ -91,7 +91,7 @@ export function applyTheme(theme: Theme, persist = true) { const props = compile(_theme); - for (const tag of document.head.children) { + for (const tag of window.document.head.children) { if (tag.tagName === 'META' && tag.getAttribute('name') === 'theme-color') { tag.setAttribute('content', props['htmlThemeColor']); break; @@ -99,10 +99,10 @@ export function applyTheme(theme: Theme, persist = true) { } for (const [k, v] of Object.entries(props)) { - document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString()); + window.document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString()); } - document.documentElement.style.setProperty('color-scheme', colorScheme); + window.document.documentElement.style.setProperty('color-scheme', colorScheme); if (persist) { miLocalStorage.setItem('theme', JSON.stringify(props)); diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue index a39a4ee86b..930f633c9f 100644 --- a/packages/frontend/src/ui/_common_/common.vue +++ b/packages/frontend/src/ui/_common_/common.vue @@ -67,7 +67,7 @@ const dev = _DEV_; const notifications = ref([]); function onNotification(notification: Misskey.entities.Notification, isClient = false) { - if (document.visibilityState === 'visible') { + if (window.document.visibilityState === 'visible') { if (!isClient && notification.type !== 'test') { // サーバーサイドのテスト通知の際は自動で既読をつけない(テストできないので) useStream().send('readNotification'); diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index 754bf070fa..98d6f329ab 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -129,8 +129,8 @@ watch(store.r.menuDisplay, () => { }); function toggleIconOnly() { - if (document.startViewTransition && prefer.s.animation) { - document.startViewTransition(() => { + if (window.document.startViewTransition && prefer.s.animation) { + window.document.startViewTransition(() => { store.set('menuDisplay', iconOnly.value ? 'sideFull' : 'sideIcon'); }); } else { diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index 8f35ce0c68..f51577fc68 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -87,9 +87,9 @@ provideMetadataReceiver((metadataGetter) => { pageMetadata.value = info; if (pageMetadata.value) { if (isRoot.value && pageMetadata.value.title === instanceName) { - document.title = pageMetadata.value.title; + window.document.title = pageMetadata.value.title; } else { - document.title = `${pageMetadata.value.title} | ${instanceName}`; + window.document.title = `${pageMetadata.value.title} | ${instanceName}`; } } }); @@ -142,7 +142,7 @@ if (window.innerWidth < 1024) { window.location.reload(); } -document.documentElement.style.overflowY = 'scroll'; +window.document.documentElement.style.overflowY = 'scroll'; onMounted(() => { window.addEventListener('resize', () => { diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 4c33d7cb27..65aff8455a 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -202,8 +202,8 @@ function onWheel(ev: WheelEvent) { } } -document.documentElement.style.overflowY = 'hidden'; -document.documentElement.style.scrollBehavior = 'auto'; +window.document.documentElement.style.overflowY = 'hidden'; +window.document.documentElement.style.scrollBehavior = 'auto'; async function deleteProfile() { if (prefer.s['deck.profile'] == null) return; diff --git a/packages/frontend/src/ui/minimum.vue b/packages/frontend/src/ui/minimum.vue index 94382b664a..ec20ac1114 100644 --- a/packages/frontend/src/ui/minimum.vue +++ b/packages/frontend/src/ui/minimum.vue @@ -30,9 +30,9 @@ provideMetadataReceiver((metadataGetter) => { pageMetadata.value = info; if (pageMetadata.value) { if (isRoot.value && pageMetadata.value.title === instanceName) { - document.title = pageMetadata.value.title; + window.document.title = pageMetadata.value.title; } else { - document.title = `${pageMetadata.value.title} | ${instanceName}`; + window.document.title = `${pageMetadata.value.title} | ${instanceName}`; } } }); diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 92b5d253d3..2742b4cd98 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -143,9 +143,9 @@ provideMetadataReceiver((metadataGetter) => { pageMetadata.value = info; if (pageMetadata.value) { if (isRoot.value && pageMetadata.value.title === instanceName) { - document.title = pageMetadata.value.title; + window.document.title = pageMetadata.value.title; } else { - document.title = `${pageMetadata.value.title} | ${instanceName}`; + window.document.title = `${pageMetadata.value.title} | ${instanceName}`; } } }); @@ -205,12 +205,12 @@ provide>(CURRENT_STICKY_BOTTOM, navFooterHeight); watch(navFooter, () => { if (navFooter.value) { navFooterHeight.value = navFooter.value.offsetHeight; - document.body.style.setProperty('--MI-stickyBottom', `${navFooterHeight.value}px`); - document.body.style.setProperty('--MI-minBottomSpacing', 'var(--MI-minBottomSpacingMobile)'); + window.document.body.style.setProperty('--MI-stickyBottom', `${navFooterHeight.value}px`); + window.document.body.style.setProperty('--MI-minBottomSpacing', 'var(--MI-minBottomSpacingMobile)'); } else { navFooterHeight.value = 0; - document.body.style.setProperty('--MI-stickyBottom', '0px'); - document.body.style.setProperty('--MI-minBottomSpacing', '0px'); + window.document.body.style.setProperty('--MI-stickyBottom', '0px'); + window.document.body.style.setProperty('--MI-minBottomSpacing', '0px'); } }, { immediate: true, diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index ddc3761b04..3e07959458 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -51,9 +51,9 @@ provideMetadataReceiver((metadataGetter) => { pageMetadata.value = info; if (pageMetadata.value) { if (isRoot.value && pageMetadata.value.title === instanceName) { - document.title = pageMetadata.value.title; + window.document.title = pageMetadata.value.title; } else { - document.title = `${pageMetadata.value.title} | ${instanceName}`; + window.document.title = `${pageMetadata.value.title} | ${instanceName}`; } } }); diff --git a/packages/frontend/src/ui/zen.vue b/packages/frontend/src/ui/zen.vue index bfb2ef634b..3e4d452281 100644 --- a/packages/frontend/src/ui/zen.vue +++ b/packages/frontend/src/ui/zen.vue @@ -45,9 +45,9 @@ provideMetadataReceiver((metadataGetter) => { pageMetadata.value = info; if (pageMetadata.value) { if (isRoot.value && pageMetadata.value.title === instanceName) { - document.title = pageMetadata.value.title; + window.document.title = pageMetadata.value.title; } else { - document.title = `${pageMetadata.value.title} | ${instanceName}`; + window.document.title = `${pageMetadata.value.title} | ${instanceName}`; } } }); diff --git a/packages/frontend/src/use/use-note-capture.ts b/packages/frontend/src/use/use-note-capture.ts index 0de2dbb3c5..97aec4c1f0 100644 --- a/packages/frontend/src/use/use-note-capture.ts +++ b/packages/frontend/src/use/use-note-capture.ts @@ -86,7 +86,7 @@ export function useNoteCapture(props: { function capture(withHandler = false): void { if (connection) { // TODO: このノートがストリーミング経由で流れてきた場合のみ sr する - connection.send(document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id }); + connection.send(window.document.body.contains(props.rootEl.value ?? null as Node | null) ? 'sr' : 's', { id: note.value.id }); if (pureNote.value.id !== note.value.id) connection.send('s', { id: pureNote.value.id }); if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated); } diff --git a/packages/frontend/src/use/use-tooltip.ts b/packages/frontend/src/use/use-tooltip.ts index d9ddfc8b5d..af76a3a1e8 100644 --- a/packages/frontend/src/use/use-tooltip.ts +++ b/packages/frontend/src/use/use-tooltip.ts @@ -29,7 +29,7 @@ export function useTooltip( if (!isHovering) return; if (elRef.value == null) return; const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el; - if (!document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため + if (!window.document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため const showing = ref(true); onShow(showing); @@ -38,7 +38,7 @@ export function useTooltip( }; autoHidingTimer = window.setInterval(() => { - if (elRef.value == null || !document.body.contains(elRef.value instanceof Element ? elRef.value : elRef.value.$el)) { + if (elRef.value == null || !window.document.body.contains(elRef.value instanceof Element ? elRef.value : elRef.value.$el)) { if (!isHovering) return; isHovering = false; window.clearTimeout(timeoutId); diff --git a/packages/frontend/src/utility/focus-trap.ts b/packages/frontend/src/utility/focus-trap.ts index fd17fa38a0..13d3bc56d2 100644 --- a/packages/frontend/src/utility/focus-trap.ts +++ b/packages/frontend/src/utility/focus-trap.ts @@ -50,7 +50,7 @@ function releaseFocusTrap(el: HTMLElement): void { const highestZIndexElement = getHighestZIndexElement(); - if (el.parentElement != null && el !== document.body) { + if (el.parentElement != null && el !== window.document.body) { el.parentElement.childNodes.forEach((siblingNode) => { const siblingEl = getHTMLElementOrNull(siblingNode); if (!siblingEl) return; @@ -104,7 +104,7 @@ export function focusTrap(el: HTMLElement, hasInteractionWithOtherFocusTrappedEl el.inert = false; } - if (el.parentElement != null && el !== document.body) { + if (el.parentElement != null && el !== window.document.body) { el.parentElement.childNodes.forEach((siblingNode) => { const siblingEl = getHTMLElementOrNull(siblingNode); if (!siblingEl) return; diff --git a/packages/frontend/src/utility/focus.ts b/packages/frontend/src/utility/focus.ts index e3fd928d1d..cbbe8226d7 100644 --- a/packages/frontend/src/utility/focus.ts +++ b/packages/frontend/src/utility/focus.ts @@ -58,7 +58,7 @@ export const focusParent = (input: MaybeHTMLElement | null | undefined, self = f const focusOrScroll = (element: HTMLElement, scroll: boolean) => { if (scroll) { - const scrollContainer = getScrollContainer(element) ?? document.documentElement; + const scrollContainer = getScrollContainer(element) ?? window.document.documentElement; const scrollContainerTop = getScrollPosition(scrollContainer); const stickyTop = getStickyTop(element, scrollContainer); const stickyBottom = getStickyBottom(element, scrollContainer); @@ -74,7 +74,7 @@ const focusOrScroll = (element: HTMLElement, scroll: boolean) => { scrollContainer.scrollTo({ top: scrollTo, behavior: 'instant' }); } - if (document.activeElement !== element) { + if (window.document.activeElement !== element) { element.focus({ preventScroll: true }); } }; diff --git a/packages/frontend/src/utility/fullscreen.ts b/packages/frontend/src/utility/fullscreen.ts index 7a0a018ef3..6702393cf1 100644 --- a/packages/frontend/src/utility/fullscreen.ts +++ b/packages/frontend/src/utility/fullscreen.ts @@ -35,8 +35,8 @@ export const requestFullscreen = ({ videoEl, playerEl, options }: RequestFullscr export const exitFullscreen = ({ videoEl }: ExitFullscreenProps) => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (document.exitFullscreen != null) { - document.exitFullscreen(); + if (window.document.exitFullscreen != null) { + window.document.exitFullscreen(); return; } if (videoEl.webkitExitFullscreen != null) { diff --git a/packages/frontend/src/utility/hotkey.ts b/packages/frontend/src/utility/hotkey.ts index fe62139a74..81fc28d7c8 100644 --- a/packages/frontend/src/utility/hotkey.ts +++ b/packages/frontend/src/utility/hotkey.ts @@ -54,9 +54,9 @@ export const makeHotkey = (keymap: Keymap) => { const actions = parseKeymap(keymap); return (ev: KeyboardEvent) => { if ('pswp' in window && window.pswp != null) return; - if (document.activeElement != null) { - if (IGNORE_ELEMENTS.includes(document.activeElement.tagName.toLowerCase())) return; - if (getHTMLElementOrNull(document.activeElement)?.isContentEditable) return; + if (window.document.activeElement != null) { + if (IGNORE_ELEMENTS.includes(window.document.activeElement.tagName.toLowerCase())) return; + if (getHTMLElementOrNull(window.document.activeElement)?.isContentEditable) return; } for (const action of actions) { if (matchPatterns(ev, action)) { diff --git a/packages/frontend/src/utility/init-chart.ts b/packages/frontend/src/utility/init-chart.ts index 9775b9fec4..260899c1d7 100644 --- a/packages/frontend/src/utility/init-chart.ts +++ b/packages/frontend/src/utility/init-chart.ts @@ -50,7 +50,7 @@ export function initChart() { ); // フォントカラー - Chart.defaults.color = getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-fg'); + Chart.defaults.color = getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-fg'); Chart.defaults.borderColor = store.s.darkMode ? 'rgba(255, 255, 255, 0.1)' : 'rgba(0, 0, 0, 0.1)'; diff --git a/packages/frontend/src/utility/physics.ts b/packages/frontend/src/utility/physics.ts index 8a4e9319b3..5de34fd094 100644 --- a/packages/frontend/src/utility/physics.ts +++ b/packages/frontend/src/utility/physics.ts @@ -28,7 +28,7 @@ export function physics(container: HTMLElement) { // create renderer const render = Matter.Render.create({ engine: engine, - //element: document.getElementById('debug'), + //element: window.document.getElementById('debug'), options: { width: containerWidth, height: containerHeight, diff --git a/packages/frontend/src/utility/select-file.ts b/packages/frontend/src/utility/select-file.ts index 1bee4986f6..b9b3687483 100644 --- a/packages/frontend/src/utility/select-file.ts +++ b/packages/frontend/src/utility/select-file.ts @@ -25,7 +25,7 @@ export function chooseFileFromPc( const nameConverter = options?.nameConverter ?? (() => undefined); return new Promise((res, rej) => { - const input = document.createElement('input'); + const input = window.document.createElement('input'); input.type = 'file'; input.multiple = multiple; input.onchange = () => { diff --git a/packages/frontend/src/utility/snowfall-effect.ts b/packages/frontend/src/utility/snowfall-effect.ts index d88bdb6660..5c86969876 100644 --- a/packages/frontend/src/utility/snowfall-effect.ts +++ b/packages/frontend/src/utility/snowfall-effect.ts @@ -156,7 +156,7 @@ export class SnowfallEffect { easing: 0.0005, }; /** - * @throws {Error} - Thrown when it fails to get WebGL context for the canvas + * @throws {Error} - Thrown when it fails to get WebGL context for the canvas */ constructor(options: { sakura?: boolean; @@ -172,7 +172,7 @@ export class SnowfallEffect { const gl = canvas.getContext('webgl2', { antialias: true }); if (gl == null) throw new Error('Failed to get WebGL context'); - document.body.append(canvas); + window.document.body.append(canvas); this.canvas = canvas; this.gl = gl; @@ -190,7 +190,7 @@ export class SnowfallEffect { } private initCanvas(): HTMLCanvasElement { - const canvas = document.createElement('canvas'); + const canvas = window.document.createElement('canvas'); Object.assign(canvas.style, { position: 'fixed', diff --git a/packages/frontend/src/utility/sound.ts b/packages/frontend/src/utility/sound.ts index 120f480b63..796af0e5ca 100644 --- a/packages/frontend/src/utility/sound.ts +++ b/packages/frontend/src/utility/sound.ts @@ -226,7 +226,7 @@ export function createSourceNode(buffer: AudioBuffer, opts: { * @param file ファイルのURL(ドライブIDではない) */ export async function getSoundDuration(file: string): Promise { - const audioEl = document.createElement('audio'); + const audioEl = window.document.createElement('audio'); audioEl.src = file; return new Promise((resolve) => { const si = setInterval(() => { @@ -249,7 +249,7 @@ export function isMute(): boolean { } // noinspection RedundantIfStatementJS - if (prefer.s['sound.useSoundOnlyWhenActive'] && document.visibilityState === 'hidden') { + if (prefer.s['sound.useSoundOnlyWhenActive'] && window.document.visibilityState === 'hidden') { // ブラウザがアクティブな時のみサウンドを出力する return true; } diff --git a/packages/frontend/src/utility/sticky-sidebar.ts b/packages/frontend/src/utility/sticky-sidebar.ts index 50f1e6ecc8..867c9b8324 100644 --- a/packages/frontend/src/utility/sticky-sidebar.ts +++ b/packages/frontend/src/utility/sticky-sidebar.ts @@ -18,7 +18,7 @@ export class StickySidebar { this.container = container; this.el = this.container.children[0] as HTMLElement; this.el.style.position = 'sticky'; - this.spacer = document.createElement('div'); + this.spacer = window.document.createElement('div'); this.container.prepend(this.spacer); this.marginTop = marginTop; this.offsetTop = this.container.getBoundingClientRect().top; diff --git a/packages/frontend/src/utility/upload/isWebpSupported.ts b/packages/frontend/src/utility/upload/isWebpSupported.ts index 2511236ecc..affd81fd57 100644 --- a/packages/frontend/src/utility/upload/isWebpSupported.ts +++ b/packages/frontend/src/utility/upload/isWebpSupported.ts @@ -6,7 +6,7 @@ let isWebpSupportedCache: boolean | undefined; export function isWebpSupported() { if (isWebpSupportedCache === undefined) { - const canvas = document.createElement('canvas'); + const canvas = window.document.createElement('canvas'); canvas.width = 1; canvas.height = 1; isWebpSupportedCache = canvas.toDataURL('image/webp').startsWith('data:image/webp'); diff --git a/packages/frontend/src/widgets/WidgetRss.vue b/packages/frontend/src/widgets/WidgetRss.vue index a7213f4c21..132eb0a629 100644 --- a/packages/frontend/src/widgets/WidgetRss.vue +++ b/packages/frontend/src/widgets/WidgetRss.vue @@ -77,7 +77,7 @@ const fetchEndpoint = computed(() => { const intervalClear = ref<(() => void) | undefined>(); const tick = () => { - if (document.visibilityState === 'hidden' && rawItems.value.length !== 0) return; + if (window.document.visibilityState === 'hidden' && rawItems.value.length !== 0) return; window.fetch(fetchEndpoint.value, {}) .then(res => res.json()) diff --git a/packages/frontend/src/widgets/WidgetRssTicker.vue b/packages/frontend/src/widgets/WidgetRssTicker.vue index 13b76533d7..b5be4d35c2 100644 --- a/packages/frontend/src/widgets/WidgetRssTicker.vue +++ b/packages/frontend/src/widgets/WidgetRssTicker.vue @@ -108,7 +108,7 @@ const intervalClear = ref<(() => void) | undefined>(); const key = ref(0); const tick = () => { - if (document.visibilityState === 'hidden' && rawItems.value.length !== 0) return; + if (window.document.visibilityState === 'hidden' && rawItems.value.length !== 0) return; window.fetch(fetchEndpoint.value, {}) .then(res => res.json()) diff --git a/packages/frontend/test/scroll.test.ts b/packages/frontend/test/scroll.test.ts index 32a5a1c558..34e7e64313 100644 --- a/packages/frontend/test/scroll.test.ts +++ b/packages/frontend/test/scroll.test.ts @@ -12,10 +12,10 @@ describe('Scroll', () => { /* 動作しない(happy-domのバグ?) test('Initial onScrollTop callback for connected elements', () => { const { document } = new Window(); - const div = document.createElement('div'); + const div = window.document.createElement('div'); assert.strictEqual(div.scrollTop, 0); - document.body.append(div); + window.document.body.append(div); let called = false; onScrollTop(div as any as HTMLElement, () => called = true); @@ -26,7 +26,7 @@ describe('Scroll', () => { test('No onScrollTop callback for disconnected elements', () => { const { document } = new Window(); - const div = document.createElement('div'); + const div = window.document.createElement('div'); assert.strictEqual(div.scrollTop, 0); let called = false; @@ -40,10 +40,10 @@ describe('Scroll', () => { /* 動作しない(happy-domのバグ?) test('Initial onScrollBottom callback for connected elements', () => { const { document } = new Window(); - const div = document.createElement('div'); + const div = window.document.createElement('div'); assert.strictEqual(div.scrollTop, 0); - document.body.append(div); + window.document.body.append(div); let called = false; onScrollBottom(div as any as HTMLElement, () => called = true); @@ -54,7 +54,7 @@ describe('Scroll', () => { test('No onScrollBottom callback for disconnected elements', () => { const { document } = new Window(); - const div = document.createElement('div'); + const div = window.document.createElement('div'); assert.strictEqual(div.scrollTop, 0); let called = false; From ebc54b1f82454f8bd7b05c54dd9f59b215655a11 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Mar 2025 10:07:37 +0000 Subject: [PATCH 234/649] Bump version to 2025.3.2-beta.7 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 51422b3638..e8993af22c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.3.2-beta.6", + "version": "2025.3.2-beta.7", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index b66f202876..47848f37fd 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.3.2-beta.6", + "version": "2025.3.2-beta.7", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From 1fd87bd2e46eb50f718f95f94d844fe694e43a53 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 20 Mar 2025 20:28:16 +0900 Subject: [PATCH 235/649] fix(frontend): prevent transition glitch of MkHorizontalSwipe --- .../src/components/MkHorizontalSwipe.vue | 6 +-- packages/frontend/src/pages/channel.vue | 8 +-- packages/frontend/src/pages/channels.vue | 10 ++-- packages/frontend/src/pages/drive.file.vue | 4 +- packages/frontend/src/pages/explore.vue | 6 +-- .../frontend/src/pages/flash/flash-index.vue | 6 +-- .../frontend/src/pages/follow-requests.vue | 52 +++++++++---------- packages/frontend/src/pages/gallery/index.vue | 6 +-- packages/frontend/src/pages/instance-info.vue | 12 ++--- .../frontend/src/pages/my-clips/index.vue | 4 +- packages/frontend/src/pages/notifications.vue | 8 +-- packages/frontend/src/pages/pages.vue | 6 +-- packages/frontend/src/pages/search.vue | 4 +- packages/frontend/src/pages/timeline.vue | 4 +- packages/frontend/src/pages/user/index.vue | 24 ++++----- 15 files changed, 79 insertions(+), 81 deletions(-) diff --git a/packages/frontend/src/components/MkHorizontalSwipe.vue b/packages/frontend/src/components/MkHorizontalSwipe.vue index 849136eb8f..bc63bef0b6 100644 --- a/packages/frontend/src/components/MkHorizontalSwipe.vue +++ b/packages/frontend/src/components/MkHorizontalSwipe.vue @@ -19,9 +19,9 @@ SPDX-License-Identifier: AGPL-3.0-only :leaveToClass="transitionName === 'swipeAnimationLeft' ? $style.swipeAnimationLeft_leaveTo : $style.swipeAnimationRight_leaveTo" :style="`--swipe: ${pullDistance}px;`" > - - - +
+ +
diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index 1419e83df7..cd66140bf2 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
@@ -33,7 +33,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
{{ i18n.ts.thisChannelArchived }} @@ -41,10 +41,10 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
-
+
diff --git a/packages/frontend/src/pages/channels.vue b/packages/frontend/src/pages/channels.vue index cf047fcd5d..79d264944a 100644 --- a/packages/frontend/src/pages/channels.vue +++ b/packages/frontend/src/pages/channels.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
@@ -25,28 +25,28 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
-
+
-
+
-
+
diff --git a/packages/frontend/src/pages/drive.file.vue b/packages/frontend/src/pages/drive.file.vue index ecc1117da9..3063d5a4d6 100644 --- a/packages/frontend/src/pages/drive.file.vue +++ b/packages/frontend/src/pages/drive.file.vue @@ -10,11 +10,11 @@ SPDX-License-Identifier: AGPL-3.0-only - + - + diff --git a/packages/frontend/src/pages/explore.vue b/packages/frontend/src/pages/explore.vue index b76f6a6033..794af86e43 100644 --- a/packages/frontend/src/pages/explore.vue +++ b/packages/frontend/src/pages/explore.vue @@ -7,13 +7,13 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
-
+
-
+
diff --git a/packages/frontend/src/pages/flash/flash-index.vue b/packages/frontend/src/pages/flash/flash-index.vue index 6aee91dfda..fedb2de8fe 100644 --- a/packages/frontend/src/pages/flash/flash-index.vue +++ b/packages/frontend/src/pages/flash/flash-index.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
@@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index 1ea501c34c..95f6ba0bc6 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -8,36 +8,34 @@ SPDX-License-Identifier: AGPL-3.0-only -
- - - + diff --git a/packages/frontend/src/pages/gallery/index.vue b/packages/frontend/src/pages/gallery/index.vue index 04445c913c..9a09250bff 100644 --- a/packages/frontend/src/pages/gallery/index.vue +++ b/packages/frontend/src/pages/gallery/index.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
@@ -26,14 +26,14 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
-
+
{{ i18n.ts.postToGallery }}
diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index c4aed8d6df..3f704e2b88 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
{{ instance.name || `(${i18n.ts.unknown})` }} @@ -91,7 +91,7 @@ SPDX-License-Identifier: AGPL-3.0-only manifest.json
-
+
@@ -116,14 +116,14 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
-
+
@@ -135,8 +135,9 @@ SPDX-License-Identifier: AGPL-3.0-only + + diff --git a/packages/frontend/src/components/index.ts b/packages/frontend/src/components/index.ts index c28c457e33..6c6903c3a4 100644 --- a/packages/frontend/src/components/index.ts +++ b/packages/frontend/src/components/index.ts @@ -25,6 +25,8 @@ import MkPageHeader from './global/MkPageHeader.vue'; import MkSpacer from './global/MkSpacer.vue'; import MkStickyContainer from './global/MkStickyContainer.vue'; import MkLazy from './global/MkLazy.vue'; +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'; @@ -60,6 +62,8 @@ export const components = { MkSpacer: MkSpacer, MkStickyContainer: MkStickyContainer, MkLazy: MkLazy, + PageWithHeader: PageWithHeader, + PageWithAnimBg: PageWithAnimBg, SearchMarker: SearchMarker, SearchLabel: SearchLabel, SearchKeyword: SearchKeyword, @@ -89,6 +93,8 @@ declare module '@vue/runtime-core' { MkSpacer: typeof MkSpacer; MkStickyContainer: typeof MkStickyContainer; MkLazy: typeof MkLazy; + PageWithHeader: typeof PageWithHeader; + PageWithAnimBg: typeof PageWithAnimBg; SearchMarker: typeof SearchMarker; SearchLabel: typeof SearchLabel; SearchKeyword: typeof SearchKeyword; diff --git a/packages/frontend/src/pages/about-misskey.vue b/packages/frontend/src/pages/about-misskey.vue index 2d0135e6a6..481088fc30 100644 --- a/packages/frontend/src/pages/about-misskey.vue +++ b/packages/frontend/src/pages/about-misskey.vue @@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/pages/page.vue b/packages/frontend/src/pages/page.vue index cad5f2e109..b684d4b68b 100644 --- a/packages/frontend/src/pages/page.vue +++ b/packages/frontend/src/pages/page.vue @@ -4,8 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index b6ca104830..5a29f942bd 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -51,6 +59,8 @@ import MkRadios from '@/components/MkRadios.vue'; import MkButton from '@/components/MkButton.vue'; import FormSlot from '@/components/form/slot.vue'; import MkContainer from '@/components/MkContainer.vue'; +import MkSwitch from '@/components/MkSwitch.vue'; +import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue'; import * as os from '@/os.js'; import { navbarItemDef } from '@/navbar.js'; import { store } from '@/store.js'; @@ -68,6 +78,7 @@ const items = ref(prefer.s.menu.map(x => ({ }))); const menuDisplay = computed(store.makeGetterSetter('menuDisplay')); +const showNavbarSubButtons = prefer.model('showNavbarSubButtons'); async function addItem() { const menu = Object.keys(navbarItemDef).filter(k => !prefer.s.menu.includes(k)); diff --git a/packages/frontend/src/preferences/def.ts b/packages/frontend/src/preferences/def.ts index 127ebeef0c..310c3856eb 100644 --- a/packages/frontend/src/preferences/def.ts +++ b/packages/frontend/src/preferences/def.ts @@ -329,6 +329,9 @@ export const PREF_DEF = { makeEveryTextElementsSelectable: { default: DEFAULT_DEVICE_KIND === 'desktop', }, + showNavbarSubButtons: { + default: true, + }, plugins: { default: [] as Plugin[], }, diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index 88ce3a96e2..0f00a25d7a 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -65,7 +65,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> -
+
diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts index 64fe328478..7c2ec90dd8 100644 --- a/packages/frontend/src/utility/autogen/settings-search-index.ts +++ b/packages/frontend/src/utility/autogen/settings-search-index.ts @@ -587,6 +587,12 @@ export const searchIndexes: SearchIndexItem[] = [ path: '/settings/other', icon: 'ti ti-dots', }, + { + id: 'pOot4giZs', + label: i18n.ts._settings.showNavbarSubButtons, + keywords: ['toggle', 'button', 'sub'], + path: '/settings/navbar', + }, { id: '3icEvyv2D', children: [ From 600bb34172bc34a401324119128c2dc71a21e506 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Mar 2025 09:54:23 +0900 Subject: [PATCH 262/649] =?UTF-8?q?enhance(frontend):=20=E8=A8=AD=E5=AE=9A?= =?UTF-8?q?=E3=81=AE=E3=82=A4=E3=83=B3=E3=83=87=E3=83=83=E3=82=AF=E3=82=B9?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../frontend/src/pages/settings/navbar.vue | 90 ++++++++++--------- .../utility/autogen/settings-search-index.ts | 14 ++- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/packages/frontend/src/pages/settings/navbar.vue b/packages/frontend/src/pages/settings/navbar.vue index b6fdd009b2..f944490a66 100644 --- a/packages/frontend/src/pages/settings/navbar.vue +++ b/packages/frontend/src/pages/settings/navbar.vue @@ -4,53 +4,55 @@ SPDX-License-Identifier: AGPL-3.0-only -->
- - - - - - - - -
- {{ i18n.ts.addItem }} - {{ i18n.ts.default }} - {{ i18n.ts.save }} -
+ +
+ + + + + + + + +
+ {{ i18n.ts.addItem }} + {{ i18n.ts.default }} + {{ i18n.ts.save }} +
- - - - - + + + + + - + - - - - - - - -
+ + + + + + + +
+ diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index f461ee9bc9..3a7d2cd490 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -429,6 +429,23 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + +
+ + + + + + + +
+
+
+ @@ -609,6 +626,7 @@ const emojiStyle = prefer.model('emojiStyle'); const useBlurEffectForModal = prefer.model('useBlurEffectForModal'); const useBlurEffect = prefer.model('useBlurEffect'); const defaultFollowWithReplies = prefer.model('defaultFollowWithReplies'); +const chatShowSenderName = prefer.model('chat.showSenderName'); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); diff --git a/packages/frontend/src/preferences/def.ts b/packages/frontend/src/preferences/def.ts index 310c3856eb..801bb29e8c 100644 --- a/packages/frontend/src/preferences/def.ts +++ b/packages/frontend/src/preferences/def.ts @@ -374,6 +374,10 @@ export const PREF_DEF = { default: 'left' as 'left' | 'right' | 'center', }, + 'chat.showSenderName': { + default: false, + }, + 'game.dropAndFusion': { default: { bgmVolume: 0.25, diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts index 316319bbf0..1e41dffe22 100644 --- a/packages/frontend/src/utility/autogen/settings-search-index.ts +++ b/packages/frontend/src/utility/autogen/settings-search-index.ts @@ -487,47 +487,59 @@ export const searchIndexes: SearchIndexItem[] = [ id: 'vPQPvmntL', children: [ { - id: 'zoogNoJEO', + id: 'zZxyXHk3A', + label: i18n.ts._settings._chat.showSenderName, + keywords: ['show', 'sender', 'name'], + }, + ], + label: i18n.ts.chat, + keywords: ['chat', 'messaging'], + }, + { + id: 'sCscGhMmH', + children: [ + { + id: 'dLkRNHn3k', label: i18n.ts.squareAvatars, keywords: ['avatar', 'icon', 'square'], }, { - id: '7ix3kvMyU', + id: 'BvooTWFW5', label: i18n.ts.seasonalScreenEffect, keywords: ['effect', 'show'], }, { - id: '6RxgjmMLN', + id: 'yzbghkAq0', label: i18n.ts.openImageInNewTab, keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'], }, { - id: 'alM3BcFzs', + id: 'aSbKFHbOy', label: i18n.ts.withRepliesByDefaultForNewlyFollowed, keywords: ['follow', 'replies'], }, { - id: 'yzbghkAq0', + id: '89bn97UgY', label: i18n.ts.whenServerDisconnected, keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'], }, { - id: '4SPd8QhYx', + id: 'hgf3rgdA6', label: i18n.ts.numberOfPageCache, keywords: ['cache', 'page'], }, { - id: 'BoNg4LwOq', + id: '6FVdHPhhv', label: i18n.ts.forceShowAds, keywords: ['ad', 'show'], }, { - id: 'hgf3rgdA6', + id: '5Bx5DAST1', label: i18n.ts.hemisphere, keywords: [], }, { - id: 'nnj4DkjhP', + id: 'wv7Cwiwb1', label: i18n.ts.additionalEmojiDictionary, keywords: ['emoji', 'dictionary', 'additional', 'extra'], }, From 2272eceffa42f3b3ed0602d0f30bfafc03a9a49e Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:19:54 +0900 Subject: [PATCH 270/649] =?UTF-8?q?enhance(frontend):=20Enter=E3=81=A7?= =?UTF-8?q?=E3=83=81=E3=83=A3=E3=83=83=E3=83=88=E3=81=AE=E3=83=A1=E3=83=83?= =?UTF-8?q?=E3=82=BB=E3=83=BC=E3=82=B8=E3=82=92=E9=80=81=E4=BF=A1=E3=81=A7?= =?UTF-8?q?=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 20 ++++++++++++++ locales/ja-JP.yml | 5 ++++ .../frontend/src/pages/chat/room.form.vue | 12 +++++++-- .../src/pages/settings/preferences.vue | 26 ++++++++++++++++++- packages/frontend/src/preferences/def.ts | 3 +++ .../utility/autogen/settings-search-index.ts | 25 +++++++++++------- 6 files changed, 78 insertions(+), 13 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 0fcfcee7e5..b0da7915dc 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5448,6 +5448,14 @@ export interface Locale extends ILocale { * ホーム */ "home": string; + /** + * 送信 + */ + "send": string; + /** + * 改行 + */ + "newline": string; /** * このルームをミュート */ @@ -5614,11 +5622,23 @@ export interface Locale extends ILocale { * ナビゲーションバーに副ボタンを表示 */ "showNavbarSubButtons": string; + /** + * オンのとき + */ + "ifOn": string; + /** + * オフのとき + */ + "ifOff": string; "_chat": { /** * 送信者の名前を表示 */ "showSenderName": string; + /** + * Enterで送信 + */ + "sendOnEnter": string; }; }; "_preferencesProfile": { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e770d04768..b95adb1871 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1359,6 +1359,8 @@ _chat: members: "メンバー" searchMessages: "メッセージを検索" home: "ホーム" + send: "送信" + newline: "改行" muteThisRoom: "このルームをミュート" deleteRoom: "ルームを削除" cannotChatWithTheUser: "このユーザーとのチャットを開始できません" @@ -1404,9 +1406,12 @@ _settings: makeEveryTextElementsSelectable: "全てのテキスト要素を選択可能にする" makeEveryTextElementsSelectable_description: "有効にすると、一部のシチュエーションでのユーザビリティが低下する場合があります。" showNavbarSubButtons: "ナビゲーションバーに副ボタンを表示" + ifOn: "オンのとき" + ifOff: "オフのとき" _chat: showSenderName: "送信者の名前を表示" + sendOnEnter: "Enterで送信" _preferencesProfile: profileName: "プロファイル名" diff --git a/packages/frontend/src/pages/chat/room.form.vue b/packages/frontend/src/pages/chat/room.form.vue index aba9d6061f..27ddbeb565 100644 --- a/packages/frontend/src/pages/chat/room.form.vue +++ b/packages/frontend/src/pages/chat/room.form.vue @@ -151,8 +151,16 @@ function onDrop(ev: DragEvent): void { } function onKeydown(ev: KeyboardEvent) { - if ((ev.key === 'Enter') && (ev.ctrlKey || ev.metaKey)) { - send(); + if (ev.key === 'Enter') { + if (prefer.s['chat.sendOnEnter']) { + if (!(ev.ctrlKey || ev.metaKey || ev.shiftKey)) { + send(); + } + } else { + if ((ev.ctrlKey || ev.metaKey)) { + send(); + } + } } } diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index 3a7d2cd490..816f8d7435 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -434,7 +434,7 @@ SPDX-License-Identifier: AGPL-3.0-only -
+
@@ -442,6 +442,28 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + + +
@@ -627,6 +649,7 @@ const useBlurEffectForModal = prefer.model('useBlurEffectForModal'); const useBlurEffect = prefer.model('useBlurEffect'); const defaultFollowWithReplies = prefer.model('defaultFollowWithReplies'); const chatShowSenderName = prefer.model('chat.showSenderName'); +const chatSendOnEnter = prefer.model('chat.sendOnEnter'); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); @@ -654,6 +677,7 @@ watch([ squareAvatars, highlightSensitiveMedia, enableSeasonalScreenEffect, + chatShowSenderName, ], async () => { await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true }); }); diff --git a/packages/frontend/src/preferences/def.ts b/packages/frontend/src/preferences/def.ts index 801bb29e8c..b588cc3b5f 100644 --- a/packages/frontend/src/preferences/def.ts +++ b/packages/frontend/src/preferences/def.ts @@ -377,6 +377,9 @@ export const PREF_DEF = { 'chat.showSenderName': { default: false, }, + 'chat.sendOnEnter': { + default: false, + }, 'game.dropAndFusion': { default: { diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts index 1e41dffe22..c939c93425 100644 --- a/packages/frontend/src/utility/autogen/settings-search-index.ts +++ b/packages/frontend/src/utility/autogen/settings-search-index.ts @@ -491,55 +491,60 @@ export const searchIndexes: SearchIndexItem[] = [ label: i18n.ts._settings._chat.showSenderName, keywords: ['show', 'sender', 'name'], }, + { + id: 'omEy5Q3Ev', + label: i18n.ts._settings._chat.sendOnEnter, + keywords: ['send', 'enter', 'newline'], + }, ], label: i18n.ts.chat, keywords: ['chat', 'messaging'], }, { - id: 'sCscGhMmH', + id: '5fy7VEy6i', children: [ { - id: 'dLkRNHn3k', + id: 'EosiWZvak', label: i18n.ts.squareAvatars, keywords: ['avatar', 'icon', 'square'], }, { - id: 'BvooTWFW5', + id: 'qY5xTzl35', label: i18n.ts.seasonalScreenEffect, keywords: ['effect', 'show'], }, { - id: 'yzbghkAq0', + id: '2VSnj81vC', label: i18n.ts.openImageInNewTab, keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'], }, { - id: 'aSbKFHbOy', + id: 'hdQa7W2H1', label: i18n.ts.withRepliesByDefaultForNewlyFollowed, keywords: ['follow', 'replies'], }, { - id: '89bn97UgY', + id: 'nnj4DkjhP', label: i18n.ts.whenServerDisconnected, keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'], }, { - id: 'hgf3rgdA6', + id: 'Eh7vTluDO', label: i18n.ts.numberOfPageCache, keywords: ['cache', 'page'], }, { - id: '6FVdHPhhv', + id: 'vTRSKf1JA', label: i18n.ts.forceShowAds, keywords: ['ad', 'show'], }, { - id: '5Bx5DAST1', + id: 'dwhQfcLGt', label: i18n.ts.hemisphere, keywords: [], }, { - id: 'wv7Cwiwb1', + id: 'Ar1lj7f7U', label: i18n.ts.additionalEmojiDictionary, keywords: ['emoji', 'dictionary', 'additional', 'extra'], }, From 1736955694336096dd0e6e999c43fefa4c55801b Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:29:03 +0900 Subject: [PATCH 271/649] =?UTF-8?q?fix(backend):=20=E8=87=AA=E5=88=86?= =?UTF-8?q?=E3=81=8C=E3=82=AA=E3=83=BC=E3=83=8A=E3=83=BC=E3=81=A7=E3=81=AF?= =?UTF-8?q?=E3=81=AA=E3=81=84=E5=8F=82=E5=8A=A0=E4=B8=AD=E3=81=AE=E3=83=AB?= =?UTF-8?q?=E3=83=BC=E3=83=A0=E3=81=AB=E3=83=A1=E3=83=83=E3=82=BB=E3=83=BC?= =?UTF-8?q?=E3=82=B8=E3=82=92=E9=80=81=E4=BF=A1=E3=81=99=E3=82=8B=E3=81=A8?= =?UTF-8?q?=E4=B8=8D=E5=BF=85=E8=A6=81=E3=81=AA=E9=80=9A=E7=9F=A5=E3=81=8C?= =?UTF-8?q?=E7=99=BA=E7=94=9F=E3=81=99=E3=82=8B=E3=81=AE=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/ChatService.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts index 57e33af107..3b73a0f6ba 100644 --- a/packages/backend/src/core/ChatService.ts +++ b/packages/backend/src/core/ChatService.ts @@ -199,6 +199,8 @@ export class ChatService { throw new Error('you are not a member of the room'); } + const membershipsOtherThanMe = memberships.filter(member => member.userId !== fromUser.id); + const message = { id: this.idService.gen(), fromUserId: fromUser.id, @@ -216,7 +218,7 @@ export class ChatService { this.globalEventService.publishChatRoomStream(toRoom.id, 'message', packedMessage); const redisPipeline = this.redisClient.pipeline(); - for (const membership of memberships) { + for (const membership of membershipsOtherThanMe) { if (membership.isMuted) continue; redisPipeline.set(`newRoomChatMessageExists:${membership.userId}:${toRoom.id}`, message.id); @@ -227,7 +229,7 @@ export class ChatService { // 3秒経っても既読にならなかったらイベント発行 setTimeout(async () => { const redisPipeline = this.redisClient.pipeline(); - for (const membership of memberships) { + for (const membership of membershipsOtherThanMe) { redisPipeline.get(`newRoomChatMessageExists:${membership.userId}:${toRoom.id}`); } const markers = await redisPipeline.exec(); @@ -237,12 +239,12 @@ export class ChatService { const packedMessageForTo = await this.chatEntityService.packMessageDetailed(inserted); - for (let i = 0; i < memberships.length; i++) { + for (let i = 0; i < membershipsOtherThanMe.length; i++) { const marker = markers[i][1]; if (marker == null) continue; - this.globalEventService.publishMainStream(memberships[i].userId, 'newChatMessage', packedMessageForTo); - //this.pushNotificationService.pushNotification(memberships[i].userId, 'newChatMessage', packedMessageForTo); + this.globalEventService.publishMainStream(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo); + //this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo); } }, 3000); From c51e862b7de460cd7c1b57a63a002156bbfe1b49 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Mar 2025 13:41:12 +0900 Subject: [PATCH 272/649] =?UTF-8?q?enhance:=20=E9=80=81=E4=BF=A1=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=83=81=E3=83=A3=E3=83=83=E3=83=88=E3=83=AB=E3=83=BC?= =?UTF-8?q?=E3=83=A0=E3=81=B8=E3=81=AE=E6=8B=9B=E5=BE=85=E3=82=92=E7=A2=BA?= =?UTF-8?q?=E8=AA=8D=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 4 ++ locales/ja-JP.yml | 1 + packages/backend/src/core/ChatService.ts | 10 +++ .../backend/src/server/api/endpoint-list.ts | 1 + .../chat/rooms/invitations/outbox.ts | 67 ++++++++++++++++++ .../frontend/src/pages/chat/room.members.vue | 32 ++++++++- packages/misskey-js/etc/misskey-js.api.md | 8 +++ .../misskey-js/src/autogen/apiClientJSDoc.ts | 11 +++ packages/misskey-js/src/autogen/endpoint.ts | 3 + packages/misskey-js/src/autogen/entities.ts | 2 + packages/misskey-js/src/autogen/types.ts | 69 +++++++++++++++++++ 11 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 packages/backend/src/server/api/endpoints/chat/rooms/invitations/outbox.ts diff --git a/locales/index.d.ts b/locales/index.d.ts index b0da7915dc..eee9de8f0d 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5424,6 +5424,10 @@ export interface Locale extends ILocale { * ユーザーを招待 */ "inviteUser": string; + /** + * 送信した招待 + */ + "sentInvitations": string; /** * 参加 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index b95adb1871..e4c17276b1 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1353,6 +1353,7 @@ _chat: noHistory: "履歴はありません" noRooms: "ルームはありません" inviteUser: "ユーザーを招待" + sentInvitations: "送信した招待" join: "参加" ignore: "無視" leave: "ルームから退出" diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts index 3b73a0f6ba..062ca96f17 100644 --- a/packages/backend/src/core/ChatService.ts +++ b/packages/backend/src/core/ChatService.ts @@ -547,6 +547,16 @@ export class ChatService { return created; } + @bindThis + public async getSentRoomInvitationsWithPagination(roomId: MiChatRoom['id'], limit: number, sinceId?: MiChatRoomInvitation['id'] | null, untilId?: MiChatRoomInvitation['id'] | null) { + const query = this.queryService.makePaginationQuery(this.chatRoomInvitationsRepository.createQueryBuilder('invitation'), sinceId, untilId) + .where('invitation.roomId = :roomId', { roomId }); + + const invitations = await query.take(limit).getMany(); + + return invitations; + } + @bindThis public async getOwnedRoomsWithPagination(ownerId: MiUser['id'], limit: number, sinceId?: MiChatRoom['id'] | null, untilId?: MiChatRoom['id'] | null) { const query = this.queryService.makePaginationQuery(this.chatRoomsRepository.createQueryBuilder('room'), sinceId, untilId) diff --git a/packages/backend/src/server/api/endpoint-list.ts b/packages/backend/src/server/api/endpoint-list.ts index 9bb29e138b..c8cb87e0ab 100644 --- a/packages/backend/src/server/api/endpoint-list.ts +++ b/packages/backend/src/server/api/endpoint-list.ts @@ -417,5 +417,6 @@ export * as 'chat/rooms/members' from './endpoints/chat/rooms/members.js'; export * as 'chat/rooms/invitations/create' from './endpoints/chat/rooms/invitations/create.js'; export * as 'chat/rooms/invitations/ignore' from './endpoints/chat/rooms/invitations/ignore.js'; export * as 'chat/rooms/invitations/inbox' from './endpoints/chat/rooms/invitations/inbox.js'; +export * as 'chat/rooms/invitations/outbox' from './endpoints/chat/rooms/invitations/outbox.js'; export * as 'chat/history' from './endpoints/chat/history.js'; export * as 'v2/admin/emoji/list' from './endpoints/v2/admin/emoji/list.js'; diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/invitations/outbox.ts b/packages/backend/src/server/api/endpoints/chat/rooms/invitations/outbox.ts new file mode 100644 index 0000000000..12d496e94b --- /dev/null +++ b/packages/backend/src/server/api/endpoints/chat/rooms/invitations/outbox.ts @@ -0,0 +1,67 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { Inject, Injectable } from '@nestjs/common'; +import ms from 'ms'; +import { Endpoint } from '@/server/api/endpoint-base.js'; +import { DI } from '@/di-symbols.js'; +import { ApiError } from '@/server/api/error.js'; +import { ChatService } from '@/core/ChatService.js'; +import { ChatEntityService } from '@/core/entities/ChatEntityService.js'; + +export const meta = { + tags: ['chat'], + + requireCredential: true, + + kind: 'read:chat', + + res: { + type: 'array', + optional: false, nullable: false, + items: { + type: 'object', + optional: false, nullable: false, + ref: 'ChatRoomInvitation', + }, + }, + + errors: { + noSuchRoom: { + message: 'No such room.', + code: 'NO_SUCH_ROOM', + id: 'a3c6b309-9717-4316-ae94-a69b53437237', + }, + }, +} as const; + +export const paramDef = { + type: 'object', + properties: { + roomId: { type: 'string', format: 'misskey:id' }, + limit: { type: 'integer', minimum: 1, maximum: 100, default: 30 }, + sinceId: { type: 'string', format: 'misskey:id' }, + untilId: { type: 'string', format: 'misskey:id' }, + }, + required: ['roomId'], +} as const; + +@Injectable() +export default class extends Endpoint { // eslint-disable-line import/no-default-export + constructor( + private chatService: ChatService, + private chatEntityService: ChatEntityService, + ) { + super(meta, paramDef, async (ps, me) => { + const room = await this.chatService.findMyRoomById(me.id, ps.roomId); + if (room == null) { + throw new ApiError(meta.errors.noSuchRoom); + } + + const invitations = await this.chatService.getSentRoomInvitationsWithPagination(ps.roomId, ps.limit, ps.sinceId, ps.untilId); + return this.chatEntityService.packRoomInvitations(invitations, me); + }); + } +} diff --git a/packages/frontend/src/pages/chat/room.members.vue b/packages/frontend/src/pages/chat/room.members.vue index d20216a81c..2b31efab38 100644 --- a/packages/frontend/src/pages/chat/room.members.vue +++ b/packages/frontend/src/pages/chat/room.members.vue @@ -18,6 +18,18 @@ SPDX-License-Identifier: AGPL-3.0-only
+ +
@@ -47,12 +59,20 @@ const isOwner = computed(() => { }); const memberships = ref([]); +const invitations = ref([]); onMounted(async () => { memberships.value = await misskeyApi('chat/rooms/members', { roomId: props.room.id, limit: 50, }); + + if (isOwner.value) { + invitations.value = await misskeyApi('chat/rooms/invitations/outbox', { + roomId: props.room.id, + limit: 50, + }); + } }); @@ -65,9 +85,15 @@ onMounted(async () => { flex: 1; min-width: 0; margin-right: 8px; +} - &:hover { - text-decoration: none; - } +.invitation { + display: flex; +} + +.invitationBody { + flex: 1; + min-width: 0; + margin-right: 8px; } diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index e79cd794a6..8610a21304 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1046,6 +1046,12 @@ type ChatRoomsInvitationsInboxRequest = operations['chat___rooms___invitations__ // @public (undocumented) type ChatRoomsInvitationsInboxResponse = operations['chat___rooms___invitations___inbox']['responses']['200']['content']['application/json']; +// @public (undocumented) +type ChatRoomsInvitationsOutboxRequest = operations['chat___rooms___invitations___outbox']['requestBody']['content']['application/json']; + +// @public (undocumented) +type ChatRoomsInvitationsOutboxResponse = operations['chat___rooms___invitations___outbox']['responses']['200']['content']['application/json']; + // @public (undocumented) type ChatRoomsJoiningRequest = operations['chat___rooms___joining']['requestBody']['content']['application/json']; @@ -1619,6 +1625,8 @@ declare namespace entities { ChatRoomsInvitationsIgnoreResponse, ChatRoomsInvitationsInboxRequest, ChatRoomsInvitationsInboxResponse, + ChatRoomsInvitationsOutboxRequest, + ChatRoomsInvitationsOutboxResponse, ChatRoomsJoinRequest, ChatRoomsJoinResponse, ChatRoomsJoiningRequest, diff --git a/packages/misskey-js/src/autogen/apiClientJSDoc.ts b/packages/misskey-js/src/autogen/apiClientJSDoc.ts index e12ba0d6b2..e5d0b94a10 100644 --- a/packages/misskey-js/src/autogen/apiClientJSDoc.ts +++ b/packages/misskey-js/src/autogen/apiClientJSDoc.ts @@ -1688,6 +1688,17 @@ declare module '../api.js' { credential?: string | null, ): Promise>; + /** + * No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:chat* + */ + request( + endpoint: E, + params: P, + credential?: string | null, + ): Promise>; + /** * No description provided. * diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 558f4ab514..1dfdb53320 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -235,6 +235,8 @@ import type { ChatRoomsInvitationsIgnoreResponse, ChatRoomsInvitationsInboxRequest, ChatRoomsInvitationsInboxResponse, + ChatRoomsInvitationsOutboxRequest, + ChatRoomsInvitationsOutboxResponse, ChatRoomsJoinRequest, ChatRoomsJoinResponse, ChatRoomsJoiningRequest, @@ -784,6 +786,7 @@ export type Endpoints = { 'chat/rooms/invitations/create': { req: ChatRoomsInvitationsCreateRequest; res: ChatRoomsInvitationsCreateResponse }; 'chat/rooms/invitations/ignore': { req: ChatRoomsInvitationsIgnoreRequest; res: ChatRoomsInvitationsIgnoreResponse }; 'chat/rooms/invitations/inbox': { req: ChatRoomsInvitationsInboxRequest; res: ChatRoomsInvitationsInboxResponse }; + 'chat/rooms/invitations/outbox': { req: ChatRoomsInvitationsOutboxRequest; res: ChatRoomsInvitationsOutboxResponse }; 'chat/rooms/join': { req: ChatRoomsJoinRequest; res: ChatRoomsJoinResponse }; 'chat/rooms/joining': { req: ChatRoomsJoiningRequest; res: ChatRoomsJoiningResponse }; 'chat/rooms/leave': { req: ChatRoomsLeaveRequest; res: ChatRoomsLeaveResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index bb21272e01..0e3ca7202e 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -238,6 +238,8 @@ export type ChatRoomsInvitationsIgnoreRequest = operations['chat___rooms___invit export type ChatRoomsInvitationsIgnoreResponse = operations['chat___rooms___invitations___ignore']['responses']['200']['content']['application/json']; export type ChatRoomsInvitationsInboxRequest = operations['chat___rooms___invitations___inbox']['requestBody']['content']['application/json']; export type ChatRoomsInvitationsInboxResponse = operations['chat___rooms___invitations___inbox']['responses']['200']['content']['application/json']; +export type ChatRoomsInvitationsOutboxRequest = operations['chat___rooms___invitations___outbox']['requestBody']['content']['application/json']; +export type ChatRoomsInvitationsOutboxResponse = operations['chat___rooms___invitations___outbox']['responses']['200']['content']['application/json']; export type ChatRoomsJoinRequest = operations['chat___rooms___join']['requestBody']['content']['application/json']; export type ChatRoomsJoinResponse = operations['chat___rooms___join']['responses']['200']['content']['application/json']; export type ChatRoomsJoiningRequest = operations['chat___rooms___joining']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 31bc34e473..3acef22101 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -1484,6 +1484,15 @@ export type paths = { */ post: operations['chat___rooms___invitations___inbox']; }; + '/chat/rooms/invitations/outbox': { + /** + * chat/rooms/invitations/outbox + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:chat* + */ + post: operations['chat___rooms___invitations___outbox']; + }; '/chat/rooms/join': { /** * chat/rooms/join @@ -14737,6 +14746,66 @@ export type operations = { }; }; }; + /** + * chat/rooms/invitations/outbox + * @description No description provided. + * + * **Credential required**: *Yes* / **Permission**: *read:chat* + */ + chat___rooms___invitations___outbox: { + requestBody: { + content: { + 'application/json': { + /** Format: misskey:id */ + roomId: string; + /** @default 30 */ + limit?: number; + /** Format: misskey:id */ + sinceId?: string; + /** Format: misskey:id */ + untilId?: string; + }; + }; + }; + responses: { + /** @description OK (with results) */ + 200: { + content: { + 'application/json': components['schemas']['ChatRoomInvitation'][]; + }; + }; + /** @description Client error */ + 400: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Authentication error */ + 401: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Forbidden error */ + 403: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description I'm Ai */ + 418: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + /** @description Internal server error */ + 500: { + content: { + 'application/json': components['schemas']['Error']; + }; + }; + }; + }; /** * chat/rooms/join * @description No description provided. From 2fc3baa9882dd257a1ed91277ced85b862eb2836 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 25 Mar 2025 04:45:07 +0000 Subject: [PATCH 273/649] Bump version to 2025.3.2-beta.12 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8acf676bff..fc2de6e887 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.3.2-beta.11", + "version": "2025.3.2-beta.12", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index ec98e1542b..dc4d49183b 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.3.2-beta.11", + "version": "2025.3.2-beta.12", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From 304d0eb83b6e10336ec319600f060f0a719d07b9 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 25 Mar 2025 15:25:43 +0900 Subject: [PATCH 274/649] =?UTF-8?q?enhance:=20=E3=83=81=E3=83=A3=E3=83=83?= =?UTF-8?q?=E3=83=88=E3=83=AB=E3=83=BC=E3=83=A0=E3=81=AB=E6=8B=9B=E5=BE=85?= =?UTF-8?q?=E3=81=95=E3=82=8C=E3=81=9F=E3=81=A8=E3=81=8D=E3=81=AE=E9=80=9A?= =?UTF-8?q?=E7=9F=A5=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- locales/index.d.ts | 8 ++++ locales/ja-JP.yml | 2 + packages/backend/src/core/ChatService.ts | 6 +++ .../entities/NotificationEntityService.ts | 23 +++++++--- packages/backend/src/models/Notification.ts | 6 +++ .../src/models/json-schema/notification.ts | 15 +++++++ .../backend/src/models/json-schema/user.ts | 1 + .../server/api/endpoints/admin/show-user.ts | 1 + .../src/server/api/endpoints/i/update.ts | 1 + packages/backend/src/types.ts | 2 + packages/frontend-shared/js/const.ts | 1 + .../src/components/MkNotification.vue | 5 +++ packages/misskey-js/etc/misskey-js.api.md | 2 +- packages/misskey-js/src/autogen/types.ts | 43 +++++++++++++++++-- packages/misskey-js/src/consts.ts | 2 +- 15 files changed, 105 insertions(+), 13 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index eee9de8f0d..f7d875d2c8 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -9883,6 +9883,10 @@ export interface Locale extends ILocale { * ロールが付与されました */ "roleAssigned": string; + /** + * チャットルームへ招待されました + */ + "chatRoomInvitationReceived": string; /** * プッシュ通知の更新をしました */ @@ -9992,6 +9996,10 @@ export interface Locale extends ILocale { * ロールが付与された */ "roleAssigned": string; + /** + * チャットルームへ招待された + */ + "chatRoomInvitationReceived": string; /** * 実績の獲得 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e4c17276b1..efaa279454 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2612,6 +2612,7 @@ _notification: newNote: "新しい投稿" unreadAntennaNote: "アンテナ {name}" roleAssigned: "ロールが付与されました" + chatRoomInvitationReceived: "チャットルームへ招待されました" emptyPushNotificationMessage: "プッシュ通知の更新をしました" achievementEarned: "実績を獲得" testNotification: "通知テスト" @@ -2641,6 +2642,7 @@ _notification: receiveFollowRequest: "フォロー申請を受け取った" followRequestAccepted: "フォローが受理された" roleAssigned: "ロールが付与された" + chatRoomInvitationReceived: "チャットルームへ招待された" achievementEarned: "実績の獲得" exportCompleted: "エクスポートが完了した" login: "ログイン" diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts index 062ca96f17..4c010b2ef7 100644 --- a/packages/backend/src/core/ChatService.ts +++ b/packages/backend/src/core/ChatService.ts @@ -26,6 +26,7 @@ import { Packed } from '@/misc/json-schema.js'; import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; import { CustomEmojiService } from '@/core/CustomEmojiService.js'; import { emojiRegex } from '@/misc/emoji-regex.js'; +import { NotificationService } from '@/core/NotificationService.js'; const MAX_ROOM_MEMBERS = 30; const MAX_REACTIONS_PER_MESSAGE = 100; @@ -68,6 +69,7 @@ export class ChatService { private apRendererService: ApRendererService, private queueService: QueueService, private pushNotificationService: PushNotificationService, + private notificationService: NotificationService, private userBlockingService: UserBlockingService, private queryService: QueryService, private roleService: RoleService, @@ -544,6 +546,10 @@ export class ChatService { const created = await this.chatRoomInvitationsRepository.insertOne(invitation); + this.notificationService.createNotification(inviteeId, 'chatRoomInvitationReceived', { + invitationId: invitation.id, + }, inviterId); + return created; } diff --git a/packages/backend/src/core/entities/NotificationEntityService.ts b/packages/backend/src/core/entities/NotificationEntityService.ts index dff6968f9c..d8b947839f 100644 --- a/packages/backend/src/core/entities/NotificationEntityService.ts +++ b/packages/backend/src/core/entities/NotificationEntityService.ts @@ -16,6 +16,7 @@ import { bindThis } from '@/decorators.js'; import { FilterUnionByProperty, groupedNotificationTypes } from '@/types.js'; import { CacheService } from '@/core/CacheService.js'; import { RoleEntityService } from './RoleEntityService.js'; +import { ChatEntityService } from './ChatEntityService.js'; import type { OnModuleInit } from '@nestjs/common'; import type { UserEntityService } from './UserEntityService.js'; import type { NoteEntityService } from './NoteEntityService.js'; @@ -27,6 +28,7 @@ export class NotificationEntityService implements OnModuleInit { private userEntityService: UserEntityService; private noteEntityService: NoteEntityService; private roleEntityService: RoleEntityService; + private chatEntityService: ChatEntityService; constructor( private moduleRef: ModuleRef, @@ -41,9 +43,6 @@ export class NotificationEntityService implements OnModuleInit { private followRequestsRepository: FollowRequestsRepository, private cacheService: CacheService, - - //private userEntityService: UserEntityService, - //private noteEntityService: NoteEntityService, ) { } @@ -51,6 +50,7 @@ export class NotificationEntityService implements OnModuleInit { this.userEntityService = this.moduleRef.get('UserEntityService'); this.noteEntityService = this.moduleRef.get('NoteEntityService'); this.roleEntityService = this.moduleRef.get('RoleEntityService'); + this.chatEntityService = this.moduleRef.get('ChatEntityService'); } /** @@ -59,7 +59,6 @@ export class NotificationEntityService implements OnModuleInit { async #packInternal ( src: T, meId: MiUser['id'], - options: { checkValidNotifier?: boolean; }, @@ -92,7 +91,7 @@ export class NotificationEntityService implements OnModuleInit { // if the user has been deleted, don't show this notification if (needsUser && !userIfNeed) return null; - // #region Grouped notifications + //#region Grouped notifications if (notification.type === 'reaction:grouped') { const reactions = (await Promise.all(notification.reactions.map(async reaction => { const user = hint?.packedUsers != null @@ -137,7 +136,7 @@ export class NotificationEntityService implements OnModuleInit { users, }); } - // #endregion + //#endregion const needsRole = notification.type === 'roleAssigned'; const role = needsRole ? await this.roleEntityService.pack(notification.roleId) : undefined; @@ -146,6 +145,13 @@ export class NotificationEntityService implements OnModuleInit { return null; } + const needsChatRoomInvitation = notification.type === 'chatRoomInvitationReceived'; + const chatRoomInvitation = needsChatRoomInvitation ? await this.chatEntityService.packRoomInvitation(notification.invitationId, { id: meId }) : undefined; + // if the invitation has been deleted, don't show this notification + if (needsChatRoomInvitation && !chatRoomInvitation) { + return null; + } + return await awaitAll({ id: notification.id, createdAt: new Date(notification.createdAt).toISOString(), @@ -159,6 +165,9 @@ export class NotificationEntityService implements OnModuleInit { ...(notification.type === 'roleAssigned' ? { role: role, } : {}), + ...(notification.type === 'chatRoomInvitationReceived' ? { + invitation: chatRoomInvitation, + } : {}), ...(notification.type === 'followRequestAccepted' ? { message: notification.message, } : {}), @@ -236,7 +245,7 @@ export class NotificationEntityService implements OnModuleInit { public async pack( src: MiNotification | MiGroupedNotification, meId: MiUser['id'], - + options: { checkValidNotifier?: boolean; }, diff --git a/packages/backend/src/models/Notification.ts b/packages/backend/src/models/Notification.ts index 5772ace338..5764a307b0 100644 --- a/packages/backend/src/models/Notification.ts +++ b/packages/backend/src/models/Notification.ts @@ -75,6 +75,12 @@ export type MiNotification = { id: string; createdAt: string; roleId: MiRole['id']; +} | { + type: 'chatRoomInvitationReceived'; + id: string; + createdAt: string; + notifierId: MiUser['id']; + invitationId: string; } | { type: 'achievementEarned'; id: string; diff --git a/packages/backend/src/models/json-schema/notification.ts b/packages/backend/src/models/json-schema/notification.ts index 1638b2b3c7..7f23d2d6a1 100644 --- a/packages/backend/src/models/json-schema/notification.ts +++ b/packages/backend/src/models/json-schema/notification.ts @@ -287,6 +287,21 @@ export const packedNotificationSchema = { optional: false, nullable: false, }, }, + }, { + type: 'object', + properties: { + ...baseSchema.properties, + type: { + type: 'string', + optional: false, nullable: false, + enum: ['chatRoomInvitationReceived'], + }, + invitation: { + type: 'object', + ref: 'ChatRoomInvitation', + optional: false, nullable: false, + }, + }, }, { type: 'object', properties: { diff --git a/packages/backend/src/models/json-schema/user.ts b/packages/backend/src/models/json-schema/user.ts index b10430782b..0094f25e34 100644 --- a/packages/backend/src/models/json-schema/user.ts +++ b/packages/backend/src/models/json-schema/user.ts @@ -608,6 +608,7 @@ export const packedMeDetailedOnlySchema = { receiveFollowRequest: { optional: true, ...notificationRecieveConfig }, followRequestAccepted: { optional: true, ...notificationRecieveConfig }, roleAssigned: { optional: true, ...notificationRecieveConfig }, + chatRoomInvitationReceived: { optional: true, ...notificationRecieveConfig }, achievementEarned: { optional: true, ...notificationRecieveConfig }, app: { optional: true, ...notificationRecieveConfig }, test: { optional: true, ...notificationRecieveConfig }, diff --git a/packages/backend/src/server/api/endpoints/admin/show-user.ts b/packages/backend/src/server/api/endpoints/admin/show-user.ts index 655bd32bce..1ba6853dbe 100644 --- a/packages/backend/src/server/api/endpoints/admin/show-user.ts +++ b/packages/backend/src/server/api/endpoints/admin/show-user.ts @@ -106,6 +106,7 @@ export const meta = { receiveFollowRequest: { optional: true, ...notificationRecieveConfig }, followRequestAccepted: { optional: true, ...notificationRecieveConfig }, roleAssigned: { optional: true, ...notificationRecieveConfig }, + chatRoomInvitationReceived: { optional: true, ...notificationRecieveConfig }, achievementEarned: { optional: true, ...notificationRecieveConfig }, app: { optional: true, ...notificationRecieveConfig }, test: { optional: true, ...notificationRecieveConfig }, diff --git a/packages/backend/src/server/api/endpoints/i/update.ts b/packages/backend/src/server/api/endpoints/i/update.ts index baf397bf06..082d97f5d4 100644 --- a/packages/backend/src/server/api/endpoints/i/update.ts +++ b/packages/backend/src/server/api/endpoints/i/update.ts @@ -212,6 +212,7 @@ export const paramDef = { receiveFollowRequest: notificationRecieveConfig, followRequestAccepted: notificationRecieveConfig, roleAssigned: notificationRecieveConfig, + chatRoomInvitationReceived: notificationRecieveConfig, achievementEarned: notificationRecieveConfig, app: notificationRecieveConfig, test: notificationRecieveConfig, diff --git a/packages/backend/src/types.ts b/packages/backend/src/types.ts index c6b1035554..4e215c93c6 100644 --- a/packages/backend/src/types.ts +++ b/packages/backend/src/types.ts @@ -15,6 +15,7 @@ * receiveFollowRequest - フォローリクエストされた * followRequestAccepted - 自分の送ったフォローリクエストが承認された * roleAssigned - ロールが付与された + * chatRoomInvitationReceived - チャットルームに招待された * achievementEarned - 実績を獲得 * exportCompleted - エクスポートが完了 * login - ログイン @@ -34,6 +35,7 @@ export const notificationTypes = [ 'receiveFollowRequest', 'followRequestAccepted', 'roleAssigned', + 'chatRoomInvitationReceived', 'achievementEarned', 'exportCompleted', 'login', diff --git a/packages/frontend-shared/js/const.ts b/packages/frontend-shared/js/const.ts index 0241446784..fa60476b69 100644 --- a/packages/frontend-shared/js/const.ts +++ b/packages/frontend-shared/js/const.ts @@ -66,6 +66,7 @@ export const notificationTypes = [ 'receiveFollowRequest', 'followRequestAccepted', 'roleAssigned', + 'chatRoomInvitationReceived', 'achievementEarned', 'exportCompleted', 'login', diff --git a/packages/frontend/src/components/MkNotification.vue b/packages/frontend/src/components/MkNotification.vue index 2824701579..c2e8b8e2fe 100644 --- a/packages/frontend/src/components/MkNotification.vue +++ b/packages/frontend/src/components/MkNotification.vue @@ -43,6 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only + From ed86b1706de715925be2d3a22ae8f68cdc12195b Mon Sep 17 00:00:00 2001 From: Acid Chicken Date: Wed, 26 Mar 2025 12:17:56 +0900 Subject: [PATCH 291/649] ci(storybook): prevent running for bots --- .github/workflows/storybook.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 6608761c13..07f196b7b8 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -5,13 +5,15 @@ on: branches: - master - develop - - dev/storybook8 # for testing pull_request_target: branches-ignore: # Since pull requests targets master mostly is the "develop" branch. # Storybook CI is checked on the "push" event of "develop" branch so it would cause a duplicate build. # This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master. - master + # Neither Dependabot nor Renovate will change the actual behavior for components. + - dependabot/** + - renovate/** jobs: build: From c29a5764d3836bc05906036be20fab2eeea8b85b Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 27 Mar 2025 16:51:08 +0900 Subject: [PATCH 292/649] refactor(backend): better method name --- packages/backend/src/core/QueryService.ts | 4 ++-- packages/backend/src/core/SearchService.ts | 4 ++-- packages/backend/src/server/api/endpoints/antennas/notes.ts | 4 ++-- .../backend/src/server/api/endpoints/channels/timeline.ts | 4 ++-- packages/backend/src/server/api/endpoints/clips/notes.ts | 4 ++-- packages/backend/src/server/api/endpoints/notes/children.ts | 4 ++-- .../backend/src/server/api/endpoints/notes/global-timeline.ts | 4 ++-- .../backend/src/server/api/endpoints/notes/hybrid-timeline.ts | 4 ++-- .../backend/src/server/api/endpoints/notes/local-timeline.ts | 4 ++-- packages/backend/src/server/api/endpoints/notes/mentions.ts | 4 ++-- packages/backend/src/server/api/endpoints/notes/renotes.ts | 4 ++-- packages/backend/src/server/api/endpoints/notes/replies.ts | 4 ++-- .../backend/src/server/api/endpoints/notes/search-by-tag.ts | 4 ++-- packages/backend/src/server/api/endpoints/notes/timeline.ts | 4 ++-- .../src/server/api/endpoints/notes/user-list-timeline.ts | 4 ++-- packages/backend/src/server/api/endpoints/roles/notes.ts | 4 ++-- packages/backend/src/server/api/endpoints/users/notes.ts | 4 ++-- .../backend/src/server/api/endpoints/users/recommendation.ts | 2 +- 18 files changed, 35 insertions(+), 35 deletions(-) diff --git a/packages/backend/src/core/QueryService.ts b/packages/backend/src/core/QueryService.ts index c4feeaf971..412ab33b3f 100644 --- a/packages/backend/src/core/QueryService.ts +++ b/packages/backend/src/core/QueryService.ts @@ -69,7 +69,7 @@ export class QueryService { // ここでいうBlockedは被Blockedの意 @bindThis - public generateBlockedUserQuery(q: SelectQueryBuilder, me: { id: MiUser['id'] }): void { + public generateBlockedUserQueryForNotes(q: SelectQueryBuilder, me: { id: MiUser['id'] }): void { const blockingQuery = this.blockingsRepository.createQueryBuilder('blocking') .select('blocking.blockerId') .where('blocking.blockeeId = :blockeeId', { blockeeId: me.id }); @@ -127,7 +127,7 @@ export class QueryService { } @bindThis - public generateMutedUserQuery(q: SelectQueryBuilder, me: { id: MiUser['id'] }, exclude?: { id: MiUser['id'] }): void { + public generateMutedUserQueryForNotes(q: SelectQueryBuilder, me: { id: MiUser['id'] }, exclude?: { id: MiUser['id'] }): void { const mutingQuery = this.mutingsRepository.createQueryBuilder('muting') .select('muting.muteeId') .where('muting.muterId = :muterId', { muterId: me.id }); diff --git a/packages/backend/src/core/SearchService.ts b/packages/backend/src/core/SearchService.ts index bc62559e46..aa787c93de 100644 --- a/packages/backend/src/core/SearchService.ts +++ b/packages/backend/src/core/SearchService.ts @@ -234,8 +234,8 @@ export class SearchService { } this.queryService.generateVisibilityQuery(query, me); - if (me) this.queryService.generateMutedUserQuery(query, me); - if (me) this.queryService.generateBlockedUserQuery(query, me); + if (me) this.queryService.generateMutedUserQueryForNotes(query, me); + if (me) this.queryService.generateBlockedUserQueryForNotes(query, me); return query.limit(pagination.limit).getMany(); } diff --git a/packages/backend/src/server/api/endpoints/antennas/notes.ts b/packages/backend/src/server/api/endpoints/antennas/notes.ts index 727697ea14..4b8543c2d1 100644 --- a/packages/backend/src/server/api/endpoints/antennas/notes.ts +++ b/packages/backend/src/server/api/endpoints/antennas/notes.ts @@ -109,8 +109,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); const notes = await query.getMany(); if (sinceId != null && untilId == null) { diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts index d4fd75e049..cec5f8fd9c 100644 --- a/packages/backend/src/server/api/endpoints/channels/timeline.ts +++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts @@ -122,8 +122,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('note.channel', 'channel'); if (me) { - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); } //#endregion diff --git a/packages/backend/src/server/api/endpoints/clips/notes.ts b/packages/backend/src/server/api/endpoints/clips/notes.ts index 943c31c894..7638aae442 100644 --- a/packages/backend/src/server/api/endpoints/clips/notes.ts +++ b/packages/backend/src/server/api/endpoints/clips/notes.ts @@ -87,8 +87,8 @@ export default class extends Endpoint { // eslint- if (me) { this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); } const notes = await query diff --git a/packages/backend/src/server/api/endpoints/notes/children.ts b/packages/backend/src/server/api/endpoints/notes/children.ts index 0c6533d336..e73c98282c 100644 --- a/packages/backend/src/server/api/endpoints/notes/children.ts +++ b/packages/backend/src/server/api/endpoints/notes/children.ts @@ -71,8 +71,8 @@ export default class extends Endpoint { // eslint- this.queryService.generateVisibilityQuery(query, me); if (me) { - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); } const notes = await query.limit(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts index 258a0bfb8f..8d38bb1c65 100644 --- a/packages/backend/src/server/api/endpoints/notes/global-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/global-timeline.ts @@ -79,8 +79,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); if (me) { - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); this.queryService.generateMutedUserRenotesQueryForNotes(query, me); } diff --git a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts index aed9065bf9..99d1c9f19c 100644 --- a/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/hybrid-timeline.ts @@ -243,8 +243,8 @@ export default class extends Endpoint { // eslint- } this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); this.queryService.generateMutedUserRenotesQueryForNotes(query, me); if (ps.includeMyRenotes === false) { diff --git a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts index 0b48f2c78b..97acf2ad39 100644 --- a/packages/backend/src/server/api/endpoints/notes/local-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/local-timeline.ts @@ -156,8 +156,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - if (me) this.queryService.generateMutedUserQuery(query, me); - if (me) this.queryService.generateBlockedUserQuery(query, me); + if (me) this.queryService.generateMutedUserQueryForNotes(query, me); + if (me) this.queryService.generateBlockedUserQueryForNotes(query, me); if (me) this.queryService.generateMutedUserRenotesQueryForNotes(query, me); if (ps.withFiles) { diff --git a/packages/backend/src/server/api/endpoints/notes/mentions.ts b/packages/backend/src/server/api/endpoints/notes/mentions.ts index 18a3915ab5..bbb63646e9 100644 --- a/packages/backend/src/server/api/endpoints/notes/mentions.ts +++ b/packages/backend/src/server/api/endpoints/notes/mentions.ts @@ -72,9 +72,9 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); this.queryService.generateMutedNoteThreadQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); if (ps.visibility) { query.andWhere('note.visibility = :visibility', { visibility: ps.visibility }); diff --git a/packages/backend/src/server/api/endpoints/notes/renotes.ts b/packages/backend/src/server/api/endpoints/notes/renotes.ts index ffe1ee6eb8..b34d9261a1 100644 --- a/packages/backend/src/server/api/endpoints/notes/renotes.ts +++ b/packages/backend/src/server/api/endpoints/notes/renotes.ts @@ -72,8 +72,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - if (me) this.queryService.generateMutedUserQuery(query, me); - if (me) this.queryService.generateBlockedUserQuery(query, me); + if (me) this.queryService.generateMutedUserQueryForNotes(query, me); + if (me) this.queryService.generateBlockedUserQueryForNotes(query, me); const renotes = await query.limit(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/notes/replies.ts b/packages/backend/src/server/api/endpoints/notes/replies.ts index 5f32332a6a..f36af1a328 100644 --- a/packages/backend/src/server/api/endpoints/notes/replies.ts +++ b/packages/backend/src/server/api/endpoints/notes/replies.ts @@ -56,8 +56,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - if (me) this.queryService.generateMutedUserQuery(query, me); - if (me) this.queryService.generateBlockedUserQuery(query, me); + if (me) this.queryService.generateMutedUserQueryForNotes(query, me); + if (me) this.queryService.generateBlockedUserQueryForNotes(query, me); const timeline = await query.limit(ps.limit).getMany(); diff --git a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts index 626ff080c7..c45851548a 100644 --- a/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts +++ b/packages/backend/src/server/api/endpoints/notes/search-by-tag.ts @@ -81,8 +81,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - if (me) this.queryService.generateMutedUserQuery(query, me); - if (me) this.queryService.generateBlockedUserQuery(query, me); + if (me) this.queryService.generateMutedUserQueryForNotes(query, me); + if (me) this.queryService.generateBlockedUserQueryForNotes(query, me); try { if (ps.tag) { diff --git a/packages/backend/src/server/api/endpoints/notes/timeline.ts b/packages/backend/src/server/api/endpoints/notes/timeline.ts index 7cb11cc1eb..a88b28892e 100644 --- a/packages/backend/src/server/api/endpoints/notes/timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/timeline.ts @@ -199,8 +199,8 @@ export default class extends Endpoint { // eslint- })); this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); this.queryService.generateMutedUserRenotesQueryForNotes(query, me); if (ps.includeMyRenotes === false) { diff --git a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts index 87f9b322a6..80f1c69b25 100644 --- a/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts +++ b/packages/backend/src/server/api/endpoints/notes/user-list-timeline.ts @@ -184,8 +184,8 @@ export default class extends Endpoint { // eslint- })); this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); this.queryService.generateMutedUserRenotesQueryForNotes(query, me); if (ps.includeMyRenotes === false) { diff --git a/packages/backend/src/server/api/endpoints/roles/notes.ts b/packages/backend/src/server/api/endpoints/roles/notes.ts index 71f2782a5d..6cd9f80929 100644 --- a/packages/backend/src/server/api/endpoints/roles/notes.ts +++ b/packages/backend/src/server/api/endpoints/roles/notes.ts @@ -102,8 +102,8 @@ export default class extends Endpoint { // eslint- .leftJoinAndSelect('renote.user', 'renoteUser'); this.queryService.generateVisibilityQuery(query, me); - this.queryService.generateMutedUserQuery(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); const notes = await query.getMany(); notes.sort((a, b) => a.id > b.id ? -1 : 1); diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts index e9c334057e..f5b7a07b01 100644 --- a/packages/backend/src/server/api/endpoints/users/notes.ts +++ b/packages/backend/src/server/api/endpoints/users/notes.ts @@ -185,8 +185,8 @@ export default class extends Endpoint { // eslint- this.queryService.generateVisibilityQuery(query, me); if (me) { - this.queryService.generateMutedUserQuery(query, me, { id: ps.userId }); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateMutedUserQueryForNotes(query, me, { id: ps.userId }); + this.queryService.generateBlockedUserQueryForNotes(query, me); } if (ps.withFiles) { diff --git a/packages/backend/src/server/api/endpoints/users/recommendation.ts b/packages/backend/src/server/api/endpoints/users/recommendation.ts index 5b3b4527f7..5b1c6b514b 100644 --- a/packages/backend/src/server/api/endpoints/users/recommendation.ts +++ b/packages/backend/src/server/api/endpoints/users/recommendation.ts @@ -63,7 +63,7 @@ export default class extends Endpoint { // eslint- this.queryService.generateMutedUserQueryForUsers(query, me); this.queryService.generateBlockQueryForUsers(query, me); - this.queryService.generateBlockedUserQuery(query, me); + this.queryService.generateBlockedUserQueryForNotes(query, me); const followingQuery = this.followingsRepository.createQueryBuilder('following') .select('following.followeeId') From b95da9c9a46d55c673787ed78526afbc9107785c Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:12:23 +0900 Subject: [PATCH 293/649] =?UTF-8?q?enhance(backend):=20=E3=83=9F=E3=83=A5?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=81=97=E3=81=A6=E3=81=84=E3=82=8B=E3=83=A6?= =?UTF-8?q?=E3=83=BC=E3=82=B6=E3=83=BC=E3=82=92=E3=83=A6=E3=83=BC=E3=82=B6?= =?UTF-8?q?=E3=83=BC=E6=A4=9C=E7=B4=A2=E3=81=AE=E7=B5=90=E6=9E=9C=E3=81=8B?= =?UTF-8?q?=E3=82=89=E9=99=A4=E5=A4=96=E3=81=99=E3=82=8B=E3=82=88=E3=81=86?= =?UTF-8?q?=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 1 + .../backend/src/core/UserSearchService.ts | 100 +++++++++++++++++- .../users/search-by-username-and-host.ts | 2 +- .../src/server/api/endpoints/users/search.ts | 81 ++------------ 4 files changed, 107 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff95b6b5dc..6d94dbe213 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - メッセージにはリアクションも可能です - Enhance: セキュリティを強化するため、ジョブキューのダッシュボード(bull-board)統合が削除されました。 - Misskeyネイティブでダッシュボードを実装予定です +- Enhance: ミュートしているユーザーをユーザー検索の結果から除外するように ### Client - Feat: 設定の管理が強化されました diff --git a/packages/backend/src/core/UserSearchService.ts b/packages/backend/src/core/UserSearchService.ts index 0d03cf6ee0..4be7bd9bdb 100644 --- a/packages/backend/src/core/UserSearchService.ts +++ b/packages/backend/src/core/UserSearchService.ts @@ -6,7 +6,7 @@ import { Inject, Injectable } from '@nestjs/common'; import { Brackets, SelectQueryBuilder } from 'typeorm'; import { DI } from '@/di-symbols.js'; -import { type FollowingsRepository, MiUser, type UsersRepository } from '@/models/_.js'; +import { type FollowingsRepository, MiUser, type MutingsRepository, type UserProfilesRepository, type UsersRepository } from '@/models/_.js'; import { bindThis } from '@/decorators.js'; import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; import type { Config } from '@/config.js'; @@ -22,10 +22,19 @@ export class UserSearchService { constructor( @Inject(DI.config) private config: Config, + @Inject(DI.usersRepository) private usersRepository: UsersRepository, + + @Inject(DI.userProfilesRepository) + private userProfilesRepository: UserProfilesRepository, + @Inject(DI.followingsRepository) private followingsRepository: FollowingsRepository, + + @Inject(DI.mutingsRepository) + private mutingsRepository: MutingsRepository, + private userEntityService: UserEntityService, ) { } @@ -58,7 +67,7 @@ export class UserSearchService { * @see {@link UserSearchService#buildSearchUserNoLoginQueries} */ @bindThis - public async search( + public async searchByUsernameAndHost( params: { username?: string | null, host?: string | null, @@ -202,4 +211,91 @@ export class UserSearchService { return userQuery; } + + @bindThis + public async search(query: string, meId: MiUser['id'] | null, options: Partial<{ + limit: number; + offset: number; + origin: 'local' | 'remote' | 'combined'; + }> = {}) { + const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 + + const isUsername = query.startsWith('@') && !query.includes(' ') && query.indexOf('@', 1) === -1; + + let users: MiUser[] = []; + + const mutingQuery = meId == null ? null : this.mutingsRepository.createQueryBuilder('muting') + .select('muting.muteeId') + .where('muting.muterId = :muterId', { muterId: meId }); + + const nameQuery = this.usersRepository.createQueryBuilder('user') + .where(new Brackets(qb => { + qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(query) + '%' }); + + if (isUsername) { + qb.orWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(query.replace('@', '').toLowerCase()) + '%' }); + } else if (this.userEntityService.validateLocalUsername(query)) { // Also search username if it qualifies as username + qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(query.toLowerCase()) + '%' }); + } + })) + .andWhere(new Brackets(qb => { + qb + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); + })) + .andWhere('user.isSuspended = FALSE'); + + if (mutingQuery) { + nameQuery.andWhere(`user.id NOT IN (${mutingQuery.getQuery()})`); + nameQuery.setParameters(mutingQuery.getParameters()); + } + + if (options.origin === 'local') { + nameQuery.andWhere('user.host IS NULL'); + } else if (options.origin === 'remote') { + nameQuery.andWhere('user.host IS NOT NULL'); + } + + users = await nameQuery + .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') + .limit(options.limit) + .offset(options.offset) + .getMany(); + + if (users.length < (options.limit ?? 30)) { + const profQuery = this.userProfilesRepository.createQueryBuilder('prof') + .select('prof.userId') + .where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(query) + '%' }); + + if (mutingQuery) { + profQuery.andWhere(`prof.userId NOT IN (${mutingQuery.getQuery()})`); + profQuery.setParameters(mutingQuery.getParameters()); + } + + if (options.origin === 'local') { + profQuery.andWhere('prof.userHost IS NULL'); + } else if (options.origin === 'remote') { + profQuery.andWhere('prof.userHost IS NOT NULL'); + } + + const userQuery = this.usersRepository.createQueryBuilder('user') + .where(`user.id IN (${ profQuery.getQuery() })`) + .andWhere(new Brackets(qb => { + qb + .where('user.updatedAt IS NULL') + .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); + })) + .andWhere('user.isSuspended = FALSE') + .setParameters(profQuery.getParameters()); + + users = users.concat(await userQuery + .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') + .limit(options.limit) + .offset(options.offset) + .getMany(), + ); + } + + return users; + } } diff --git a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts index 8ff952dcb5..134f1a8e87 100644 --- a/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts +++ b/packages/backend/src/server/api/endpoints/users/search-by-username-and-host.ts @@ -46,7 +46,7 @@ export default class extends Endpoint { // eslint- private userSearchService: UserSearchService, ) { super(meta, paramDef, (ps, me) => { - return this.userSearchService.search({ + return this.userSearchService.searchByUsernameAndHost({ username: ps.username, host: ps.host, }, { diff --git a/packages/backend/src/server/api/endpoints/users/search.ts b/packages/backend/src/server/api/endpoints/users/search.ts index 0b0136066d..5d36847e03 100644 --- a/packages/backend/src/server/api/endpoints/users/search.ts +++ b/packages/backend/src/server/api/endpoints/users/search.ts @@ -3,14 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { Brackets } from 'typeorm'; import { Inject, Injectable } from '@nestjs/common'; -import type { UsersRepository, UserProfilesRepository } from '@/models/_.js'; -import type { MiUser } from '@/models/User.js'; import { Endpoint } from '@/server/api/endpoint-base.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DI } from '@/di-symbols.js'; -import { sqlLikeEscape } from '@/misc/sql-like-escape.js'; +import { UserSearchService } from '@/core/UserSearchService.js'; export const meta = { tags: ['users'], @@ -45,79 +42,15 @@ export const paramDef = { @Injectable() export default class extends Endpoint { // eslint-disable-line import/no-default-export constructor( - @Inject(DI.usersRepository) - private usersRepository: UsersRepository, - - @Inject(DI.userProfilesRepository) - private userProfilesRepository: UserProfilesRepository, - private userEntityService: UserEntityService, + private userSearchService: UserSearchService, ) { super(meta, paramDef, async (ps, me) => { - const activeThreshold = new Date(Date.now() - (1000 * 60 * 60 * 24 * 30)); // 30日 - - ps.query = ps.query.trim(); - const isUsername = ps.query.startsWith('@') && !ps.query.includes(' ') && ps.query.indexOf('@', 1) === -1; - - let users: MiUser[] = []; - - const nameQuery = this.usersRepository.createQueryBuilder('user') - .where(new Brackets(qb => { - qb.where('user.name ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' }); - - if (isUsername) { - qb.orWhere('user.usernameLower LIKE :username', { username: sqlLikeEscape(ps.query.replace('@', '').toLowerCase()) + '%' }); - } else if (this.userEntityService.validateLocalUsername(ps.query)) { // Also search username if it qualifies as username - qb.orWhere('user.usernameLower LIKE :username', { username: '%' + sqlLikeEscape(ps.query.toLowerCase()) + '%' }); - } - })) - .andWhere(new Brackets(qb => { - qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE'); - - if (ps.origin === 'local') { - nameQuery.andWhere('user.host IS NULL'); - } else if (ps.origin === 'remote') { - nameQuery.andWhere('user.host IS NOT NULL'); - } - - users = await nameQuery - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .limit(ps.limit) - .offset(ps.offset) - .getMany(); - - if (users.length < ps.limit) { - const profQuery = this.userProfilesRepository.createQueryBuilder('prof') - .select('prof.userId') - .where('prof.description ILIKE :query', { query: '%' + sqlLikeEscape(ps.query) + '%' }); - - if (ps.origin === 'local') { - profQuery.andWhere('prof.userHost IS NULL'); - } else if (ps.origin === 'remote') { - profQuery.andWhere('prof.userHost IS NOT NULL'); - } - - const query = this.usersRepository.createQueryBuilder('user') - .where(`user.id IN (${ profQuery.getQuery() })`) - .andWhere(new Brackets(qb => { - qb - .where('user.updatedAt IS NULL') - .orWhere('user.updatedAt > :activeThreshold', { activeThreshold: activeThreshold }); - })) - .andWhere('user.isSuspended = FALSE') - .setParameters(profQuery.getParameters()); - - users = users.concat(await query - .orderBy('user.updatedAt', 'DESC', 'NULLS LAST') - .limit(ps.limit) - .offset(ps.offset) - .getMany(), - ); - } + const users = await this.userSearchService.search(ps.query.trim(), me?.id ?? null, { + offset: ps.offset, + limit: ps.limit, + origin: ps.origin, + }); return await this.userEntityService.packMany(users, me, { schema: ps.detail ? 'UserDetailed' : 'UserLite' }); }); From f7e901deb2a3d7457231c9a240d13d332e24461a Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:30:04 +0900 Subject: [PATCH 294/649] test fixes --- .../backend/test/unit/UserSearchService.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/backend/test/unit/UserSearchService.ts b/packages/backend/test/unit/UserSearchService.ts index 66a7f39ff1..697425beb8 100644 --- a/packages/backend/test/unit/UserSearchService.ts +++ b/packages/backend/test/unit/UserSearchService.ts @@ -134,13 +134,13 @@ describe('UserSearchService', () => { await app.close(); }); - describe('search', () => { + describe('searchByUsernameAndHost', () => { test('フォロー中のアクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); await setActive([alice, alyce, alyssa, bob, bobbi, bobbie, bobby]); await setInactive([alycia, alysha, alyson]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, root, @@ -154,7 +154,7 @@ describe('UserSearchService', () => { await createFollowings(root, [alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, root, @@ -168,7 +168,7 @@ describe('UserSearchService', () => { await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); await setInactive([alice, alyce, alycia]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, root, @@ -181,7 +181,7 @@ describe('UserSearchService', () => { test('フォローしていない非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, root, @@ -195,7 +195,7 @@ describe('UserSearchService', () => { await setActive([root, alyssa, bob, bobbi, alyce, alycia]); await setInactive([alyson, alice, alysha, bobbie, bobby]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { }, { limit: 100 }, root, @@ -216,7 +216,7 @@ describe('UserSearchService', () => { await setActive([alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); await setInactive([alice, alyce, alycia]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, ); @@ -228,7 +228,7 @@ describe('UserSearchService', () => { test('[非ログイン] 非アクティブユーザのうち、"al"から始まる人が全員ヒットする', async () => { await setInactive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, ); @@ -240,7 +240,7 @@ describe('UserSearchService', () => { await createFollowings(root, [alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al', host: 'exam' }, { limit: 100 }, root, @@ -253,7 +253,7 @@ describe('UserSearchService', () => { await setActive([alice, alyce, alycia, alysha, alyson, alyssa, bob, bobbi, bobbie, bobby]); await setSuspended([alice, alyce, alycia]); - const result = await service.search( + const result = await service.searchByUsernameAndHost( { username: 'al' }, { limit: 100 }, root, From a78db27a3ca4e2125b217bdef4a0920d33029423 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 27 Mar 2025 17:30:06 +0900 Subject: [PATCH 295/649] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d94dbe213..ff77553206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,7 @@ - 投稿フォームをリセットできるように - 文字数カウントを復活 - Enhance: 2段階認証時のリカバリーコードのファイル名にサーバーURLを含めるように +- Enhance: 全体的なブラッシュアップ - Fix: テーマ切り替え時に一部の色が変わらない問題を修正 ### Server From e40846c46bdcbb8be0c15ac7e874e8ec2291f519 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Thu, 27 Mar 2025 19:50:03 +0900 Subject: [PATCH 296/649] fix e2e test --- packages/backend/test/e2e/users.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/test/e2e/users.ts b/packages/backend/test/e2e/users.ts index f82d4c6a30..e04d258c0d 100644 --- a/packages/backend/test/e2e/users.ts +++ b/packages/backend/test/e2e/users.ts @@ -732,7 +732,7 @@ describe('ユーザー', () => { }); test.each([ { label: '「見つけやすくする」がOFFのユーザーが含まれる', user: () => userNotExplorable }, - { label: 'ミュートユーザーが含まれる', user: () => userMutedByAlice }, + { label: 'ミュートユーザーが含まれない', user: () => userMutedByAlice, excluded: true }, { label: 'ブロックされているユーザーが含まれる', user: () => userBlockedByAlice }, { label: 'ブロックしてきているユーザーが含まれる', user: () => userBlockingAlice }, { label: '承認制ユーザーが含まれる', user: () => userLocking }, From 61e09d483e35b6d464a04a2d04633fd6b878b475 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Fri, 28 Mar 2025 09:22:37 +0900 Subject: [PATCH 297/649] refactor --- .../src/components/global/MkPageHeader.vue | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index d5680b8413..6a926f7718 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index a1e1460da1..4ed4cdc773 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -122,11 +122,6 @@ const menuDef = computed(() => [{ text: i18n.ts.sounds, to: '/settings/sounds', active: currentPage.value?.route.name === 'sounds', - }, { - icon: 'ti ti-accessible', - text: i18n.ts.accessibility, - to: '/settings/accessibility', - active: currentPage.value?.route.name === 'accessibility', }, { icon: 'ti ti-plug', text: i18n.ts.plugins, diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index 7e7ed21dd5..a4e9616325 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -418,6 +418,116 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + +
+ + {{ i18n.ts._settings.accessibilityBanner }} + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ @@ -671,6 +781,18 @@ const defaultFollowWithReplies = prefer.model('defaultFollowWithReplies'); const chatShowSenderName = prefer.model('chat.showSenderName'); const chatSendOnEnter = prefer.model('chat.sendOnEnter'); const useStickyIcons = prefer.model('useStickyIcons'); +const reduceAnimation = prefer.model('animation', v => !v, v => !v); +const animatedMfm = prefer.model('animatedMfm'); +const disableShowingAnimatedImages = prefer.model('disableShowingAnimatedImages'); +const keepScreenOn = prefer.model('keepScreenOn'); +const enableHorizontalSwipe = prefer.model('enableHorizontalSwipe'); +const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPlayer'); +const contextMenu = prefer.model('contextMenu'); +const menuStyle = prefer.model('menuStyle'); +const makeEveryTextElementsSelectable = prefer.model('makeEveryTextElementsSelectable'); + +const fontSize = ref(miLocalStorage.getItem('fontSize')); +const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); watch(lang, () => { miLocalStorage.setItem('lang', lang.value as string); @@ -678,6 +800,22 @@ watch(lang, () => { miLocalStorage.removeItem('localeVersion'); }); +watch(fontSize, () => { + if (fontSize.value == null) { + miLocalStorage.removeItem('fontSize'); + } else { + miLocalStorage.setItem('fontSize', fontSize.value); + } +}); + +watch(useSystemFont, () => { + if (useSystemFont.value) { + miLocalStorage.setItem('useSystemFont', 't'); + } else { + miLocalStorage.removeItem('useSystemFont'); + } +}); + watch([ hemisphere, lang, @@ -700,6 +838,11 @@ watch([ enableSeasonalScreenEffect, chatShowSenderName, useStickyIcons, + keepScreenOn, + contextMenu, + fontSize, + useSystemFont, + makeEveryTextElementsSelectable, ], async () => { await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true }); }); diff --git a/packages/frontend/src/router.definition.ts b/packages/frontend/src/router.definition.ts index 0585a31fd1..23118160e2 100644 --- a/packages/frontend/src/router.definition.ts +++ b/packages/frontend/src/router.definition.ts @@ -128,10 +128,6 @@ export const ROUTE_DEF = [{ path: '/sounds', name: 'sounds', component: page(() => import('@/pages/settings/sounds.vue')), - }, { - path: '/accessibility', - name: 'accessibility', - component: page(() => import('@/pages/settings/accessibility.vue')), }, { path: '/plugin/install', name: 'plugin', diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts index 9e1f41e3c7..b77957fe84 100644 --- a/packages/frontend/src/utility/autogen/settings-search-index.ts +++ b/packages/frontend/src/utility/autogen/settings-search-index.ts @@ -489,17 +489,79 @@ export const searchIndexes: SearchIndexItem[] = [ id: '96LnS1sxB', children: [ { - id: '5h8vhCX1S', + id: 'vPQPvmntL', + label: i18n.ts.reduceUiAnimation, + keywords: ['animation', 'motion', 'reduce'], + }, + { + id: 'wfJ91vwzq', + label: i18n.ts.disableShowingAnimatedImages, + keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'], + }, + { + id: '42b1L4xdq', + label: i18n.ts.enableAnimatedMfm, + keywords: ['mfm', 'enable', 'show', 'animated'], + }, + { + id: 'dLkRNHn3k', + label: i18n.ts.enableHorizontalSwipe, + keywords: ['swipe', 'horizontal', 'tab'], + }, + { + id: 'BvooTWFW5', + label: i18n.ts.keepScreenOn, + keywords: ['keep', 'screen', 'display', 'on'], + }, + { + id: 'yzbghkAq0', + label: i18n.ts.useNativeUIForVideoAudioPlayer, + keywords: ['native', 'system', 'video', 'audio', 'player', 'media'], + }, + { + id: 'aSbKFHbOy', + label: i18n.ts._settings.makeEveryTextElementsSelectable, + keywords: ['text', 'selectable'], + }, + { + id: 'bTcAsPvNz', + label: i18n.ts.menuStyle, + keywords: ['menu', 'style', 'popup', 'drawer'], + }, + { + id: 'lSVBaLnyW', + label: i18n.ts._contextMenu.title, + keywords: ['contextmenu', 'system', 'native'], + }, + { + id: 'pec0uMPq5', + label: i18n.ts.fontSize, + keywords: ['font', 'size'], + }, + { + id: 'Eh7vTluDO', + label: i18n.ts.useSystemFont, + keywords: ['font', 'system', 'native'], + }, + ], + label: i18n.ts.accessibility, + keywords: ['accessibility', i18n.ts._settings.accessibilityBanner], + }, + { + id: 'vTRSKf1JA', + children: [ + { + id: '2VjlA02wB', label: i18n.ts.turnOffToImprovePerformance, keywords: ['blur'], }, { - id: 'Cbjosj3TG', + id: 'f6J0lmg1g', label: i18n.ts.turnOffToImprovePerformance, keywords: ['blur', 'modal'], }, { - id: 'BKndoHcCj', + id: 'hQqXhfNg8', label: i18n.ts.turnOffToImprovePerformance, keywords: ['sticky'], }, @@ -508,55 +570,55 @@ export const searchIndexes: SearchIndexItem[] = [ keywords: ['performance'], }, { - id: '4yCgcFElF', + id: 'utM8dEobb', label: i18n.ts.dataSaver, keywords: ['datasaver'], }, { - id: 'DILm2LlCn', + id: 'gOUvwkE9t', children: [ { - id: 'Fd0rFTSry', + id: 'iUMUvFURf', label: i18n.ts.squareAvatars, keywords: ['avatar', 'icon', 'square'], }, { - id: 'xNsLokqeA', + id: 'ceyPO9Ywi', label: i18n.ts.seasonalScreenEffect, keywords: ['effect', 'show'], }, { - id: 'sZcalFBE8', + id: 'ztwIlsXhP', label: i18n.ts.openImageInNewTab, keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'], }, { - id: 'Eh7vTluDO', + id: 'vLSsQbZEo', label: i18n.ts.withRepliesByDefaultForNewlyFollowed, keywords: ['follow', 'replies'], }, { - id: 'vTRSKf1JA', + id: 'hQt85bBIX', label: i18n.ts.whenServerDisconnected, keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'], }, { - id: 'zlO5cBZFH', + id: 'C9SyK2m0', label: i18n.ts.numberOfPageCache, keywords: ['cache', 'page'], }, { - id: 'huQ8nc4iD', + id: '2U0iVUtfW', label: i18n.ts.forceShowAds, keywords: ['ad', 'show'], }, { - id: 'nJWfqwQ4R', + id: '1rA7ADEXY', label: i18n.ts.hemisphere, keywords: [], }, { - id: 'kwEEgTlwR', + id: 'vRayx89Rt', label: i18n.ts.additionalEmojiDictionary, keywords: ['emoji', 'dictionary', 'additional', 'extra'], }, @@ -906,70 +968,6 @@ export const searchIndexes: SearchIndexItem[] = [ path: '/settings/account-data', icon: 'ti ti-package', }, - { - id: 'f08Mi1Uwn', - children: [ - { - id: 'C5dRH2Ypy', - label: i18n.ts.reduceUiAnimation, - keywords: ['animation', 'motion', 'reduce'], - }, - { - id: '5mZxz2cru', - label: i18n.ts.disableShowingAnimatedImages, - keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'], - }, - { - id: 'c0Iy5hL5o', - label: i18n.ts.enableAnimatedMfm, - keywords: ['mfm', 'enable', 'show', 'animated'], - }, - { - id: '4HYFjs2Nv', - label: i18n.ts.enableHorizontalSwipe, - keywords: ['swipe', 'horizontal', 'tab'], - }, - { - id: 'kYVJ3SVNq', - label: i18n.ts.keepScreenOn, - keywords: ['keep', 'screen', 'display', 'on'], - }, - { - id: 'w4Bv0meAt', - label: i18n.ts.useNativeUIForVideoAudioPlayer, - keywords: ['native', 'system', 'video', 'audio', 'player', 'media'], - }, - { - id: 'b1GYEEJeh', - label: i18n.ts._settings.makeEveryTextElementsSelectable, - keywords: ['text', 'selectable'], - }, - { - id: 'vVLxwINTJ', - label: i18n.ts.menuStyle, - keywords: ['menu', 'style', 'popup', 'drawer'], - }, - { - id: '14cMhMLHL', - label: i18n.ts._contextMenu.title, - keywords: ['contextmenu', 'system', 'native'], - }, - { - id: 'oSo4LXMX9', - label: i18n.ts.fontSize, - keywords: ['font', 'size'], - }, - { - id: '7LQSAThST', - label: i18n.ts.useSystemFont, - keywords: ['font', 'system', 'native'], - }, - ], - label: i18n.ts.accessibility, - keywords: ['accessibility', i18n.ts._settings.accessibilityBanner], - path: '/settings/accessibility', - icon: 'ti ti-accessible', - }, ] as const; export type SearchIndex = typeof searchIndexes; From c06d0b9b42f426078b549354476606c3f4d33b93 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 11:27:35 +0900 Subject: [PATCH 350/649] enhance(frontend): organize settings page --- .../src/pages/settings/preferences.vue | 18 +++++++-------- .../utility/autogen/settings-search-index.ts | 22 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue index a4e9616325..86ae8af213 100644 --- a/packages/frontend/src/pages/settings/preferences.vue +++ b/packages/frontend/src/pages/settings/preferences.vue @@ -104,15 +104,6 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - - - - {{ i18n.ts.add }} - {{ i18n.ts.remove }} - -
@@ -164,6 +155,15 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + {{ i18n.ts.add }} + {{ i18n.ts.remove }} + +

diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts index b77957fe84..df621beb7d 100644 --- a/packages/frontend/src/utility/autogen/settings-search-index.ts +++ b/packages/frontend/src/utility/autogen/settings-search-index.ts @@ -323,43 +323,43 @@ export const searchIndexes: SearchIndexItem[] = [ label: i18n.ts.emojiStyle, keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'], }, - { - id: 'wo0s0CaI1', - label: i18n.ts.pinnedList, - keywords: ['pinned', 'list'], - }, ], label: i18n.ts.general, keywords: ['general'], }, { - id: 'l78F2W9Ok', + id: '5G6O6qdis', children: [ { - id: 'iOJ3Crlky', + id: 'khT3n6byY', label: i18n.ts.showFixedPostForm, keywords: ['post', 'form', 'timeline'], }, { - id: 'CQldliCSi', + id: 'q5ElfNSou', label: i18n.ts.showFixedPostFormInChannel, keywords: ['post', 'form', 'timeline', 'channel'], }, { - id: 'd2H4E5ys6', + id: '3GcWIaZf8', label: i18n.ts.collapseRenotes, keywords: ['renote', i18n.ts.collapseRenotesDescription], }, { - id: 'yb11lSY1G', + id: 'd2H4E5ys6', label: i18n.ts.showGapBetweenNotesInTimeline, keywords: ['note', 'timeline', 'gap'], }, { - id: 'fL49Zxe9i', + id: '1LHOhDKGW', label: i18n.ts.disableStreamingTimeline, keywords: ['disable', 'streaming', 'timeline'], }, + { + id: 'DSzwvTp7i', + label: i18n.ts.pinnedList, + keywords: ['pinned', 'list'], + }, { id: 'ykifk3NHS', label: i18n.ts.showNoteActionsOnlyHover, From 88c743aa3386049f2b2de1afe7fb5c125e0581f1 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 11:45:41 +0900 Subject: [PATCH 351/649] chore(frontend): remove unused style --- packages/frontend/src/components/MkNote.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 8840a6a8bf..66a70c9be3 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -658,7 +658,6 @@ function emitUpdReaction(emoji: string, delta: number) { diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue deleted file mode 100644 index 43d24da28b..0000000000 --- a/packages/frontend/src/ui/classic.sidebar.vue +++ /dev/null @@ -1,245 +0,0 @@ - - - - - - - diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue deleted file mode 100644 index c984cde342..0000000000 --- a/packages/frontend/src/ui/classic.vue +++ /dev/null @@ -1,326 +0,0 @@ - - - - - - - From 17f3113b92a4ff79b4f7588663c7f08ae955325d Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:30:04 +0900 Subject: [PATCH 355/649] =?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/MkPostForm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 78c69306b0..e43ff65e1d 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -1314,7 +1314,7 @@ html[data-color-scheme=light] .preview { padding: 0 24px; margin: 0; width: 100%; - font-size: 16px; + font-size: 110%; border: none; border-radius: 0; background: transparent; From 0655c8a29bb6122cdda7235720a1ef220bb0a293 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:33:52 +0900 Subject: [PATCH 356/649] clean up --- packages/frontend/src/pages/settings/navbar.vue | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/frontend/src/pages/settings/navbar.vue b/packages/frontend/src/pages/settings/navbar.vue index f944490a66..91968c5300 100644 --- a/packages/frontend/src/pages/settings/navbar.vue +++ b/packages/frontend/src/pages/settings/navbar.vue @@ -40,8 +40,6 @@ SPDX-License-Identifier: AGPL-3.0-only - - From 303b62aff3c01cd0945ccef2e0fea17dbd27da40 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 14:34:32 +0900 Subject: [PATCH 357/649] New Crowdin updates (#15721) * New translations ja-jp.yml (German) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (German) * New translations ja-jp.yml (German) * New translations ja-jp.yml (German) * New translations ja-jp.yml (German) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (English) --- locales/ca-ES.yml | 1 + locales/de-DE.yml | 183 +++++++++++++++++++++++++++++++++++++++++++++- locales/en-US.yml | 1 + locales/zh-CN.yml | 1 + locales/zh-TW.yml | 1 + 5 files changed, 186 insertions(+), 1 deletion(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index b371a6b025..fde5b2aad9 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -1406,6 +1406,7 @@ _settings: timelineAndNote: "Línia de temps i nota" makeEveryTextElementsSelectable: "Fes que tots els elements del text siguin seleccionables" makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions." + useStickyIcons: "Utilitza icones fixes" showNavbarSubButtons: "Mostrar sub botons a la barra de navegació " ifOn: "Quan s'encén " ifOff: "Quan s'apaga " diff --git a/locales/de-DE.yml b/locales/de-DE.yml index b32f4512be..ee0a97098c 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -301,6 +301,7 @@ uploadFromUrlMayTakeTime: "Es kann eine Weile dauern, bis das Hochladen abgeschl explore: "Erkunden" messageRead: "Gelesen" noMoreHistory: "Kein weiterer Verlauf vorhanden" +startChat: "Chat starten" nUsersRead: "Von {n} Benutzern gelesen" agreeTo: "Ich stimme {0} zu" agree: "Zustimmen" @@ -1256,7 +1257,7 @@ replaying: "Aufzeichnung" endReplay: "Aufzeichnung verlassen" copyReplayData: "Aufzeichnung kopieren" ranking: "Rangliste" -lastNDays: "Letzten {n} Tage" +lastNDays: "Letzte {n} Tage" backToTitle: "Zurück zum Startbildschirm" hemisphere: "Hemisphäre" withSensitive: "Zeige \"sensitive Inhalte\" an" @@ -1318,25 +1319,93 @@ noName: "Kein Name" skip: "Überspringen" restore: "Wiederherstellen" syncBetweenDevices: "Zwischen Geräten synchronisieren" +preferenceSyncConflictTitle: "Der konfigurierte Wert ist auf dem Server bereits vorhanden." +preferenceSyncConflictText: "Die Einstellungen mit aktivierter Synchronisierung werden ihre Werte auf dem Server speichern. Es gibt jedoch bereits Werte auf dem Server. Welche Einstellungswerte sollen überschrieben werden?" +preferenceSyncConflictChoiceServer: "Konfigurierte Werte auf dem Server" +preferenceSyncConflictChoiceDevice: "Konfigurierte Werte auf dem Gerät" +preferenceSyncConflictChoiceCancel: "Einrichten der Synchronisierung abbrechen" paste: "Einfügen" +emojiPalette: "Emoji-Palette" postForm: "Notizfenster" textCount: "Zeichenanzahl" information: "Über" +chat: "Chat" +migrateOldSettings: "Alte Client-Einstellungen migrieren" +migrateOldSettings_description: "Dies sollte normalerweise automatisch geschehen, aber wenn die Migration aus irgendeinem Grund nicht erfolgreich war, kannst du den Migrationsprozess selbst manuell auslösen. Die aktuellen Konfigurationsinformationen werden dabei überschrieben." +compress: "Komprimieren" _chat: + noMessagesYet: "Noch keine Nachrichten" + newMessage: "Neue Nachricht" + individualChat: "Privater Chat" + individualChat_description: "Führe einen privaten Chat mit einer anderen Person." + roomChat_description: "Ein Chat-Raum, an dem mehrere Personen teilnehmen können.\nDu kannst auch Personen einladen, die keine privaten Chats zulassen, wenn sie die Einladung annehmen." + createRoom: "Raum erstellen" + inviteUserToChat: "Lade Benutzer ein, um mit dem Chatten zu beginnen" + yourRooms: "Erstellte Räume" invitations: "Einladen" + noInvitations: "Keine Einladungen" + history: "Verlauf" noHistory: "Kein Verlauf gefunden" + noRooms: "Keine Räume gefunden" + inviteUser: "Benutzer einladen" + sentInvitations: "Verschickte Einladungen" + join: "Beitreten" + ignore: "Ignorieren" + leave: "Raum verlassen" members: "Mitglieder" + searchMessages: "Nachrichten suchen" home: "Startseite" send: "Senden" + newline: "Neue Zeile" + muteThisRoom: "Raum stummschalten" + deleteRoom: "Raum löschen" + chatNotAvailableForThisAccountOrServer: "Der Chat ist auf diesem Server oder für dieses Konto nicht aktiviert." + chatNotAvailableInOtherAccount: "Die Chatfunktion wurde vom anderen Benutzer deaktiviert." + cannotChatWithTheUser: "Starten eines Chats mit diesem Benutzer nicht möglich" + cannotChatWithTheUser_description: "Der Chat ist entweder nicht verfügbar oder die andere Seite hat den Chat nicht aktiviert." + chatWithThisUser: "Mit dem Benutzer chatten" + thisUserAllowsChatOnlyFromFollowers: "Dieser Benutzer nimmt nur Chats von Followern an." + thisUserAllowsChatOnlyFromFollowing: "Dieser Benutzer nimmt nur Chats von Benutzern an, denen er folgt." + thisUserAllowsChatOnlyFromMutualFollowing: "Dieser Benutzer akzeptiert nur Chats von Benutzern, die sich gegenseitig folgen." + thisUserNotAllowedChatAnyone: "Dieser Benutzer nimmt keine Chats von anderen Benutzern an." + chatAllowedUsers: "Wem das Chatten erlaubt werden soll" + chatAllowedUsers_note: "Du kannst unabhängig von dieser Einstellung mit allen Personen chatten, denen du eine Chat-Nachricht gesendet hast." + _chatAllowedUsers: + everyone: "Jeder" + followers: "Nur deine Follower" + following: "Nur Benutzer, denen du folgst" + mutual: "Nur Benutzer, die sich gegenseitig folgen" + none: "Niemand" _emojiPalette: palettes: "Palette" enableSyncBetweenDevicesForPalettes: "Synchronisierung der Paletten zwischen Geräten aktivieren" paletteForMain: "Hauptpalette" + paletteForReaction: "Reaktions-Palette" _settings: + driveBanner: "Du kannst den Drive verwalten und konfigurieren, die Auslastung überprüfen und Einstellungen für das Hochladen von Dateien vornehmen." + pluginBanner: "Du kannst die Funktionen des Clients mit Plugins erweitern. Plugins können installiert, individuell konfiguriert und verwaltet werden." api: "API" webhook: "Webhook" + serviceConnectionBanner: "Du kannst Zugriffstoken und Webhooks für die Integration mit externen Anwendungen und Diensten verwalten und konfigurieren." accountData: "Kontodaten" + accountDataBanner: "Export/Import und Verwaltung von Kontodatenarchiven." + muteAndBlockBanner: "Du kannst Einstellungen konfigurieren und verwalten, um Inhalte auszublenden und Aktionen für bestimmte Benutzer zu beschränken." + accessibilityBanner: "Die Clients können personalisiert und für eine optimale Nutzung im Hinblick auf ihre Darstellung und ihr Verhalten eingerichtet werden." + privacyBanner: "Du kannst Einstellungen für die Privatsphäre deines Kontos vornehmen, z. B. inwieweit Inhalte veröffentlicht werden, wie leicht sie zu finden sind und ob Follower genehmigt werden müssen." + securityBanner: "Du kannst Einstellungen für die Kontosicherheit konfigurieren, z. B. Passwörter, Anmeldemethoden, Authentifizierungs-Apps und Passkeys." + appearanceBanner: "Du kannst das Erscheinungsbild und die Anzeigeeinstellungen für den Client nach deinen Wünschen konfigurieren." + soundsBanner: "Du kannst die Einstellungen für die Wiedergabe von Klängen im Client konfigurieren." + timelineAndNote: "Chroniken und Notizen" + makeEveryTextElementsSelectable: "Alle Textelemente auswählbar machen" + makeEveryTextElementsSelectable_description: "Die Aktivierung kann in manchen Situationen die Benutzerfreundlichkeit beeinträchtigen." + ifOn: "Wenn eingeschaltet" + ifOff: "Wenn ausgeschaltet" + _chat: + showSenderName: "Name des Absenders anzeigen" + sendOnEnter: "Eingabetaste sendet Nachricht" _preferencesProfile: + profileName: "Profilname" + profileNameDescription: "Lege einen Namen fest, der dieses Gerät identifiziert." profileNameDescription2: "Beispiel: \"Haupt-PC\", \"Smartphone\"" _preferencesBackup: autoBackup: "Automatische Sicherung" @@ -1353,9 +1422,11 @@ _accountSettings: requireSigninToViewContentsDescription2: "Der Inhalt wird nicht in URL-Vorschauen (OGP), eingebettet in Webseiten oder auf Servern, die keine Zitate unterstützen, angezeigt." requireSigninToViewContentsDescription3: "Diese Einschränkungen gelten möglicherweise nicht für föderierte Inhalte von anderen Servern." makeNotesFollowersOnlyBefore: "Macht frühere Notizen nur für Follower sichtbar" + makeNotesFollowersOnlyBeforeDescription: "Solange diese Funktion aktiviert ist, sind Notizen, die nach dem eingestellten Datum und der eingestellten Zeit liegen oder die eingestellte Zeit abgelaufen ist, nur für Follower sichtbar. Bei Deaktivierung wird auch der öffentliche Status der Notiz wiederhergestellt." makeNotesHiddenBefore: "Frühere Notizen privat machen" makeNotesHiddenBeforeDescription: "" mayNotEffectForFederatedNotes: "Dies hat möglicherweise keine Auswirkungen auf Notizen, die an andere Server föderiert werden." + mayNotEffectSomeSituations: "Diese Einschränkungen sind vereinfacht. Sie gelten möglicherweise nicht in allen Situationen, z. B. bei der Anzeige auf einem fremden Server oder während der Moderation." notesOlderThanSpecifiedDateAndTime: "Notizen vor einem bestimmtem Datum und Uhrzeit" _abuseUserReport: forward: "Weiterleiten" @@ -1363,11 +1434,15 @@ _abuseUserReport: resolve: "lösen" accept: "Akzeptieren" reject: "Ablehnen" + resolveTutorial: "Wenn der Inhalt der Meldung rechtmäßig ist, wähle „Akzeptieren“, um sie als gelöst zu markieren.\nWenn der Inhalt der Meldung unzulässig ist, wähle „Ablehnen“, um sie zu ignorieren." _delivery: + status: "Auslieferungsstatus" stop: "Gesperrt" _type: none: "Wird veröffentlicht" manuallySuspended: "Manuell gesperrt" + goneSuspended: "Gesperrt wegen Löschung des Servers" + autoSuspendedForNotResponding: "Gesperrt, weil der Server nicht antwortet" _bubbleGame: howToPlay: "Wie man spielt" hold: "Halten" @@ -1377,6 +1452,8 @@ _bubbleGame: highScore: "Höchstpunktzahl" maxChain: "Maximale Anzahl an Verkettungen" yen: "{yen} Yen" + estimatedQty: "{qty} Stück" + scoreSweets: "{onigiriQtyWithUnit} Onigiri" _howToPlay: section1: "Passe die Position an und lasse das Objekt in das Spielfeld fallen." section2: "Wenn sich zwei Objekte der gleichen Art berühren, verwandeln sie sich in ein anderes Objekt und du bekommst Punkte." @@ -1434,15 +1511,20 @@ _initialTutorial: reactDone: "Du kannst eine Reaktion zurücknehmen, indem du auf den '-' Button drückst." _timeline: title: "So funktionieren die Chroniken" + description1: "Misskey stellt mehrere Chroniken bereit (einige können je nach den Richtlinien des Servers nicht verfügbar sein)." home: "Du kannst Beiträge von den Konten sehen, denen du folgst." local: "Du kannst Beiträge aller Benutzer auf diesem Server sehen." social: "Notizen von der Startseite und der lokalen Chronik werden angezeigt." global: "Du kannst Notizen von allen föderierten Servern sehen." description2: "Du kannst jederzeit am oberen Rand des Bildschirms zwischen den jeweiligen Chroniken wechseln." + description3: "Darüber hinaus gibt es Listen-Chroniken und Kanal-Chroniken. Weitere Einzelheiten findest du unter {link}." _postNote: + description1: "Wenn du eine Notiz auf Misskey veröffentlichst, stehen dir verschiedene Optionen zur Verfügung. Die Oberfläche sieht folgendermaßen aus." _visibility: description: "Du kannst einschränken, wer deine Notiz sehen kann." public: "Deine Notiz wird für alle Nutzer sichtbar sein." + home: "Nur auf der Startseite sichtbar. Kann von Followern, Profilbesuchern und durch Renotes gesehen werden." + followers: "Nur für Follower sichtbar. Nur Follower können es sehen und niemand sonst, und es kann nicht von anderen gerenoted werden." direct: "Die Notiz wird nur für den angegebenen Benutzer veröffentlicht und der Empfänger wird benachrichtigt. Kann anstelle von Direktnachrichten verwendet werden." doNotSendConfidencialOnDirect1: "Sei vorsichtig, wenn du sensible Informationen verschickst!" doNotSendConfidencialOnDirect2: "Die Administratoren des Servers können den Inhalt der Notiz sehen. Sei vorsichtig mit sensiblen Informationen, wenn du Direktnachrichten an Benutzer auf nicht vertrauenswürdigen Servern sendest." @@ -1453,8 +1535,10 @@ _initialTutorial: _exampleNote: cw: "Das wird dich bestimmt hungrig machen!" note: "Ich hatte gerade einen Donut mit Schokoladenüberzug 🍩😋" + useCases: "Dient zur Kennzeichnung von Notizen, wie sie in den Serverrichtlinien vorgeschrieben sind, oder zur eigenen Festlegung von Spoiler-Beiträgen oder sensiblem Text." _howToMakeAttachmentsSensitive: title: "Wie markiert man Anhänge als sensibel?" + description: "Markiere Anhänge als sensibel, die aufgrund von den Serverregeln nicht sichtbar sein sollen." tryThisFile: "Versuche, das angehängte Bild als sensibel zu markieren!" _exampleNote: note: "Ups, ich habe es vergeigt, den Natto-Deckel zu öffnen..." @@ -1465,7 +1549,9 @@ _initialTutorial: title: "Du hast das Tutorial abgeschlossen! 🎉" description: "Die hier beschriebenen Funktionen sind nur ein kleiner Teil dessen, was Misskey zu bieten hat; um mehr darüber zu erfahren, wie du Misskey benutzen kannst, besuche bitte {link}." _timelineDescription: + home: "In der Startseiten-Chronik kannst du Notizen von Konten sehen, denen du folgst." local: "In der lokalen Chronik siehst du Notizen von allen Benutzern auf diesem Server." + social: "Die soziale Chronik zeigt Notizen von der Startseite und der lokalen Chronik." global: "In der globalen Chronik siehst du Notizen von allen föderierten Servern." _serverRules: description: "Eine Reihe von Regeln, die vor der Registrierung angezeigt werden. Eine Zusammenfassung der Nutzungsbedingungen anzuzeigen ist empfohlen." @@ -1483,6 +1569,8 @@ _serverSettings: fanoutTimelineDbFallbackDescription: "Ist diese Option aktiviert, wird die Chronik auf zusätzliche Abfragen in der Datenbank zurückgreifen, wenn sich die Chronik nicht im Cache befindet. Eine Deaktivierung führt zu geringerer Serverlast, aber schränkt den Zeitraum der abrufbaren Chronik ein. " reactionsBufferingDescription: "Wenn diese Option aktiviert ist, kann sie die Leistung beim Erstellen von Reaktionen erheblich verbessern und die Belastung der Datenbank verringern. Allerdings steigt die Speichernutzung von Redis." inquiryUrl: "Kontakt-URL" + inquiryUrlDescription: "Gib eine URL für das Kontaktformular der Serverbetreiber oder eine Webseite an, die Kontaktinformationen enthält." + openRegistration: "Registrierung von Konten aktivieren" openRegistrationWarning: "Das Aktivieren von Registrierungen ist riskant. Es wird empfohlen, sie nur dann zu aktivieren, wenn der Server ständig überwacht wird und im Falle eines Problems sofort reagiert werden kann." thisSettingWillAutomaticallyOffWhenModeratorsInactive: "Wenn über einen bestimmten Zeitraum keine Moderatorenaktivität festgestellt wird, wird diese Einstellung automatisch deaktiviert, um Spam zu verhindern." _accountMigration: @@ -1800,6 +1888,7 @@ _role: canManageAvatarDecorations: "Profilbilddekorationen verwalten" driveCapacity: "Drive-Kapazität" alwaysMarkNsfw: "Dateien immer als NSFW markieren" + canUpdateBioMedia: "Kann ein Profil- oder ein Bannerbild bearbeiten" pinMax: "Maximale Anzahl an angehefteten Notizen" antennaMax: "Maximale Anzahl an Antennen" wordMuteMax: "Maximale Zeichenlänge für Wortstummschaltungen" @@ -1815,12 +1904,20 @@ _role: canUseTranslator: "Verwendung des Übersetzers" avatarDecorationLimit: "Maximale Anzahl an Profilbilddekorationen, die angebracht werden können" canImportAntennas: "Importieren von Antennen erlauben" + canImportBlocking: "Importieren von Blockierungen zulassen" + canImportFollowing: "Importieren von Gefolgten zulassen" + canImportMuting: "Importieren von Stummgeschalteten zulassen" canImportUserLists: "Importieren von Listen erlauben" + canChat: "Chatten erlauben" _condition: + roleAssignedTo: "Manuellen Rollen zugewiesen" isLocal: "Lokaler Benutzer" isRemote: "Benutzer fremder Instanz" isCat: "Katzen-Benutzer" isBot: "Bot-Benutzer" + isSuspended: "Gesperrter Benutzer" + isLocked: "Private Konten" + isExplorable: "Benutzer, die ihr Konto im \"Erkunden\"-Bereich sichtbar machen" createdLessThan: "Kontoerstellung liegt weniger als X zurück" createdMoreThan: "Kontoerstellung liegt mehr als X zurück" followersLessThanOrEq: "Hat X oder weniger Follower" @@ -1975,6 +2072,7 @@ _theme: installed: "{name} wurde installiert" installedThemes: "Installierte Farbschemata" builtinThemes: "Eingebaute Farbschemata" + instanceTheme: "Server-Thema" alreadyInstalled: "Dieses Farbschema ist bereits installiert" invalid: "Der Code dieses Farbschemas ist ungültig" make: "Farbschema erstellen" @@ -2041,6 +2139,7 @@ _sfx: noteMy: "Meine Notizen" notification: "Benachrichtigungen" reaction: "Auswählen einer Reaktion" + chatMessage: "Chat-Nachrichten" _soundSettings: driveFile: "Audiodatei aus dem Drive verwenden" driveFileWarn: "Wähle eine Audiodatei aus dem Drive" @@ -2064,6 +2163,10 @@ _timeIn: seconds: "In {n}s" minutes: "In {n} Min." hours: "In {n} Std." + days: "In {n} Tagen" + weeks: "In {n} Wochen" + months: "In {n} Monaten" + years: "In {n} Jahren" _time: second: "Sekunde(n)" minute: "Minute(n)" @@ -2097,6 +2200,7 @@ _2fa: backupCodesDescription: "Verwende diese Codes, falls du nicht mehr auf deine App zur Zweifaktorauthentifizierung zugreifen kannst. Jeder Code kann nur einmal verwendet werden. Bewahre sie an einem sicheren Ort auf." backupCodeUsedWarning: "Ein Backup-Code wurde verwendet. Falls du den Zugriff zu deiner Zweifaktorauthentifizierungsapp verloren hast, konfiguriere diese bitte möglichst bald erneut." backupCodesExhaustedWarning: "Alle Backup-Codes wurden verwendet. Falls du den Zugang zu deiner Zweifaktorauthentifizierungsapp verlierst, wirst du dich nicht mehr in dieses Konto einloggen können. Bitte konfiguriere diese App erneut." + moreDetailedGuideHere: "Hier ist eine ausführliche Anleitung" _permissions: "read:account": "Deine Benutzerkontoinformationen lesen" "write:account": "Deine Benutzerkontoinformationen bearbeiten" @@ -2147,8 +2251,12 @@ _permissions: "read:admin:server-info": "Serverinformationen anzeigen" "read:admin:show-moderation-log": "Moderationsprotokoll einsehen" "read:admin:show-user": "Private Benutzerinformationen einsehen" + "write:admin:suspend-user": "Benutzer sperren" "write:admin:unset-user-avatar": "Benutzer-Profilbild entfernen" "write:admin:unset-user-banner": "Benutzer-Banner entfernen" + "write:admin:unsuspend-user": "Benutzer entsperren" + "write:admin:meta": "Metadaten der Instanz verwalten" + "write:admin:user-note": "Moderationsvermerke verwalten" "write:admin:roles": "Rollen verwalten" "read:admin:roles": "Rollen anzeigen" "write:admin:relays": "Relays verwalten" @@ -2172,7 +2280,10 @@ _permissions: "read:admin:ad": "Werbung ansehen" "write:invite-codes": "Einladungscodes erstellen" "read:invite-codes": "Einladungscodes anzeigen" + "read:federation": "Informationen zur Föderation einsehen" + "write:report-abuse": "Verstöße melden" "write:chat": "Chats bedienen" + "read:chat": "Chats durchsuchen" _auth: shareAccessTitle: "Verteilung von App-Berechtigungen" shareAccess: "Möchtest du „{name}“ authorisieren, auf dieses Benutzerkonto zugreifen zu können?" @@ -2295,6 +2406,7 @@ _profile: avatarDecorationMax: "Du kannst bis zu {max} Dekorationen hinzufügen." followedMessage: "Nachricht, wenn dir jemand folgt" followedMessageDescription: "Du kannst eine kurze Nachricht festlegen, die dem Empfänger angezeigt wird, wenn er dir folgt." + followedMessageDescriptionForLockedAccount: "Wenn Folgeanfragen deine Genehmigung brauchen, wird dies beim Genehmigen einer Anfrage angezeigt." _exportOrImport: allNotes: "Alle Notizen" favoritedNotes: "Als Favorit markierte Notizen" @@ -2352,6 +2464,7 @@ _play: title: "Titel" script: "Skript" summary: "Beschreibung" + visibilityDescription: "Wenn du die Sichtbarkeit auf Privat stellst, wird der Play nicht auf deinem Profil sichtbar sein, aber jeder, der die URL hat, kann ihn trotzdem aufrufen." _pages: newPage: "Seite erstellen" editPage: "Seite bearbeiten" @@ -2383,6 +2496,7 @@ _pages: eyeCatchingImageSet: "Vorschaubild festlegen" eyeCatchingImageRemove: "Vorschaubild entfernen" chooseBlock: "Block hinzufügen" + enterSectionTitle: "Titel des Abschnitts eingeben" selectType: "Typ auswählen" contentBlocks: "Inhalt" inputBlocks: "Eingabe" @@ -2393,6 +2507,8 @@ _pages: section: "Abschnitt" image: "Bild" button: "Knopf" + dynamic: "Dynamische Bausteine" + dynamicDescription: "Dieser Baustein wurde abgeschafft. Bitte verwende von nun an {play}." note: "Eingebettete Notiz" _note: id: "Notiz-ID" @@ -2415,6 +2531,7 @@ _notification: newNote: "Neue Notiz" unreadAntennaNote: "Antenne {name}" roleAssigned: "Rolle zugewiesen" + chatRoomInvitationReceived: "Du wurdest in einen Chatraum eingeladen" emptyPushNotificationMessage: "Push-Benachrichtigungen wurden aktualisiert" achievementEarned: "Errungenschaft freigeschaltet" testNotification: "Testbenachrichtigung" @@ -2442,9 +2559,11 @@ _notification: receiveFollowRequest: "Erhaltene Follow-Anfragen" followRequestAccepted: "Akzeptierte Follow-Anfragen" roleAssigned: "Rolle zugewiesen" + chatRoomInvitationReceived: "Einladungen zum Chatraum" achievementEarned: "Errungenschaft freigeschaltet" exportCompleted: "Der Export ist abgeschlossen" login: "Anmeldung" + createToken: "Erstellung von Zugriffstokens" test: "Test-Benachrichtigungen" app: "Benachrichtigungen von Apps" _actions: @@ -2560,6 +2679,7 @@ _moderationLogTypes: unmarkSensitiveDriveFile: "Datei als nicht sensitiv markiert" resolveAbuseReport: "Meldung bearbeitet" forwardAbuseReport: "Meldung weitergeleitet" + updateAbuseReportNote: "Moderationsnotiz einer Meldung aktualisiert" createInvitation: "Einladung erstellt" createAd: "Werbung erstellt" deleteAd: "Werbung gelöscht" @@ -2579,6 +2699,8 @@ _moderationLogTypes: deletePage: "Seite gelöscht" deleteFlash: "Play gelöscht" deleteGalleryPost: "Galeriebeitrag gelöscht" + deleteChatRoom: "Chatraum gelöscht" + updateProxyAccountDescription: "Beschreibung des Proxy-Benutzerkontos aktualisiert" _fileViewer: title: "Dateiinformationen" type: "Dateityp" @@ -2644,6 +2766,7 @@ _hemisphere: S: "Südliche Erdhalbkugel" caption: "Wird in einigen Client-Einstellungen zur Bestimmung der Jahreszeit verwendet." _reversi: + reversi: "Reversi" gameSettings: "Spieleinstellungen" chooseBoard: "Spielbrett auswählen" blackOrWhite: "Schwarz/Weiß" @@ -2661,6 +2784,7 @@ _reversi: pastTurnOf: "Zug von {name}" surrender: "Aufgeben" surrendered: "Aufgegeben" + timeout: "Zeit abgelaufen" drawn: "Unentschieden" won: "{name} hat gewonnen" black: "Schwarz" @@ -2675,6 +2799,7 @@ _reversi: freeMatch: "Freies Spiel" lookingForPlayer: "Gegner werden gesucht..." gameCanceled: "Das Spiel wurde abgesagt." + shareToTlTheGameWhenStart: "Spiel in der Chronik teilen, wenn es gestartet wurde" iStartedAGame: "Das Spiel hat begonnen! #MisskeyReversi" opponentHasSettingsChanged: "Der Gegner hat seine Einstellungen geändert." allowIrregularRules: "Irreguläre Regeln (völlig frei)" @@ -2695,7 +2820,9 @@ _urlPreviewSetting: requireContentLengthDescription: "Wenn der Server keine Content-Length zurückgibt, wird keine Vorschau erzeugt." userAgent: "User-Agent" userAgentDescription: "Legt den User-Agent fest, der beim Abrufen der Vorschau verwendet werden soll. Bleibt er leer, wird der Standard-User-Agent verwendet." + summaryProxy: "Proxy-Endpunkte, die Vorschaubilder erzeugen" summaryProxyDescription: "Generierung von Vorschaubildern mit Summaly Proxy anstelle von Misskey selbst." + summaryProxyDescription2: "Die folgenden Parameter werden als Abfrage-Strings mit dem Proxy verknüpft. Wenn der Proxy sie nicht unterstützt, werden die Werte ignoriert." _mediaControls: pip: "Bild-in-Bild" playbackRate: "Wiedergabegeschwindigkeit" @@ -2703,15 +2830,57 @@ _mediaControls: _contextMenu: title: "Kontextmenü" app: "Anwendung" + appWithShift: "Anwendung per Umschalttaste" + native: "Natives Browsermenü" _gridComponent: _error: requiredValue: "Dieser Wert ist ein Pflichtfeld" + columnTypeNotSupport: "Die Validierung regulärer Ausdrücke wird nur für Spalten vom Typ \"Text\" unterstützt." + patternNotMatch: "Dieser Wert stimmt nicht mit dem Schema in {pattern} überein" notUnique: "Dieser Wert muss eindeutig sein" +_roleSelectDialog: + notSelected: "Nicht ausgewählt" _customEmojisManager: + _gridCommon: + copySelectionRows: "Ausgewählte Zeilen kopieren" + copySelectionRanges: "Auswahl kopieren" + deleteSelectionRows: "Ausgewählte Zeilen löschen" + searchSettings: "Sucheinstellungen" + searchSettingCaption: "Detaillierte Suchkriterien festlegen." + searchLimit: "Anzahl der Ergebnisse" + sortOrder: "Sortierung" + registrationLogs: "Registrierungsprotokoll" + registrationLogsCaption: "Protokolle werden beim Aktualisieren oder Löschen von Emojis angezeigt. Sie verschwinden nach dem Aktualisieren oder Löschen, dem Wechsel zu einer neuen Seite oder dem Neuladen." + alertEmojisRegisterFailedDescription: "Emoji konnte nicht aktualisiert oder gelöscht werden. Bitte prüfe das Registrierungsprotokoll für Details." _logs: + failureLogNothing: "Es gibt kein Fehlerprotokoll." logNothing: "Keine Protokoll-Einträge." _remote: + selectionRowDetail: "Details der ausgewählten Zeile" + importSelectionRangesRows: "Zeilen in der Auswahl importieren" + importEmojisButton: "Ausgewählte Emojis importieren" confirmImportEmojisTitle: "Emojis importieren" + confirmImportEmojisDescription: "Importiere {count} Emoji(s), die von entfernten Server empfangen wurden. Bitte achte genau auf die Lizenz der Emojis. Bist du sicher, dass du fortfahren möchtest?" + _local: + tabTitleList: "Hinzugefügte Emojis" + tabTitleRegister: "Emojis hinzufügen" + _list: + emojisNothing: "Es wurden keine Emojis hinzugefügt." + alertUpdateEmojisNothingDescription: "Es wurden keine Emojis geändert." + alertDeleteEmojisNothingDescription: "Es gibt keine zu löschenden Emojis." + confirmUpdateEmojisDescription: "Aktualisiere {count} Emoji(s). Willst du fortfahren?" + confirmDeleteEmojisDescription: "Lösche {count} ausgewählte Emoji(s). Willst du fortfahren?" + confirmMovePageDesciption: "An den Emojis auf dieser Seite wurden Änderungen vorgenommen.\nWenn du die Seite verlässt, ohne zu speichern, werden alle auf dieser Seite vorgenommenen Änderungen verworfen." + _register: + uploadSettingDescription: "Hier kannst du das Verhalten beim Hochladen von Emojis konfigurieren." + directoryToCategoryLabel: "Gib den Namen des Verzeichnisses in das Feld „Kategorie“ ein" + directoryToCategoryCaption: "Wenn du ein Verzeichnis ziehst und ablegst, gib den Verzeichnisnamen in das Feld „Kategorie“ ein." + emojiInputAreaList1: "Ziehe Bilddateien oder Verzeichnisse per Drag-and-drop in diesen Rahmen" + emojiInputAreaList2: "Klicke auf diesen Link, um von deinem PC aus zu wählen" + emojiInputAreaList3: "Klicke auf diesen Link, um vom Drive aus zu wählen" + confirmRegisterEmojisDescription: "Füge die in der Liste aufgeführten Emojis als neue benutzerdefinierte Emojis hinzu. Bist du sicher? (Um eine Überlastung zu vermeiden, können nur {count} Emoji(s) in einem Vorgang hinzugefügt werden)" + confirmClearEmojisDescription: "Verwerfe die Bearbeitungen und lösche die Emojis aus der Liste. Bist du sicher, dass du fortfahren möchtest?" + confirmUploadEmojisDescription: "Lade die {count} abgelegte(n) Datei(en) in das Drive hoch. Bist du sicher, dass du fortfahren möchtest?" _embedCodeGen: title: "Einbettungscode anpassen" header: "Kopfzeile anzeigen" @@ -2719,6 +2888,9 @@ _embedCodeGen: maxHeight: "Maximale Höhe" maxHeightDescription: "Der Wert 0 deaktiviert die Einstellung der maximalen Höhe. Gib einen Wert an, um zu verhindern, dass das Widget weiterhin vertikal vergrößert wird." maxHeightWarn: "Die Begrenzung der maximalen Höhe ist deaktiviert (0). Wenn dies nicht beabsichtigt war, setze die maximale Höhe auf einen Wert fest." + previewIsNotActual: "Die Anzeige weicht von der tatsächlichen Einbettung ab, da sie den auf dem Vorschaufenster angezeigten Bereich überschreitet." + rounded: "Ecken abrunden" + border: "Dem äußeren Rand einen Rahmen hinzufügen" applyToPreview: "Auf die Vorschau anwenden" generateCode: "Einbettungscode generieren" codeGenerated: "Der Code wurde generiert" @@ -2749,8 +2921,17 @@ _remoteLookupErrors: title: "Nicht gefunden" description: "Die angeforderte Ressource konnte nicht gefunden werden, bitte überprüfe die URI erneut." _captcha: + verify: "Bitte beantworte das CAPTCHA" + testSiteKeyMessage: "Du kannst die Vorschau prüfen, indem du die Testwerte für den Site- und Secret-Key eingibst. Weitere Informationen findest du auf der folgenden Seite." _error: + _requestFailed: + title: "CAPTCHA-Anfrage fehlgeschlagen." + text: "Bitte probiere es später noch einmal oder überprüfe die Einstellungen erneut." + _verificationFailed: + title: "CAPTCHA-Prüfung fehlgeschlagen" + text: "Bitte überprüfe nochmals, ob die Einstellungen korrekt sind." _unknown: + title: "CAPTCHA-Fehler" text: "Es ist ein unerwarteter Fehler aufgetreten." _bootErrors: title: "Laden fehlgeschlagen" diff --git a/locales/en-US.yml b/locales/en-US.yml index 68d52c721d..089ed2383d 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1406,6 +1406,7 @@ _settings: timelineAndNote: "Timeline and note" makeEveryTextElementsSelectable: "Make all text elements selectable" makeEveryTextElementsSelectable_description: "Enabling this may reduce usability in some situations." + useStickyIcons: "Make icons follow while scrolling" showNavbarSubButtons: "Show sub-buttons on the navigation bar" ifOn: "When turned on" ifOff: "When turned off" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 3f2fa089da..a39ca4f8db 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1406,6 +1406,7 @@ _settings: timelineAndNote: "时间线和帖子" makeEveryTextElementsSelectable: "使所有的文字均可选择" makeEveryTextElementsSelectable_description: "若开启,在某些情况下可能降低用户体验。" + useStickyIcons: "使图标跟随滚动" showNavbarSubButtons: "在导航栏中显示副按钮" ifOn: "启用时" ifOff: "关闭时" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 5ff252eb49..71f3c45d6a 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -1406,6 +1406,7 @@ _settings: timelineAndNote: "時間軸及貼文" makeEveryTextElementsSelectable: "允許選取所有文字" makeEveryTextElementsSelectable_description: "啟用此功能後,可能會在某些情境下降低可用性。" + useStickyIcons: "使大頭貼跟隨捲動" showNavbarSubButtons: "在導覽列顯示輔助按鈕" ifOn: "開啟時" ifOff: "關閉時" From 6e929ece6f1a1b5b369ebf1f6b534a69789a27b2 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 18:13:08 +0900 Subject: [PATCH 358/649] fix(frontend): suppress inject warn --- packages/frontend/src/components/global/MkPageHeader.vue | 2 +- packages/frontend/src/router.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/global/MkPageHeader.vue b/packages/frontend/src/components/global/MkPageHeader.vue index 6b524785e4..2914012a0c 100644 --- a/packages/frontend/src/components/global/MkPageHeader.vue +++ b/packages/frontend/src/components/global/MkPageHeader.vue @@ -68,7 +68,7 @@ const emit = defineEmits<{ (ev: 'update:tab', key: string); }>(); -const viewId = inject(DI.viewId); +//const viewId = inject(DI.viewId); const injectedPageMetadata = inject(DI.pageMetadata); const pageMetadata = computed(() => props.overridePageMetadata ?? injectedPageMetadata.value); diff --git a/packages/frontend/src/router.ts b/packages/frontend/src/router.ts index d702da80fa..97ca63f50d 100644 --- a/packages/frontend/src/router.ts +++ b/packages/frontend/src/router.ts @@ -42,5 +42,5 @@ mainRouter.addListener('change', ctx => { mainRouter.init(); export function useRouter(): Router { - return inject(DI.router) ?? mainRouter; + return inject(DI.router, null) ?? mainRouter; } From e0d87028391500898adc2668d509e2d155d8b961 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 18:13:39 +0900 Subject: [PATCH 359/649] perf(frontend): tweak MkRange --- packages/frontend/src/components/MkRange.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/frontend/src/components/MkRange.vue b/packages/frontend/src/components/MkRange.vue index 734b624541..c0e3e5db4b 100644 --- a/packages/frontend/src/components/MkRange.vue +++ b/packages/frontend/src/components/MkRange.vue @@ -159,12 +159,13 @@ function onMousedown(ev: MouseEvent | TouchEvent) { const onDrag = (ev: MouseEvent | TouchEvent) => { ev.preventDefault(); + let beforeValue = finalValue.value; const containerRect = containerEl.value!.getBoundingClientRect(); const pointerX = 'touches' in ev && ev.touches.length > 0 ? ev.touches[0].clientX : 'clientX' in ev ? ev.clientX : 0; const pointerPositionOnContainer = pointerX - (containerRect.left + (thumbWidth / 2)); rawValue.value = Math.min(1, Math.max(0, pointerPositionOnContainer / (containerEl.value!.offsetWidth - thumbWidth))); - if (props.continuousUpdate) { + if (props.continuousUpdate && beforeValue !== finalValue.value) { emit('update:modelValue', finalValue.value); } }; From 87a723897611fff9b5ddda8a8bec3cdb427a21dc Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Sun, 30 Mar 2025 20:44:00 +0900 Subject: [PATCH 360/649] =?UTF-8?q?enhance(frontend):=20=E3=83=87=E3=83=83?= =?UTF-8?q?=E3=82=AD=E3=81=AE=E3=82=AA=E3=83=97=E3=82=B7=E3=83=A7=E3=83=B3?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 6 +- locales/index.d.ts | 24 ++ locales/ja-JP.yml | 6 + packages/frontend/src/pages/settings/deck.vue | 33 +++ packages/frontend/src/preferences/def.ts | 11 +- .../frontend/src/ui/_common_/navbar-h.vue | 214 ++++++++++++++++++ packages/frontend/src/ui/deck.vue | 166 +++++++++----- .../utility/autogen/settings-search-index.ts | 17 +- 8 files changed, 417 insertions(+), 60 deletions(-) create mode 100644 packages/frontend/src/ui/_common_/navbar-h.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 0268127cbe..0ecec21953 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,9 @@ - Enhance: プラグインの管理が強化されました - インストール/アンインストール/設定の変更時にリロード不要になりました - Enhance: ログアウト時、ブラウザに保存されたWebクライアントのデータを全て消去するように +- Enhance: デッキUIでカラム間のマージンを設定できるように +- Enhance: デッキUIでデッキメニューの位置を設定できるように +- Enhance: デッキUIでナビゲーションバーの位置を設定できるように - Enhance: アイコンのスクロール追従を無効化してパフォーマンス向上できるように - Enhance: CWの注釈テキストが入力されていない場合, Postボタンを非アクティブに - Enhance: CWを無効にした場合, 注釈テキストが最大入力文字数を超えていても投稿できるように @@ -52,8 +55,7 @@ - Fix: 読み込み直後にスクロールしようとすると途中で止まる場合があるのを修正 - Fix: テーマ切り替え時に一部の色が変わらない問題を修正 - NOTE: 構造上クラシックUIを新しいデザインシステムに移行することが困難なため、クラシックUIが削除されました - - デッキUIでカラムを中央寄せにし、メインカラムの左右にウィジェットカラムを配置することである程度クラシックUIを再現できます - - また、デッキでナビゲーションバーを上部に表示するオプションを実装予定です + - デッキUIでカラムを中央寄せにし、メインカラムの左右にウィジェットカラムを配置し、ナビゲーションバーを上部に表示することである程度クラシックUIを再現できます ### Server - Enhance 全体的なパフォーマンス向上 diff --git a/locales/index.d.ts b/locales/index.d.ts index 3dfd0e6029..3645639305 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -5362,6 +5362,18 @@ export interface Locale extends ILocale { * 圧縮 */ "compress": string; + /** + * 右 + */ + "right": string; + /** + * 下 + */ + "bottom": string; + /** + * 上 + */ + "top": string; "_chat": { /** * まだメッセージはありません @@ -10065,6 +10077,18 @@ export interface Locale extends ILocale { * カラムの寄せ */ "columnAlign": string; + /** + * カラム間のマージン + */ + "columnGap": string; + /** + * デッキメニューの位置 + */ + "deckMenuPosition": string; + /** + * ナビゲーションバーの位置 + */ + "navbarPosition": string; /** * カラムを追加 */ diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index eb1505270c..0e20001d6b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1336,6 +1336,9 @@ chat: "チャット" migrateOldSettings: "旧設定情報を移行" migrateOldSettings_description: "通常これは自動で行われていますが、何らかの理由により上手く移行されなかった場合は手動で移行処理をトリガーできます。現在の設定情報は上書きされます。" compress: "圧縮" +right: "右" +bottom: "下" +top: "上" _chat: noMessagesYet: "まだメッセージはありません" @@ -2662,6 +2665,9 @@ _notification: _deck: alwaysShowMainColumn: "常にメインカラムを表示" columnAlign: "カラムの寄せ" + columnGap: "カラム間のマージン" + deckMenuPosition: "デッキメニューの位置" + navbarPosition: "ナビゲーションバーの位置" addColumn: "カラムを追加" newNoteNotificationSettings: "新着ノート通知の設定" configureColumn: "カラムの設定" diff --git a/packages/frontend/src/pages/settings/deck.vue b/packages/frontend/src/pages/settings/deck.vue index 9b2b40374e..902e058e0d 100644 --- a/packages/frontend/src/pages/settings/deck.vue +++ b/packages/frontend/src/pages/settings/deck.vue @@ -45,6 +45,35 @@ SPDX-License-Identifier: AGPL-3.0-only + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -53,6 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, ref } from 'vue'; import MkSwitch from '@/components/MkSwitch.vue'; import MkRadios from '@/components/MkRadios.vue'; +import MkRange from '@/components/MkRange.vue'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { prefer } from '@/preferences.js'; @@ -62,6 +92,9 @@ const navWindow = prefer.model('deck.navWindow'); const useSimpleUiForNonRootPages = prefer.model('deck.useSimpleUiForNonRootPages'); const alwaysShowMainColumn = prefer.model('deck.alwaysShowMainColumn'); const columnAlign = prefer.model('deck.columnAlign'); +const columnGap = prefer.model('deck.columnGap'); +const menuPosition = prefer.model('deck.menuPosition'); +const navbarPosition = prefer.model('deck.navbarPosition'); const profilesSyncEnabled = ref(prefer.isSyncEnabled('deck.profiles')); diff --git a/packages/frontend/src/preferences/def.ts b/packages/frontend/src/preferences/def.ts index 37fa9471ee..5aa463f045 100644 --- a/packages/frontend/src/preferences/def.ts +++ b/packages/frontend/src/preferences/def.ts @@ -371,7 +371,16 @@ export const PREF_DEF = { default: true, }, 'deck.columnAlign': { - default: 'left' as 'left' | 'right' | 'center', + default: 'center' as 'left' | 'right' | 'center', + }, + 'deck.columnGap': { + default: 6, + }, + 'deck.menuPosition': { + default: 'bottom' as 'right' | 'bottom', + }, + 'deck.navbarPosition': { + default: 'left' as 'left' | 'top' | 'bottom', }, 'chat.showSenderName': { diff --git a/packages/frontend/src/ui/_common_/navbar-h.vue b/packages/frontend/src/ui/_common_/navbar-h.vue new file mode 100644 index 0000000000..c93935dd26 --- /dev/null +++ b/packages/frontend/src/ui/_common_/navbar-h.vue @@ -0,0 +1,214 @@ + + + + + + + diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 3f3bc32fad..3de8137404 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -4,37 +4,43 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -81,20 +54,12 @@ import { updateCurrentAccountPartial } from '@/accounts.js'; import MkInput from '@/components/MkInput.vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; import MkInfo from '@/components/MkInfo.vue'; +import MkChatHistories from '@/components/MkChatHistories.vue'; const $i = ensureSignin(); const router = useRouter(); -const initializing = ref(true); -const fetching = ref(false); -const history = ref<{ - id: string; - message: Misskey.entities.ChatMessage; - other: Misskey.entities.ChatMessage['fromUser'] | Misskey.entities.ChatMessage['toUser'] | null; - isMe: boolean; -}[]>([]); - const searchQuery = ref(''); const searched = ref(false); const searchResults = ref([]); @@ -148,57 +113,8 @@ async function search() { searched.value = true; } -async function fetchHistory() { - if (fetching.value) return; - - fetching.value = true; - - const [userMessages, roomMessages] = await Promise.all([ - misskeyApi('chat/history', { room: false }), - misskeyApi('chat/history', { room: true }), - ]); - - history.value = [...userMessages, ...roomMessages] - .toSorted((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) - .map(m => ({ - id: m.id, - message: m, - other: (!('room' in m) || m.room == null) ? (m.fromUserId === $i.id ? m.toUser : m.fromUser) : null, - isMe: m.fromUserId === $i.id, - })); - - fetching.value = false; - initializing.value = false; - - updateCurrentAccountPartial({ hasUnreadChatMessages: false }); -} - -let isActivated = true; - -onActivated(() => { - isActivated = true; -}); - -onDeactivated(() => { - isActivated = false; -}); - -useInterval(() => { - // TODO: DOM的にバックグラウンドになっていないかどうかも考慮する - if (!window.document.hidden && isActivated) { - fetchHistory(); - } -}, 1000 * 10, { - immediate: false, - afterMounted: true, -}); - -onActivated(() => { - fetchHistory(); -}); - onMounted(() => { - fetchHistory(); + updateCurrentAccountPartial({ hasUnreadChatMessages: false }); }); @@ -207,77 +123,6 @@ onMounted(() => { margin: 0 auto; } -.message { - position: relative; - display: flex; - padding: 16px 24px; - - &.isRead, - &.isMe { - opacity: 0.8; - } - - &:not(.isMe):not(.isRead) { - &::before { - content: ''; - position: absolute; - top: 8px; - right: 8px; - width: 8px; - height: 8px; - border-radius: 100%; - background-color: var(--MI_THEME-accent); - } - } -} - -.messageAvatar { - width: 50px; - height: 50px; - margin: 0 16px 0 0; -} - -.messageBody { - flex: 1; - min-width: 0; -} - -.messageHeader { - display: flex; - align-items: center; - margin-bottom: 2px; - white-space: nowrap; - overflow: clip; -} - -.messageHeaderName { - margin: 0; - padding: 0; - overflow: hidden; - text-overflow: ellipsis; - font-size: 1em; - font-weight: bold; -} - -.messageHeaderUsername { - margin: 0 8px; -} - -.messageHeaderTime { - margin-left: auto; -} - -.messageBodyText { - overflow: hidden; - overflow-wrap: break-word; - font-size: 1.1em; -} - -.youSaid { - font-weight: bold; - margin-right: 0.5em; -} - .searchResultItem { padding: 12px; border: solid 1px var(--MI_THEME-divider); diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 96961d951f..7556f513c2 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -97,6 +97,7 @@ import XWidgetsColumn from '@/ui/deck/widgets-column.vue'; import XMentionsColumn from '@/ui/deck/mentions-column.vue'; import XDirectColumn from '@/ui/deck/direct-column.vue'; import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue'; +import XChatColumn from '@/ui/deck/chat-column.vue'; import { mainRouter } from '@/router.js'; import { columns, layout, columnTypes, switchProfileMenu, addColumn as addColumnToStore, deleteProfile as deleteProfile_ } from '@/deck.js'; @@ -114,6 +115,7 @@ const columnComponents = { mentions: XMentionsColumn, direct: XDirectColumn, roleTimeline: XRoleTimelineColumn, + chat: XChatColumn, }; mainRouter.navHook = (path, flag): boolean => { diff --git a/packages/frontend/src/ui/deck/chat-column.vue b/packages/frontend/src/ui/deck/chat-column.vue new file mode 100644 index 0000000000..791af2e44c --- /dev/null +++ b/packages/frontend/src/ui/deck/chat-column.vue @@ -0,0 +1,27 @@ + + + + + From 525b6a76773a25c7bb48761082fa93732567b138 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 15 Apr 2025 15:37:29 +0900 Subject: [PATCH 476/649] feat(frontend): chat widget --- CHANGELOG.md | 1 + locales/index.d.ts | 4 ++ locales/ja-JP.yml | 1 + packages/frontend/src/widgets/WidgetChat.vue | 52 ++++++++++++++++++++ packages/frontend/src/widgets/index.ts | 2 + 5 files changed, 60 insertions(+) create mode 100644 packages/frontend/src/widgets/WidgetChat.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index 90952614c9..38563da555 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ - ### Client +- Feat: チャットウィジェットを追加 - Feat: デッキにチャットカラムを追加 - Fix: ログアウトした際に処理が終了しない問題を修正 - Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように diff --git a/locales/index.d.ts b/locales/index.d.ts index 5885e04847..97e66be6d7 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -9207,6 +9207,10 @@ export interface Locale extends ILocale { * 今日誕生日のユーザー */ "birthdayFollowings": string; + /** + * チャット + */ + "chat": string; }; "_cw": { /** diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4a334c2b41..1801c8e15b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -2421,6 +2421,7 @@ _widgets: chooseList: "リストを選択" clicker: "クリッカー" birthdayFollowings: "今日誕生日のユーザー" + chat: "チャット" _cw: hide: "隠す" diff --git a/packages/frontend/src/widgets/WidgetChat.vue b/packages/frontend/src/widgets/WidgetChat.vue new file mode 100644 index 0000000000..43b2a6e522 --- /dev/null +++ b/packages/frontend/src/widgets/WidgetChat.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/packages/frontend/src/widgets/index.ts b/packages/frontend/src/widgets/index.ts index ea17d484c5..aea810d1ea 100644 --- a/packages/frontend/src/widgets/index.ts +++ b/packages/frontend/src/widgets/index.ts @@ -35,6 +35,7 @@ export default function(app: App) { app.component('WidgetUserList', defineAsyncComponent(() => import('./WidgetUserList.vue'))); app.component('WidgetClicker', defineAsyncComponent(() => import('./WidgetClicker.vue'))); app.component('WidgetBirthdayFollowings', defineAsyncComponent(() => import('./WidgetBirthdayFollowings.vue'))); + app.component('WidgetChat', defineAsyncComponent(() => import('./WidgetChat.vue'))); } // 連合関連のウィジェット(連合無効時に隠す) @@ -70,6 +71,7 @@ export const widgets = [ 'userList', 'clicker', 'birthdayFollowings', + 'chat', ...federationWidgets, ]; From 6bd45a27b13c4c00d627ad056bc7b57047b9493d Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 15 Apr 2025 16:09:04 +0900 Subject: [PATCH 477/649] =?UTF-8?q?fix:=20=E3=83=95=E3=82=A9=E3=83=AB?= =?UTF-8?q?=E3=83=80=E3=82=92=E9=96=8B=E3=81=84=E3=81=9F=E7=8A=B6=E6=85=8B?= =?UTF-8?q?=E3=81=A7=E3=83=A1=E3=83=8B=E3=83=A5=E3=83=BC=E3=81=8B=E3=82=89?= =?UTF-8?q?=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD=E3=83=BC=E3=83=89=E3=81=97?= =?UTF-8?q?=E3=81=A6=E3=82=82=E3=83=AB=E3=83=BC=E3=83=88=E3=83=95=E3=82=A9?= =?UTF-8?q?=E3=83=AB=E3=83=80=E3=81=AB=E3=82=A2=E3=83=83=E3=83=97=E3=83=AD?= =?UTF-8?q?=E3=83=BC=E3=83=89=E3=81=95=E3=82=8C=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=20(#15836)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題 * docs(changelog): Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836 --- CHANGELOG.md | 1 + packages/frontend/src/components/MkDrive.vue | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38563da555..3214ef936f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - Feat: デッキにチャットカラムを追加 - Fix: ログアウトした際に処理が終了しない問題を修正 - Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように +- Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836 ### Server - Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように diff --git a/packages/frontend/src/components/MkDrive.vue b/packages/frontend/src/components/MkDrive.vue index c212167c8f..6270ac8314 100644 --- a/packages/frontend/src/components/MkDrive.vue +++ b/packages/frontend/src/components/MkDrive.vue @@ -626,13 +626,13 @@ function getMenu() { text: i18n.ts.upload + ' (' + i18n.ts.compress + ')', icon: 'ti ti-upload', action: () => { - chooseFileFromPc(true, { keepOriginal: false }); + chooseFileFromPc(true, { uploadFolder: folder.value?.id, keepOriginal: false }); }, }, { text: i18n.ts.upload, icon: 'ti ti-upload', action: () => { - chooseFileFromPc(true, { keepOriginal: true }); + chooseFileFromPc(true, { uploadFolder: folder.value?.id, keepOriginal: true }); }, }, { text: i18n.ts.fromUrl, From d5fe6e36aecd2551fb2f3b80af4d1c42e0010fc7 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 15 Apr 2025 16:10:17 +0900 Subject: [PATCH 478/649] =?UTF-8?q?fix:=20avatarId=20=E3=81=8C=20null=20?= =?UTF-8?q?=E3=81=AE=E3=81=A8=E3=81=8D=E3=81=AB=E3=82=82=20avatarUrl=20?= =?UTF-8?q?=E3=81=8C=20non=20null=20=E6=8B=85=E3=81=A3=E3=81=A6=E3=82=8B?= =?UTF-8?q?=E3=81=93=E3=81=A8=E3=81=8C=E3=81=82=E3=82=8B=E5=95=8F=E9=A1=8C?= =?UTF-8?q?=20(#15833)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/backend/src/core/WebhookTestService.ts | 8 ++++---- packages/backend/src/core/entities/UserEntityService.ts | 8 ++++---- packages/backend/src/models/User.ts | 4 ++++ packages/backend/src/server/ServerService.ts | 2 +- packages/backend/src/server/web/ClientServerService.ts | 2 +- packages/backend/src/server/web/FeedService.ts | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/core/WebhookTestService.ts b/packages/backend/src/core/WebhookTestService.ts index 222153fd2a..9cf985b688 100644 --- a/packages/backend/src/core/WebhookTestService.ts +++ b/packages/backend/src/core/WebhookTestService.ts @@ -411,8 +411,8 @@ export class WebhookTestService { name: user.name, username: user.username, host: user.host, - avatarUrl: user.avatarUrl, - avatarBlurhash: user.avatarBlurhash, + avatarUrl: user.avatarId == null ? null : user.avatarUrl, + avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash, avatarDecorations: user.avatarDecorations.map(it => ({ id: it.id, angle: it.angle, @@ -441,8 +441,8 @@ export class WebhookTestService { createdAt: new Date().toISOString(), updatedAt: user.updatedAt?.toISOString() ?? null, lastFetchedAt: user.lastFetchedAt?.toISOString() ?? null, - bannerUrl: user.bannerUrl, - bannerBlurhash: user.bannerBlurhash, + bannerUrl: user.bannerId == null ? null : user.bannerUrl, + bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash, isLocked: user.isLocked, isSilenced: false, isSuspended: user.isSuspended, diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index e252ff509e..d4769d24d4 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -486,8 +486,8 @@ export class UserEntityService implements OnModuleInit { name: user.name, username: user.username, host: user.host, - avatarUrl: user.avatarUrl ?? this.getIdenticonUrl(user), - avatarBlurhash: user.avatarBlurhash, + avatarUrl: (user.avatarId == null ? null : user.avatarUrl) ?? this.getIdenticonUrl(user), + avatarBlurhash: (user.avatarId == null ? null : user.avatarBlurhash), avatarDecorations: user.avatarDecorations.length > 0 ? this.avatarDecorationService.getAll().then(decorations => user.avatarDecorations.filter(ud => decorations.some(d => d.id === ud.id)).map(ud => ({ id: ud.id, angle: ud.angle || undefined, @@ -533,8 +533,8 @@ export class UserEntityService implements OnModuleInit { createdAt: this.idService.parse(user.id).date.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, - bannerUrl: user.bannerUrl, - bannerBlurhash: user.bannerBlurhash, + bannerUrl: user.bannerId == null ? null : user.bannerUrl, + bannerBlurhash: user.bannerId == null ? null : user.bannerBlurhash, isLocked: user.isLocked, isSilenced: this.roleService.getUserPolicies(user.id).then(r => !r.canPublicNote), isSuspended: user.isSuspended, diff --git a/packages/backend/src/models/User.ts b/packages/backend/src/models/User.ts index bc652cea62..baf4eefdf1 100644 --- a/packages/backend/src/models/User.ts +++ b/packages/backend/src/models/User.ts @@ -118,21 +118,25 @@ export class MiUser { @JoinColumn() public banner: MiDriveFile | null; + // avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること @Column('varchar', { length: 512, nullable: true, }) public avatarUrl: string | null; + // bannerId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは bannerId の non-null チェックをすること @Column('varchar', { length: 512, nullable: true, }) public bannerUrl: string | null; + // avatarId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは avatarId の non-null チェックをすること @Column('varchar', { length: 128, nullable: true, }) public avatarBlurhash: string | null; + // bannerId が null になったとしてもこれが null でない可能性があるため、このフィールドを使うときは bannerId の non-null チェックをすること @Column('varchar', { length: 128, nullable: true, }) diff --git a/packages/backend/src/server/ServerService.ts b/packages/backend/src/server/ServerService.ts index b899053287..355d7ca08e 100644 --- a/packages/backend/src/server/ServerService.ts +++ b/packages/backend/src/server/ServerService.ts @@ -221,7 +221,7 @@ export class ServerService implements OnApplicationShutdown { reply.header('Cache-Control', 'public, max-age=86400'); if (user) { - reply.redirect(user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user)); + reply.redirect((user.avatarId == null ? null : user.avatarUrl) ?? this.userEntityService.getIdenticonUrl(user)); } else { reply.redirect('/static-assets/user-unknown.png'); } diff --git a/packages/backend/src/server/web/ClientServerService.ts b/packages/backend/src/server/web/ClientServerService.ts index 927970e2e2..30a911088e 100644 --- a/packages/backend/src/server/web/ClientServerService.ts +++ b/packages/backend/src/server/web/ClientServerService.ts @@ -534,7 +534,7 @@ export class ClientServerService { return await reply.view('user', { user, profile, me, - avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), + avatarUrl: _user.avatarUrl, sub: request.params.sub, ...await this.generateCommonPugData(this.meta), clientCtx: htmlSafeJsonStringify({ diff --git a/packages/backend/src/server/web/FeedService.ts b/packages/backend/src/server/web/FeedService.ts index 9d810ddc84..eae7645321 100644 --- a/packages/backend/src/server/web/FeedService.ts +++ b/packages/backend/src/server/web/FeedService.ts @@ -65,7 +65,7 @@ export class FeedService { generator: 'Misskey', description: `${user.notesCount} Notes, ${profile.followingVisibility === 'public' ? user.followingCount : '?'} Following, ${profile.followersVisibility === 'public' ? user.followersCount : '?'} Followers${profile.description ? ` · ${profile.description}` : ''}`, link: author.link, - image: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user), + image: (user.avatarId == null ? null : user.avatarUrl) ?? this.userEntityService.getIdenticonUrl(user), feedLinks: { json: `${author.link}.json`, atom: `${author.link}.atom`, From f454e820bd5f1698a25fde38277ce37adbd277dc Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 15 Apr 2025 16:14:52 +0900 Subject: [PATCH 479/649] feat: render quote note with `quote-inline` class for ap compatibility (#15818) --- packages/backend/src/core/MfmService.ts | 10 +++++++-- .../src/core/activitypub/ApMfmService.ts | 10 ++++----- .../src/core/activitypub/ApRendererService.ts | 22 +++++++++++++++---- 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/core/MfmService.ts b/packages/backend/src/core/MfmService.ts index 00208927e2..28d980f718 100644 --- a/packages/backend/src/core/MfmService.ts +++ b/packages/backend/src/core/MfmService.ts @@ -6,7 +6,7 @@ import { URL } from 'node:url'; import { Inject, Injectable } from '@nestjs/common'; import * as parse5 from 'parse5'; -import { Window, XMLSerializer } from 'happy-dom'; +import { type Document, type HTMLParagraphElement, Window, XMLSerializer } from 'happy-dom'; import { DI } from '@/di-symbols.js'; import type { Config } from '@/config.js'; import { intersperse } from '@/misc/prelude/array.js'; @@ -23,6 +23,8 @@ type ChildNode = DefaultTreeAdapterMap['childNode']; const urlRegex = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+/; const urlRegexFull = /^https?:\/\/[\w\/:%#@$&?!()\[\]~.,=+\-]+$/; +export type Appender = (document: Document, body: HTMLParagraphElement) => void; + @Injectable() export class MfmService { constructor( @@ -267,7 +269,7 @@ export class MfmService { } @bindThis - public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = []) { + public toHtml(nodes: mfm.MfmNode[] | null, mentionedRemoteUsers: IMentionedRemoteUsers = [], additionalAppenders: Appender[] = []) { if (nodes == null) { return null; } @@ -492,6 +494,10 @@ export class MfmService { appendChildren(nodes, body); + for (const additionalAppender of additionalAppenders) { + additionalAppender(doc, body); + } + // Remove the unnecessary namespace const serialized = new XMLSerializer().serializeToString(body).replace(/^\s*

/, '

'); diff --git a/packages/backend/src/core/activitypub/ApMfmService.ts b/packages/backend/src/core/activitypub/ApMfmService.ts index 4036d2794a..f4c07e472c 100644 --- a/packages/backend/src/core/activitypub/ApMfmService.ts +++ b/packages/backend/src/core/activitypub/ApMfmService.ts @@ -5,7 +5,7 @@ import { Injectable } from '@nestjs/common'; import * as mfm from 'mfm-js'; -import { MfmService } from '@/core/MfmService.js'; +import { MfmService, Appender } from '@/core/MfmService.js'; import type { MiNote } from '@/models/Note.js'; import { bindThis } from '@/decorators.js'; import { extractApHashtagObjects } from './models/tag.js'; @@ -25,17 +25,17 @@ export class ApMfmService { } @bindThis - public getNoteHtml(note: Pick, apAppend?: string) { + public getNoteHtml(note: Pick, additionalAppender: Appender[] = []) { let noMisskeyContent = false; - const srcMfm = (note.text ?? '') + (apAppend ?? ''); + const srcMfm = (note.text ?? ''); const parsed = mfm.parse(srcMfm); - if (!apAppend && parsed?.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) { + if (!additionalAppender.length && parsed.every(n => ['text', 'unicodeEmoji', 'emojiCode', 'mention', 'hashtag', 'url'].includes(n.type))) { noMisskeyContent = true; } - const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers)); + const content = this.mfmService.toHtml(parsed, JSON.parse(note.mentionedRemoteUsers), additionalAppender); return { content, diff --git a/packages/backend/src/core/activitypub/ApRendererService.ts b/packages/backend/src/core/activitypub/ApRendererService.ts index f01874952f..55521d6e3a 100644 --- a/packages/backend/src/core/activitypub/ApRendererService.ts +++ b/packages/backend/src/core/activitypub/ApRendererService.ts @@ -19,7 +19,7 @@ import type { MiEmoji } from '@/models/Emoji.js'; import type { MiPoll } from '@/models/Poll.js'; import type { MiPollVote } from '@/models/PollVote.js'; import { UserKeypairService } from '@/core/UserKeypairService.js'; -import { MfmService } from '@/core/MfmService.js'; +import { MfmService, type Appender } from '@/core/MfmService.js'; import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js'; import type { MiUserKeypair } from '@/models/UserKeypair.js'; @@ -430,10 +430,24 @@ export class ApRendererService { poll = await this.pollsRepository.findOneBy({ noteId: note.id }); } - let apAppend = ''; + const apAppend: Appender[] = []; if (quote) { - apAppend += `\n\nRE: ${quote}`; + // Append quote link as `

RE: ...` + // the claas name `quote-inline` is used in non-misskey clients for styling quote notes. + // For compatibility, the span part should be kept as possible. + apAppend.push((doc, body) => { + body.appendChild(doc.createElement('br')); + body.appendChild(doc.createElement('br')); + const span = doc.createElement('span'); + span.className = 'quote-inline'; + span.appendChild(doc.createTextNode('RE: ')); + const link = doc.createElement('a'); + link.setAttribute('href', quote); + link.textContent = quote; + span.appendChild(link); + body.appendChild(span); + }); } const summary = note.cw === '' ? String.fromCharCode(0x200B) : note.cw; @@ -509,7 +523,7 @@ export class ApRendererService { const urlPart = match[0]; const urlPartParsed = new URL(urlPart); const restPart = maybeUrl.slice(match[0].length); - + return `${urlPart}${restPart}`; } catch (e) { return maybeUrl; From b2e3e658965b52873dd6771cf9771b3032a0ed15 Mon Sep 17 00:00:00 2001 From: anatawa12 Date: Tue, 15 Apr 2025 16:15:27 +0900 Subject: [PATCH 480/649] fix: use ftt for outbox (#15819) * fix: use ftt for outbox * chore: check for enableFanoutTimeline * lint: fix lint --- .../src/core/FanoutTimelineEndpointService.ts | 2 +- .../src/server/ActivityPubServerService.ts | 48 +++++++++++++++---- 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/packages/backend/src/core/FanoutTimelineEndpointService.ts b/packages/backend/src/core/FanoutTimelineEndpointService.ts index b05af99c5e..ce8cc83dfd 100644 --- a/packages/backend/src/core/FanoutTimelineEndpointService.ts +++ b/packages/backend/src/core/FanoutTimelineEndpointService.ts @@ -54,7 +54,7 @@ export class FanoutTimelineEndpointService { } @bindThis - private async getMiNotes(ps: TimelineOptions): Promise { + async getMiNotes(ps: TimelineOptions): Promise { // 呼び出し元と以下の処理をシンプルにするためにdbFallbackを置き換える if (!ps.useDbFallback) ps.dbFallback = () => Promise.resolve([]); diff --git a/packages/backend/src/server/ActivityPubServerService.ts b/packages/backend/src/server/ActivityPubServerService.ts index 72d57a9b1b..f7b22c44c4 100644 --- a/packages/backend/src/server/ActivityPubServerService.ts +++ b/packages/backend/src/server/ActivityPubServerService.ts @@ -32,6 +32,7 @@ import { isQuote, isRenote } from '@/misc/is-renote.js'; import * as Acct from '@/misc/acct.js'; import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify'; import type { FindOptionsWhere } from 'typeorm'; +import { FanoutTimelineEndpointService } from '@/core/FanoutTimelineEndpointService.js'; const ACTIVITY_JSON = 'application/activity+json; charset=utf-8'; const LD_JSON = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"; charset=utf-8'; @@ -75,6 +76,7 @@ export class ActivityPubServerService { private queueService: QueueService, private userKeypairService: UserKeypairService, private queryService: QueryService, + private fanoutTimelineEndpointService: FanoutTimelineEndpointService, ) { //this.createServer = this.createServer.bind(this); } @@ -461,16 +463,28 @@ export class ActivityPubServerService { const partOf = `${this.config.url}/users/${userId}/outbox`; if (page) { - const query = this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId) - .andWhere('note.userId = :userId', { userId: user.id }) - .andWhere(new Brackets(qb => { - qb - .where('note.visibility = \'public\'') - .orWhere('note.visibility = \'home\''); - })) - .andWhere('note.localOnly = FALSE'); - - const notes = await query.limit(limit).getMany(); + const notes = this.meta.enableFanoutTimeline ? await this.fanoutTimelineEndpointService.getMiNotes({ + sinceId: sinceId ?? null, + untilId: untilId ?? null, + limit: limit, + allowPartial: false, // Possibly true? IDK it's OK for ordered collection. + me: null, + redisTimelines: [ + `userTimeline:${user.id}`, + `userTimelineWithReplies:${user.id}`, + ], + useDbFallback: true, + ignoreAuthorFromMute: true, + excludePureRenotes: false, + noteFilter: (note) => { + if (note.visibility !== 'home' && note.visibility !== 'public') return false; + if (note.localOnly) return false; + return true; + }, + dbFallback: async (untilId, sinceId, limit) => { + return await this.getUserNotesFromDb(sinceId, untilId, limit, user.id); + }, + }) : await this.getUserNotesFromDb(sinceId ?? null, untilId ?? null, limit, user.id); if (sinceId) notes.reverse(); @@ -508,6 +522,20 @@ export class ActivityPubServerService { } } + @bindThis + private async getUserNotesFromDb(untilId: string | null, sinceId: string | null, limit: number, userId: MiUser['id']) { + return await this.queryService.makePaginationQuery(this.notesRepository.createQueryBuilder('note'), sinceId, untilId) + .andWhere('note.userId = :userId', { userId }) + .andWhere(new Brackets(qb => { + qb + .where('note.visibility = \'public\'') + .orWhere('note.visibility = \'home\''); + })) + .andWhere('note.localOnly = FALSE') + .limit(limit) + .getMany(); + } + @bindThis private async userInfo(request: FastifyRequest, reply: FastifyReply, user: MiUser | null) { if (this.meta.federation === 'none') { From fff2783c1b8b7d0ce30841e83d917091f40b521b Mon Sep 17 00:00:00 2001 From: Kisaragi <48310258+KisaragiEffective@users.noreply.github.com> Date: Tue, 15 Apr 2025 16:15:56 +0900 Subject: [PATCH 481/649] =?UTF-8?q?docs:=20=E3=83=90=E3=83=83=E3=82=AF?= =?UTF-8?q?=E3=82=A2=E3=83=83=E3=83=97=E3=81=A8=E3=83=AD=E3=82=B0=E3=82=A2?= =?UTF-8?q?=E3=82=A6=E3=83=88=E3=81=AE=E8=A8=AD=E5=AE=9A=E3=82=AF=E3=83=AA?= =?UTF-8?q?=E3=82=A2=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6=E6=9B=B8=E3=81=8D?= =?UTF-8?q?=E6=96=B9=E3=82=92=E5=A4=89=E3=81=88=E3=82=8B=20(#15808)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 「新しいクライアントからログインしたとき」がすでにログインしたことのあるクライアントだとバックアップが必要ないと読めるので「新しい」を外す 2. ログアウトしてから設定データをブラウザから削除したあとで復元できるのはバックアップをとっているときのみであることを強調 cc 1312fe34c1e499bf537f0ee49e6d72683e0101ef --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3214ef936f..f74f92c606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ - プラグイン、テーマ、クライアントに追加されたすべてのアカウント情報も含まれるようになりました - 自動で設定データをサーバーにバックアップできるように - 設定→設定のプロファイル→自動バックアップ で有効にできます - - 新しいデバイスからログインしたり、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能) + - ログインしたとき、ブラウザから設定データが消えてしまったときに自動で復元されます(復元をスキップすることも可能) - 任意の設定項目をデバイス間で同期できるように - 設定項目の「...」メニュー→「デバイス間で同期」 - 同期をオンにした際にサーバーに保存された値とローカルの値が競合する場合はどちらを優先するか選択できます @@ -58,7 +58,7 @@ - アカウントごとに設定値が分離される設定とそうでないクライアント設定が混在していた(かつ分離するかどうかを設定不可だった)のを、基本的に一律でクライアント全体に適用されるようにし、個別でアカウントごとに異なる設定を行えるように - 設定項目の「...」メニュー→「アカウントで上書き」をオンにすることで、設定値をそのアカウントでだけ適用するようにできます - ログアウトすると設定データもブラウザから消去されるようになりプライバシーが向上しました - - 再度ログインすればサーバーのバックアップから設定データを復元可能です + - バックアップを有効にしている場合、ログインした後にバックアップから設定データを復元可能です - エクスポートした設定データを他のサーバーでインポートして適用すること(設定の持ち運び)が可能になりました - 設定情報の移行は自動で行われますが、何らかの理由で失敗した場合、設定→その他→旧設定情報を移行 で再試行可能です - 過去に作成されたバックアップデータとは現在互換性がありませんのでご注意ください From fc6037af461412d914cd35a00fa004ad26d19c0f Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 15 Apr 2025 18:27:45 +0900 Subject: [PATCH 482/649] enhance(backend): push notification for chat message Resolve #15831 --- CHANGELOG.md | 2 +- packages/backend/src/core/ChatService.ts | 4 ++-- .../src/core/PushNotificationService.ts | 1 + packages/sw/src/scripts/create-notification.ts | 18 ++++++++++++++++++ packages/sw/src/scripts/operations.ts | 10 +++++++++- packages/sw/src/sw.ts | 4 ++++ packages/sw/src/types.ts | 1 + 7 files changed, 36 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f74f92c606..81b8f88536 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ ## Unreleased ### General -- +- Enhance: チャットの新規メッセージをプッシュ通知するように ### Client - Feat: チャットウィジェットを追加 diff --git a/packages/backend/src/core/ChatService.ts b/packages/backend/src/core/ChatService.ts index b0e8cfb61c..9d294a80cb 100644 --- a/packages/backend/src/core/ChatService.ts +++ b/packages/backend/src/core/ChatService.ts @@ -232,7 +232,7 @@ export class ChatService { const packedMessageForTo = await this.chatEntityService.packMessageDetailed(inserted, toUser); this.globalEventService.publishMainStream(toUser.id, 'newChatMessage', packedMessageForTo); - //this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo); + this.pushNotificationService.pushNotification(toUser.id, 'newChatMessage', packedMessageForTo); }, 3000); } @@ -302,7 +302,7 @@ export class ChatService { if (marker == null) continue; this.globalEventService.publishMainStream(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo); - //this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo); + this.pushNotificationService.pushNotification(membershipsOtherThanMe[i].userId, 'newChatMessage', packedMessageForTo); } }, 3000); diff --git a/packages/backend/src/core/PushNotificationService.ts b/packages/backend/src/core/PushNotificationService.ts index 1479bb00d9..9333c1ebc5 100644 --- a/packages/backend/src/core/PushNotificationService.ts +++ b/packages/backend/src/core/PushNotificationService.ts @@ -22,6 +22,7 @@ type PushNotificationsTypes = { note: Packed<'Note'>; }; 'readAllNotifications': undefined; + newChatMessage: Packed<'ChatMessage'>; }; // Reduce length because push message servers have character limits diff --git a/packages/sw/src/scripts/create-notification.ts b/packages/sw/src/scripts/create-notification.ts index 364328d4b0..77b3f88791 100644 --- a/packages/sw/src/scripts/create-notification.ts +++ b/packages/sw/src/scripts/create-notification.ts @@ -268,6 +268,24 @@ async function composeNotification(data: PushNotificationDataMap[keyof PushNotif data, renotify: true, }]; + case 'newChatMessage': + if (data.body.toRoom != null) { + return [`${data.body.toRoom.name}: ${getUserName(data.body.fromUser)}: ${data.body.text}`, { + icon: data.body.fromUser.avatarUrl, + badge: iconUrl('messages'), + tag: `chat:room:${data.body.toRoomId}`, + data, + renotify: true, + }]; + } else { + return [`${getUserName(data.body.fromUser)}: ${data.body.text}`, { + icon: data.body.fromUser.avatarUrl, + badge: iconUrl('messages'), + tag: `chat:user:${data.body.fromUserId}`, + data, + renotify: true, + }]; + } default: return null; } diff --git a/packages/sw/src/scripts/operations.ts b/packages/sw/src/scripts/operations.ts index 8862c6faa5..3e72b7e7c2 100644 --- a/packages/sw/src/scripts/operations.ts +++ b/packages/sw/src/scripts/operations.ts @@ -16,7 +16,7 @@ export const cli = new Misskey.api.APIClient({ origin, fetch: (...args): Promise export async function api< E extends keyof Misskey.Endpoints, - P extends Misskey.Endpoints[E]['req'] + P extends Misskey.Endpoints[E]['req'], >(endpoint: E, userId?: string, params?: P): Promise | undefined> { let account: Pick | undefined; @@ -60,6 +60,14 @@ export function openAntenna(antennaId: string, loginId: string): ReturnType { + if (body.toRoomId != null) { + return openClient('push', `/chat/room/${body.toRoomId}`, loginId, { body }); + } else { + return openClient('push', `/chat/user/${body.toUserId}`, loginId, { body }); + } +} + // post-formのオプションから投稿フォームを開く export async function openPost(options: { initialText?: string; reply?: Misskey.entities.Note; renote?: Misskey.entities.Note }, loginId?: string): ReturnType { // クエリを作成しておく diff --git a/packages/sw/src/sw.ts b/packages/sw/src/sw.ts index bf980b83a4..298af4b4b6 100644 --- a/packages/sw/src/sw.ts +++ b/packages/sw/src/sw.ts @@ -76,6 +76,7 @@ globalThis.addEventListener('push', ev => { // case 'driveFileCreated': case 'notification': case 'unreadAntennaNote': + case 'newChatMessage': // 1日以上経過している場合は無視 if (Date.now() - data.dateTime > 1000 * 60 * 60 * 24) break; @@ -155,6 +156,9 @@ globalThis.addEventListener('notificationclick', (ev: ServiceWorkerGlobalScopeEv case 'unreadAntennaNote': client = await swos.openAntenna(data.body.antenna.id, loginId); break; + case 'newChatMessage': + client = await swos.openChat(data.body, loginId); + break; default: switch (action) { case 'markAllAsRead': diff --git a/packages/sw/src/types.ts b/packages/sw/src/types.ts index 4f82779808..549220396c 100644 --- a/packages/sw/src/types.ts +++ b/packages/sw/src/types.ts @@ -23,6 +23,7 @@ type PushNotificationDataSourceMap = { note: Misskey.entities.Note; }; readAllNotifications: undefined; + newChatMessage: Misskey.entities.ChatMessage; }; export type PushNotificationData = { From 45d65ffbba1145870686c0f8c7799ce900e98a9a Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 15 Apr 2025 18:29:22 +0900 Subject: [PATCH 483/649] New Crowdin updates (#15786) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Spanish) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Catalan) * New translations ja-jp.yml (German) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Korean) * New translations ja-jp.yml (Chinese Simplified) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (English) --- locales/ca-ES.yml | 19 +++++++++++-------- locales/de-DE.yml | 2 ++ locales/en-US.yml | 2 ++ locales/es-ES.yml | 39 +++++++++++++++++++++++++++++++++++++++ locales/it-IT.yml | 19 ++++++++++++++----- locales/ko-KR.yml | 24 +++++++++++++----------- locales/zh-CN.yml | 3 +++ locales/zh-TW.yml | 8 ++++++-- 8 files changed, 90 insertions(+), 26 deletions(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 8f83a33356..129c3d24a5 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -356,7 +356,7 @@ banner: "Bàner" displayOfSensitiveMedia: "Visualització de contingut sensible" whenServerDisconnected: "Quan es perdi la connexió al servidor" disconnectedFromServer: "Desconnectat pel servidor" -reload: "Actualitza" +reload: "Actualitzar" doNothing: "Ignora" reloadConfirm: "Vols recarregar?" watch: "Veure" @@ -708,7 +708,7 @@ notificationSetting: "Paràmetres de notificacions" notificationSettingDesc: "Selecciona els tipus de notificacions que es mostraran" useGlobalSetting: "Fer servir la configuració global" useGlobalSettingDesc: "Si s'activa, es farà servir la configuració de notificacions del teu comte. Si no s'activa es poden fer configuracions individuals." -other: "Altre" +other: "Altres" regenerateLoginToken: "Regenerar clau de seguretat d'inici de sessió" regenerateLoginTokenDescription: "Regenera la clau de seguretat que es fa servir internament durant l'inici de sessió. Normalment aquesta acció no és necessària. Si es regenera es tancarà la sessió a tots els dispositius amb una sessió activa." theKeywordWhenSearchingForCustomEmoji: "Cercar un emoji personalitzat " @@ -979,6 +979,7 @@ document: "Documentació" numberOfPageCache: "Nombre de pàgines a la memòria cau" numberOfPageCacheDescription: "Incrementant aquest nombre farà que millori l'experiència de l'usuari, però es farà servir més memòria al dispositiu de l'usuari." logoutConfirm: "Vols sortir?" +logoutWillClearClientData: "En tancar la sessió, la informació del client al navegador s'esborrarà. Per garantir que la informació de configuració es pugui restaurar en tornar a iniciar sessió activa la còpia de seguretat automàtica de la configuració." lastActiveDate: "Fet servir per última vegada" statusbar: "Barra d'estat" pleaseSelect: "Selecciona una opció" @@ -1334,14 +1335,14 @@ postForm: "Formulari de publicació" textCount: "Nombre de caràcters " information: "Informació" chat: "Xat" -migrateOldSettings: "Migració de la configuració antiga " +migrateOldSettings: "Migrar la configuració anterior" migrateOldSettings_description: "Normalment això es fa automàticament, però si la transició no es fa, el procés es pot iniciar manualment. S'esborrarà la configuració actual." compress: "Comprimir " right: "Dreta" bottom: "A baix " top: "A dalt " embed: "Incrustar" -settingsMigrating: "Estem fent la migració de la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard i manualment anant a Preferències → Altres configuracions → Migrar configuració antiga)" +settingsMigrating: "Estem migrant la teva configuració. Si us plau espera un moment... (També pots fer la migració més tard, manualment, anant a Preferències → Altres → Migrar configuració antiga)" readonly: "Només lectura" goToDeck: "Tornar al tauler" _chat: @@ -1359,7 +1360,7 @@ _chat: noInvitations: "No tens cap invitació " history: "Historial de converses " noHistory: "No hi ha un registre previ" - noRooms: "No hi ha habitacions" + noRooms: "No hi ha cap sala" inviteUser: "Invitar usuaris" sentInvitations: "Enviar invitacions" join: "Afegir-se " @@ -1417,8 +1418,8 @@ _settings: makeEveryTextElementsSelectable_description: "L'activació pot reduir la usabilitat en determinades ocasions." useStickyIcons: "Utilitza icones fixes" showNavbarSubButtons: "Mostrar sub botons a la barra de navegació " - ifOn: "Quan s'encén " - ifOff: "Quan s'apaga " + ifOn: "Quan s'activa" + ifOff: "Quan es desactiva" enableSyncThemesBetweenDevices: "Sincronitzar els temes instal·lats entre dispositius" _chat: showSenderName: "Mostrar el nom del remitent" @@ -1604,7 +1605,7 @@ _accountMigration: moveTo: "Migrar aquest compte a un altre" moveToLabel: "Compte al qual es vol migrar:" moveCannotBeUndone: "Les migracions dels comptes no es poden desfer." - moveAccountDescription: "Això migrarà la teva compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)" + moveAccountDescription: "Això migrarà el teu compte a un altre diferent.\n ・Els seguidors d'aquest compte és passaran al compte nou de forma automàtica\n ・Es deixaran de seguir a tots els usuaris que es segueixen actualment en aquest compte\n ・No es poden crear notes noves, etc. en aquest compte\n\nSi bé la migració de seguidors es automàtica, has de preparar alguns pasos manualment per migrar la llista d'usuaris que segueixes. Per fer això has d'exportar els seguidors que després importaraes al compte nou mitjançant el menú de configuració. El mateix procediment s'ha de seguir per less teves llistes i els teus usuaris silenciats i bloquejats.\n\n(Aquesta explicació s'aplica a Misskey v13.12.0 i posteriors. Altres aplicacions, com Mastodon, poden funcionar diferent.)" moveAccountHowTo: "Per fer la migració, primer has de crear un àlies per aquest compte al compte al qual vols migrar.\nDesprés de crear l'àlies, introdueix el compte al qual vols migrar amb el format següent: @nomusuari@servidor.exemple.com" startMigration: "Migrar" migrationConfirm: "Vols migrar aquest compte a {account}? Una vegada comenci la migració no es podrà parar O fer marxa enrere i no podràs tornar a fer servir aquest compte mai més." @@ -2368,6 +2369,7 @@ _widgets: chooseList: "Tria una llista" clicker: "Clicker" birthdayFollowings: "Usuaris que fan l'aniversari avui" + chat: "Xat" _cw: hide: "Amagar" show: "Carregar més" @@ -2634,6 +2636,7 @@ _deck: mentions: "Mencions" direct: "Publicacions directes" roleTimeline: "Línia de temps dels rols" + chat: "Xat" _dialog: charactersExceeded: "Has arribat al màxim de caràcters! Actualment és {current} de {max}" charactersBelow: "Ets per sota del mínim de caràcters! Actualment és {current} de {min}" diff --git a/locales/de-DE.yml b/locales/de-DE.yml index b953a5717e..237603299c 100644 --- a/locales/de-DE.yml +++ b/locales/de-DE.yml @@ -2368,6 +2368,7 @@ _widgets: chooseList: "Liste auswählen" clicker: "Klickzähler" birthdayFollowings: "Nutzer, die heute Geburtstag haben" + chat: "Chat" _cw: hide: "Inhalt verbergen" show: "Inhalt anzeigen" @@ -2634,6 +2635,7 @@ _deck: mentions: "Erwähnungen" direct: "Direktnachrichten" roleTimeline: "Rollenchronik" + chat: "Chat" _dialog: charactersExceeded: "Maximallänge überschritten! Momentan {current} von {max}" charactersBelow: "Minimallänge unterschritten! Momentan {current} von {min}" diff --git a/locales/en-US.yml b/locales/en-US.yml index 02cc24a8b3..533682fd4f 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -2368,6 +2368,7 @@ _widgets: chooseList: "Select a list" clicker: "Clicker" birthdayFollowings: "Today's Birthdays" + chat: "Chat" _cw: hide: "Hide" show: "Show content" @@ -2634,6 +2635,7 @@ _deck: mentions: "Mentions" direct: "Direct notes" roleTimeline: "Role Timeline" + chat: "Chat" _dialog: charactersExceeded: "You've exceeded the maximum character limit! Currently at {current} of {max}." charactersBelow: "You're below the minimum character limit! Currently at {current} of {min}." diff --git a/locales/es-ES.yml b/locales/es-ES.yml index f60e9beabe..713478b67e 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -301,6 +301,7 @@ uploadFromUrlMayTakeTime: "Subir el fichero puede tardar un tiempo." explore: "Explorar" messageRead: "Ya leído" noMoreHistory: "El historial se ha acabado" +startChat: "Nuevo Chat" nUsersRead: "Leído por {n} personas" agreeTo: "De acuerdo con {0}" agree: "De acuerdo." @@ -694,6 +695,7 @@ userSaysSomethingAbout: "{name} dijo algo sobre {word}" makeActive: "Activar" display: "Apariencia" copy: "Copiar" +copiedToClipboard: "Texto copiado al portapapeles" metrics: "Métricas" overview: "Resumen" logs: "Registros" @@ -1293,18 +1295,55 @@ passkeyVerificationFailed: "La verificación de la clave de acceso ha fallado." passkeyVerificationSucceededButPasswordlessLoginDisabled: "La verificación de la clave de acceso ha sido satisfactoria pero se ha deshabilitado el inicio de sesión sin contraseña." messageToFollower: "Mensaje a seguidores" target: "Para" +prohibitedWordsForNameOfUser: "Palabras prohibidas para nombres de usuario" +prohibitedWordsForNameOfUserDescription: "Si alguna de las cadenas de esta lista está incluida en el nombre del usuario, el nombre será denegado. Los usuarios con privilegios de moderador no se ven afectados por esta restricción." +yourNameContainsProhibitedWords: "Tu nombre contiene palabras prohibidas" +yourNameContainsProhibitedWordsDescription: "Si deseas usar este nombre, por favor contacta con tu administrador/a de tu servidor" +lockdown: "Bloqueo" +pleaseSelectAccount: "Seleccione una cuenta, por favor." +availableRoles: "Roles disponibles " +acknowledgeNotesAndEnable: "Activar después de comprender las precauciones" federationSpecified: "Este servidor opera en una federación de listas blancas. No puede interactuar con otros servidores que no sean los especificados por el administrador." federationDisabled: "La federación está desactivada en este servidor. No puede interactuar con usuarios de otros servidores" preferences: "Preferencias" postForm: "Formulario" information: "Información" +right: "Derecha" +bottom: "Abajo" +top: "Arriba" +embed: "Insertar" +settingsMigrating: "La configuración está siendo migrada, por favor espera un momento... (También puedes migrar manualmente más tarde yendo a Ajustes otros migrar configuración antigua" +readonly: "Solo Lectura" _chat: + noMessagesYet: "Aún no hay mensajes" + newMessage: "Mensajes nuevos" + individualChat: "Chat individual" + individualChat_description: "Mantén una conversación privada con otra persona." invitations: "Invitar" noHistory: "No hay datos en el historial" members: "Miembros" home: "Inicio" send: "Enviar" + chatNotAvailableInOtherAccount: "La función de chat está desactivada para el otro usuario." + cannotChatWithTheUser: "No se puede iniciar un chat con este usuario" + cannotChatWithTheUser_description: "El chat no está disponible o la otra parte no ha habilitado el chat." + chatWithThisUser: "Chatear" + thisUserAllowsChatOnlyFromFollowers: "Este usuario sólo acepta chats de seguidores." + thisUserAllowsChatOnlyFromFollowing: "Este usuario sólo acepta chats de los usuarios a los que sigue." + thisUserAllowsChatOnlyFromMutualFollowing: "Este usuario sólo acepta chats de usuarios que son seguidores mutuos." + thisUserNotAllowedChatAnyone: "Este usuario no acepta chats de nadie." + chatAllowedUsers: "A quién permitir chatear." + chatAllowedUsers_note: "Puedes chatear con cualquier persona a la que hayas enviado un mensaje de chat, independientemente de esta configuración." + _chatAllowedUsers: + everyone: "Todos" + followers: "Sólo sus propios seguidores." + following: "Solo usuarios que sigues" + mutual: "Solo seguidores mutuos" + none: "Nadie" +_emojiPalette: + palettes: "Paleta\n" _settings: + api: "API" webhook: "Webhook" _accountSettings: requireSigninToViewContents: "Se requiere iniciar sesión para ver el contenido" diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 44b0858fe8..75691d817f 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -424,6 +424,7 @@ antennaExcludeBots: "Escludere i Bot" antennaKeywordsDescription: "Sparando con uno spazio indichi la condizione E (and). Separando con un a capo, indichi la condizione O (or)." notifyAntenna: "Invia notifiche delle nuove note" withFileAntenna: "Solo note con file in allegato" +excludeNotesInSensitiveChannel: "Escludere le Note dai canali espliciti" enableServiceworker: "Abilita ServiceWorker" antennaUsersDescription: "Elenca un nome utente per riga" caseSensitive: "Sensibile alla distinzione tra maiuscole e minuscole" @@ -727,7 +728,7 @@ reporterOrigin: "Segnalazione da" send: "Inviare" openInNewTab: "Apri in una nuova scheda" openInSideView: "Apri in vista laterale" -defaultNavigationBehaviour: "Navigazione preimpostata" +defaultNavigationBehaviour: "Tipo di navigazione predefinita" editTheseSettingsMayBreakAccount: "Modificare queste impostazioni può danneggiare il profilo" instanceTicker: "Informazioni sull'istanza da cui vengono le note" waitingFor: "Aspettando {x}" @@ -866,7 +867,7 @@ noBotProtectionWarning: "Non è stata impostata alcuna protezione dai Bot" configure: "Imposta" postToGallery: "Pubblicare nella galleria" postToHashtag: "Pubblica a questo hashtag" -gallery: "Galleria" +gallery: "Gallerie" recentPosts: "Pubblicazioni recenti" popularPosts: "Le più visualizzate" shareWithNote: "Condividere in nota" @@ -978,6 +979,7 @@ document: "Documentazione" numberOfPageCache: "Numero di pagine cache" numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria." logoutConfirm: "Vuoi davvero uscire da Misskey? " +logoutWillClearClientData: "All'uscita, la configurazione del client viene rimossa dal browser. Per ripristinarla quando si effettua nuovamente l'accesso, abilitare il backup automatico." lastActiveDate: "Data dell'ultimo utilizzo" statusbar: "Barra di stato" pleaseSelect: "Scegli un'opzione" @@ -1340,6 +1342,9 @@ right: "Destra" bottom: "Sotto" top: "Sopra" embed: "Incorporare" +settingsMigrating: "Migrazione delle impostazioni. Attendere prego ... (Puoi anche migrare manualmente in un secondo momento, nel menu: Impostazioni → Altro → Migrazione delle impostazioni)" +readonly: "Sola lettura" +goToDeck: "Torna al Deck" _chat: noMessagesYet: "Ancora nessun messaggio" newMessage: "Nuovo messaggio" @@ -1369,6 +1374,7 @@ _chat: muteThisRoom: "Silenzia stanza" deleteRoom: "Elimina stanza" chatNotAvailableForThisAccountOrServer: "Questo server, o questo profilo ha disabilitato la chat." + chatIsReadOnlyForThisAccountOrServer: "Le chat, su questo server o su questo profilo, sono di sola lettura. Impossibile scrivere in chat o creare e partecipare a stanze." chatNotAvailableInOtherAccount: "La chat non è disponibile nel profilo dell'altra persona." cannotChatWithTheUser: "Impossibile chattare con questa persona" cannotChatWithTheUser_description: "La chat potrebbe non essere disponibile, oppure l'altra persona potrebbe non esserlo." @@ -1929,6 +1935,7 @@ _role: canImportFollowing: "Può importare Following" canImportMuting: "Può importare Silenziati" canImportUserLists: "Può importare liste di Profili" + chatAvailability: "Chat consentita" _condition: roleAssignedTo: "Assegnato a ruoli manualmente" isLocal: "Profilo locale" @@ -2362,6 +2369,7 @@ _widgets: chooseList: "Seleziona una lista" clicker: "Cliccheria" birthdayFollowings: "Compleanni del giorno" + chat: "Chat" _cw: hide: "Nascondere" show: "Continua la lettura..." @@ -2594,8 +2602,8 @@ _notification: renote: "Rinota" _deck: alwaysShowMainColumn: "Mostra sempre la colonna principale" - columnAlign: "Allineare colonne" - columnGap: "Margine tra le colonne" + columnAlign: "Allineamento delle colonne" + columnGap: "Spessore del margine tra colonne" deckMenuPosition: "Posizione del menu Deck" navbarPosition: "Posizione barra di navigazione" addColumn: "Aggiungi colonna" @@ -2624,10 +2632,11 @@ _deck: tl: "Timeline" antenna: "Antenne" list: "Liste" - channel: "Canale" + channel: "Canali" mentions: "Menzioni" direct: "Note Dirette" roleTimeline: "Timeline Ruolo" + chat: "Chat" _dialog: charactersExceeded: "Hai superato il limite di {max} caratteri! ({current})" charactersBelow: "Sei al di sotto del minimo di {min} caratteri! ({current})" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index fc578758a2..fb7db80186 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -489,7 +489,7 @@ next: "다음" retype: "다시 입력" noteOf: "{user}의 노트" quoteAttached: "인용함" -quoteQuestion: "인용해서 작성하시겠습니까?" +quoteQuestion: "인용해서 첨부하시겠습니까?" attachAsFileQuestion: "붙여넣으려는 글이 너무 깁니다. 텍스트 파일로 첨부하시겠습니까?" onlyOneFileCanBeAttached: "메시지에 첨부할 수 있는 파일은 하나까지입니다" signinRequired: "진행하기 전에 로그인을 해 주세요" @@ -571,8 +571,8 @@ objectStorageSetPublicRead: "업로드할 때 'public-read'를 설정하기" s3ForcePathStyleDesc: "s3ForcePathStyle을 활성화하면, 버킷 이름을 URL의 호스트명이 아닌 경로의 일부로써 취급합니다. 셀프 호스트 Minio와 같은 서비스를 사용할 경우 활성화해야 할 수 있습니다." serverLogs: "서버 로그" deleteAll: "모두 삭제" -showFixedPostForm: "타임라인 상단에 글 작성란을 표시" -showFixedPostFormInChannel: "채널 타임라인 상단에 글 작성란을 표시" +showFixedPostForm: "타임라인 상단에 글 입력란을 표시" +showFixedPostFormInChannel: "채널 타임라인 상단에 글 입력란을 표시" withRepliesByDefaultForNewlyFollowed: "팔로우 할 때 기본적으로 답글을 타임라인에 나오게 하기" newNoteRecived: "새 노트가 있습니다" sounds: "소리" @@ -720,7 +720,7 @@ abuseReports: "신고" reportAbuse: "신고" reportAbuseRenote: "리노트 신고하기" reportAbuseOf: "{name} 신고하기" -fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요." +fillAbuseReportDescription: "신고 사유를 자세히 기재해 주세요. 대상 노트나 페이지 등이 있는 경우에는 해당 URL도 기재해 주세요." abuseReported: "신고를 보냈습니다. 신고해 주셔서 감사합니다." reporter: "신고자" reporteeOrigin: "피신고자" @@ -825,7 +825,7 @@ editCode: "코드 수정" apply: "적용" receiveAnnouncementFromInstance: "이 서버의 알림을 이메일로 수신할게요" emailNotification: "메일 알림" -publish: "게시" +publish: "공개" inChannelSearch: "채널에서 검색" useReactionPickerForContextMenu: "우클릭하여 리액션 선택기 열기" typingUsers: "{users}님이 입력 중" @@ -1081,7 +1081,7 @@ sensitiveWords: "민감한 단어" sensitiveWordsDescription: "설정한 단어가 포함된 노트의 공개 범위를 '홈'으로 강제합니다. 개행으로 구분하여 여러 개를 지정할 수 있습니다." sensitiveWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다." prohibitedWords: "금지 단어" -prohibitedWordsDescription: "설정된 단어가 포함되는 노트를 작성하려고 하면, 오류가 발생하도록 합니다. 줄바꿈으로 구분지어 복수 설정할 수 있습니다." +prohibitedWordsDescription: "설정된 단어가 포함되는 노트를 게시하려고 하면, 오류가 발생하도록 합니다. 줄바꿈으로 구분지어 복수 설정할 수 있습니다." prohibitedWordsDescription2: "공백으로 구분하면 AND 지정이 되며, 키워드를 슬래시로 둘러싸면 정규 표현식이 됩니다." hiddenTags: "숨긴 해시태그" hiddenTagsDescription: "설정한 태그를 트렌드에 표시하지 않도록 합니다. 줄 바꿈으로 하나씩 나눠서 설정할 수 있습니다." @@ -1373,7 +1373,7 @@ _chat: muteThisRoom: "이 룸을 뮤트" deleteRoom: "룸을 삭제" chatNotAvailableForThisAccountOrServer: "이 서버 또는 이 계정에서 채팅이 활성화되어 있지 않습니다." - chatIsReadOnlyForThisAccountOrServer: "이 서버 또는 이 계정에서 채팅은 읽기 전용입니다. 새로 쓰거나 채팅방을 만들거나 참가할 수 없습니다." + chatIsReadOnlyForThisAccountOrServer: "이 서버 또는 이 계정에서 채팅은 읽기 전용입니다. 새로 쓰거나 채팅 룸을 만들거나 참가할 수 없습니다." chatNotAvailableInOtherAccount: "상대방 계정에서 채팅 기능을 사용할 수 없는 상태입니다." cannotChatWithTheUser: "이 유저와 채팅을 시작할 수 없습니다" cannotChatWithTheUser_description: "채팅을 사용할 수 없는 상태이거나 상대방이 채팅을 열지 않은 상태입니다." @@ -1542,7 +1542,7 @@ _initialTutorial: description3: "이 외에도, '리스트 타임라인'이나 '채널 타임라인' 등이 있습니다. 자세한 사항은 {link}에서 확인하실 수 있습니다." _postNote: title: "노트 게시 설정" - description1: "Misskey에 노트를 쓸 때에는 다양한 옵션을 설정할 수 있습니다. 노트를 작성하는 화면은 이렇게 생겼습니다." + description1: "Misskey에 노트를 게시할 때에는 다양한 옵션 설정이 가능합니다. 노트를 게시할 때 쓰이는 '글 입력란'은 이렇게 생겼습니다." _visibility: description: "노트를 볼 수 있는 사람을 제한할 수 있습니다." public: "모든 유저에게 공개합니다." @@ -1562,7 +1562,7 @@ _initialTutorial: _howToMakeAttachmentsSensitive: title: "첨부 파일을 열람주의로 설정하려면?" description: "서버의 가이드라인에 따라 필요한 이미지, 또는 그대로 노출되기에 부적절한 미디어는 '열람 주의'를 설정해 주세요." - tryThisFile: "이 작성 창에 첨부된 이미지를 열람 주의로 설정해 보세요!" + tryThisFile: "이 입력란에 첨부된 이미지를 열람 주의로 설정해 보세요!" _exampleNote: note: "낫또 뚜껑 뜯다가 실수했다…" method: "첨부 파일을 열람 주의로 설정하려면, 해당 파일을 클릭하여 메뉴를 열고, '열람주의로 설정'을 클릭합니다." @@ -1816,7 +1816,7 @@ _achievements: description: "드라이브 폴더에 스스로를 넣게 했다" _reactWithoutRead: title: "읽고 답하긴 하시는 건가요?" - description: "100자가 넘는 노트를 작성한 지 3초 안에 리액션했다" + description: "100자가 넘는 노트를 게시한 지 3초 안에 리액션했다" _clickedClickHere: title: "여길 눌러보세요" description: "여기를 눌렀다" @@ -1845,7 +1845,7 @@ _achievements: _cookieClicked: title: "쿠키를 클릭하는 게임" description: "쿠키를 클릭했다" - flavor: "소프트웨어 착각하지 않았어?" + flavor: "소프트웨어 착각하지 않으셨나요?" _brainDiver: title: "Brain Diver" description: "Brain Diver로의 링크를 첨부했다" @@ -2368,6 +2368,7 @@ _widgets: chooseList: "리스트 선택" clicker: "클리커" birthdayFollowings: "오늘이 생일인 유저" + chat: "채팅" _cw: hide: "숨기기" show: "더 보기" @@ -2634,6 +2635,7 @@ _deck: mentions: "받은 멘션" direct: "다이렉트" roleTimeline: "역할 타임라인" + chat: "채팅" _dialog: charactersExceeded: "최대 글자수를 초과하였습니다! 현재 {current} / 최대 {max}" charactersBelow: "최소 글자수 미만입니다! 현재 {current} / 최소 {min}" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index b313c4ce1f..4b78b0a362 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -979,6 +979,7 @@ document: "文档" numberOfPageCache: "缓存页数" numberOfPageCacheDescription: "设置较高的值会更方便用户,但设备的负载和内存使用量会增加。" logoutConfirm: "是否确认登出?" +logoutWillClearClientData: "登出时将会从浏览器中删除客户端的设置信息。如果想要在再次登入时恢复设置信息,请在设置里打开自动备份。" lastActiveDate: "最后活跃时间" statusbar: "状态栏" pleaseSelect: "请选择" @@ -2367,6 +2368,7 @@ _widgets: chooseList: "选择列表" clicker: "点击器" birthdayFollowings: "今天是他们的生日" + chat: "聊天" _cw: hide: "隐藏" show: "查看更多" @@ -2633,6 +2635,7 @@ _deck: mentions: "提及" direct: "指定用户" roleTimeline: "角色时间线" + chat: "聊天" _dialog: charactersExceeded: "已经超过了最大字符数! 当前字符数 {current} / 限制字符数 {max}" charactersBelow: "低于最小字符数!当前字符数 {current} / 限制字符数 {min}" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index 57b7e84b8a..cfe3b729f0 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -424,6 +424,7 @@ antennaExcludeBots: "排除機器人帳戶" antennaKeywordsDescription: "空格代表「以及」(AND),換行代表「或者」(OR)" notifyAntenna: "通知有新貼文" withFileAntenna: "僅帶有附件的貼文" +excludeNotesInSensitiveChannel: "排除敏感頻道的貼文" enableServiceworker: "啟用瀏覽器的推播通知" antennaUsersDescription: "填寫使用者名稱,以換行分隔" caseSensitive: "區分大小寫" @@ -978,6 +979,7 @@ document: "文件" numberOfPageCache: "快取頁面數" numberOfPageCacheDescription: "增加數量會提高便利性,但也會增加負荷與記憶體使用量。" logoutConfirm: "確定要登出嗎?" +logoutWillClearClientData: "當您登出時,客戶端的設定資訊將從瀏覽器中清除。為了能夠在重新登入時恢復您的設定資訊,請啟用設定內的自動備份選項。" lastActiveDate: "上次使用日期及時間" statusbar: "狀態列" pleaseSelect: "請選擇" @@ -1307,7 +1309,7 @@ availableRoles: "可用角色" acknowledgeNotesAndEnable: "了解注意事項後再開啟。" federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管理員指定的伺服器外,它無法與其他伺服器互動。" federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。" -confirmOnReact: "反應時確認" +confirmOnReact: "在做出反應前先確認" reactAreYouSure: "用「 {emoji} 」反應嗎?" markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?" unmarkAsSensitiveConfirm: "要解除這個媒體的敏感設定嗎?" @@ -1444,7 +1446,7 @@ _accountSettings: makeNotesHiddenBefore: "隱藏過去的貼文" makeNotesHiddenBeforeDescription: "啟用此功能後,超過設定的日期和時間或超過設定時間的貼文將僅對自己顯示(私密化)。 如果您再次停用它,貼文的公開狀態也會恢復原狀。" mayNotEffectForFederatedNotes: "聯邦發送至遠端伺服器的貼文可能會不受影響。" - mayNotEffectSomeSituations: "這些限制已經簡化。它們可能不適用於某些情況,例如在遠端伺服器上檢視或管理時。" + mayNotEffectSomeSituations: "這些限制僅是簡化版本。在某些情況下,例如在遠端伺服器上瀏覽或進行審核時,可能不會套用這些限制。" notesHavePassedSpecifiedPeriod: "早於指定時間的貼文" notesOlderThanSpecifiedDateAndTime: "指定時間和日期之前的貼文" _abuseUserReport: @@ -2366,6 +2368,7 @@ _widgets: chooseList: "選擇清單" clicker: "點擊器" birthdayFollowings: "今天生日的使用者" + chat: "聊天" _cw: hide: "隱藏" show: "顯示內容" @@ -2632,6 +2635,7 @@ _deck: mentions: "提及" direct: "指定使用者" roleTimeline: "角色時間軸" + chat: "聊天" _dialog: charactersExceeded: "您的貼文太長了!現時字數 {current}/限制字數 {max}" charactersBelow: "您的貼文太短了!現時字數 {current}/限制字數 {min}" From f5a89c253347eb78977e2d7adb3ba8998f5ebe7c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 15 Apr 2025 09:32:12 +0000 Subject: [PATCH 484/649] Bump version to 2025.4.1-alpha.0 --- CHANGELOG.md | 2 +- package.json | 2 +- packages/misskey-js/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b8f88536..97c754a86b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Unreleased +## 2025.4.1 ### General - Enhance: チャットの新規メッセージをプッシュ通知するように diff --git a/package.json b/package.json index 3e59baf982..88dfe766a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.4.0", + "version": "2025.4.1-alpha.0", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index 64ac05e9a1..189826177a 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.4.0", + "version": "2025.4.1-alpha.0", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From ee29f31324ca3b0513325cbb14b25a59e6485d23 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:33:04 +0900 Subject: [PATCH 485/649] fix(frontend): make keep scroll pos of timeline --- CHANGELOG.md | 1 + .../src/use/use-scroll-position-keeper.ts | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 packages/frontend/src/use/use-scroll-position-keeper.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 97c754a86b..693b31c44a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ - Fix: ログアウトした際に処理が終了しない問題を修正 - Fix: 自動バックアップが設定されている環境でログアウト直前に設定をバックアップするように - Fix: フォルダを開いた状態でメニューからアップロードしてもルートフォルダにアップロードされる問題を修正 #15836 +- Fix: タイムラインのスクロール位置を記憶するように修正 ### Server - Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように diff --git a/packages/frontend/src/use/use-scroll-position-keeper.ts b/packages/frontend/src/use/use-scroll-position-keeper.ts new file mode 100644 index 0000000000..00cc51a459 --- /dev/null +++ b/packages/frontend/src/use/use-scroll-position-keeper.ts @@ -0,0 +1,58 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { throttle } from 'throttle-debounce'; +import { nextTick, onActivated, onUnmounted, watch } from 'vue'; +import type { Ref } from 'vue'; + +// note render skippingがオンだとズレるため、遷移直前にスクロール範囲に表示されているdata-scroll-anchor要素を特定して、復元時に当該要素までスクロールするようにする + +export function useScrollPositionKeeper(scrollContainerRef: Ref): void { + let anchorId: string | null = null; + + watch(scrollContainerRef, (el) => { + if (!el) return; + + const onScroll = () => { + if (!el) return; + const scrollContainerRect = el.getBoundingClientRect(); + const viewPosition = scrollContainerRect.height / 2; + + const anchorEls = el.querySelectorAll('[data-scroll-anchor]'); + for (let i = anchorEls.length - 1; i > -1; i--) { // 下から見た方が速い + const anchorEl = anchorEls[i] as HTMLElement; + const anchorRect = anchorEl.getBoundingClientRect(); + const anchorTop = anchorRect.top; + const anchorBottom = anchorRect.bottom; + if (anchorTop <= viewPosition && anchorBottom >= viewPosition) { + anchorId = anchorEl.getAttribute('data-scroll-anchor'); + break; + } + } + }; + + // ほんとはscrollイベントじゃなくてonBeforeDeactivatedでやりたい + // https://github.com/vuejs/vue/issues/9454 + // https://github.com/vuejs/rfcs/pull/284 + el.addEventListener('scroll', throttle(1000, onScroll), { passive: true }); + }, { + immediate: true, + }); + + onActivated(() => { + nextTick(() => { + if (!anchorId) return; + const scrollContainer = scrollContainerRef.value; + if (!scrollContainer) return; + const scrollAnchorEl = scrollContainer.querySelector(`[data-scroll-anchor="${anchorId}"]`); + if (!scrollAnchorEl) return; + scrollAnchorEl.scrollIntoView({ + behavior: 'instant', + block: 'center', + inline: 'center', + }); + }); + }); +} From 165830d6c8331f14da455cedcb4cd695aaa6c9b3 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:34:00 +0900 Subject: [PATCH 486/649] =?UTF-8?q?=E3=82=B3=E3=83=9F=E3=83=83=E3=83=88?= =?UTF-8?q?=E5=BF=98=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/components/MkNotes.vue | 4 ++-- packages/frontend/src/pages/timeline.vue | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/components/MkNotes.vue b/packages/frontend/src/components/MkNotes.vue index ad6210816d..214d52ec7f 100644 --- a/packages/frontend/src/components/MkNotes.vue +++ b/packages/frontend/src/components/MkNotes.vue @@ -23,13 +23,13 @@ SPDX-License-Identifier: AGPL-3.0-only tag="div" > diff --git a/packages/frontend/src/pages/timeline.vue b/packages/frontend/src/pages/timeline.vue index 644b2d3d13..d2bf162ce5 100644 --- a/packages/frontend/src/pages/timeline.vue +++ b/packages/frontend/src/pages/timeline.vue @@ -52,12 +52,15 @@ import { miLocalStorage } from '@/local-storage.js'; import { availableBasicTimelines, hasWithReplies, isAvailableBasicTimeline, isBasicTimeline, basicTimelineIconClass } from '@/timelines.js'; import { prefer } from '@/preferences.js'; import { useRouter } from '@/router.js'; +import { useScrollPositionKeeper } from '@/use/use-scroll-position-keeper.js'; provide('shouldOmitHeaderTitle', true); const tlComponent = useTemplateRef('tlComponent'); const rootEl = useTemplateRef('rootEl'); +useScrollPositionKeeper(rootEl); + const router = useRouter(); router.useListener('same', () => { top(); From de19d9a4d429b4ce9d4713e647659fe6460bdd11 Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 15 Apr 2025 20:48:25 +0900 Subject: [PATCH 487/649] refactor(frontend): MkHorizontalSwipe -> MkSwiper --- .../src/components/{MkHorizontalSwipe.vue => MkSwiper.vue} | 0 packages/frontend/src/pages/about.vue | 6 +++--- packages/frontend/src/pages/announcements.vue | 6 +++--- packages/frontend/src/pages/channel.vue | 6 +++--- packages/frontend/src/pages/channels.vue | 6 +++--- packages/frontend/src/pages/chat/home.vue | 6 +++--- packages/frontend/src/pages/drive.file.vue | 6 +++--- packages/frontend/src/pages/explore.vue | 6 +++--- packages/frontend/src/pages/flash/flash-index.vue | 6 +++--- packages/frontend/src/pages/follow-requests.vue | 6 +++--- packages/frontend/src/pages/gallery/index.vue | 6 +++--- packages/frontend/src/pages/instance-info.vue | 6 +++--- packages/frontend/src/pages/my-clips/index.vue | 6 +++--- packages/frontend/src/pages/notifications.vue | 2 +- packages/frontend/src/pages/pages.vue | 6 +++--- packages/frontend/src/pages/search.vue | 6 +++--- packages/frontend/src/pages/user/index.vue | 6 +++--- packages/frontend/src/utility/touch.ts | 2 +- 18 files changed, 47 insertions(+), 47 deletions(-) rename packages/frontend/src/components/{MkHorizontalSwipe.vue => MkSwiper.vue} (100%) diff --git a/packages/frontend/src/components/MkHorizontalSwipe.vue b/packages/frontend/src/components/MkSwiper.vue similarity index 100% rename from packages/frontend/src/components/MkHorizontalSwipe.vue rename to packages/frontend/src/components/MkSwiper.vue diff --git a/packages/frontend/src/pages/about.vue b/packages/frontend/src/pages/about.vue index b4315a5cfa..ec286f109f 100644 --- a/packages/frontend/src/pages/about.vue +++ b/packages/frontend/src/pages/about.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -28,7 +28,7 @@ import { instance } from '@/instance.js'; import { i18n } from '@/i18n.js'; import { claimAchievement } from '@/utility/achievements.js'; import { definePage } from '@/page.js'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; const XOverview = defineAsyncComponent(() => import('@/pages/about.overview.vue')); const XEmojis = defineAsyncComponent(() => import('@/pages/about.emojis.vue')); diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue index 1902267a6a..7a04914dd7 100644 --- a/packages/frontend/src/pages/announcements.vue +++ b/packages/frontend/src/pages/announcements.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -50,7 +50,7 @@ import { ref, computed } from 'vue'; import MkPagination from '@/components/MkPagination.vue'; import MkButton from '@/components/MkButton.vue'; import MkInfo from '@/components/MkInfo.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import * as os from '@/os.js'; import { misskeyApi } from '@/utility/misskey-api.js'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/pages/channel.vue b/packages/frontend/src/pages/channel.vue index a62e035198..e71d372722 100644 --- a/packages/frontend/src/pages/channel.vue +++ b/packages/frontend/src/pages/channel.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only - + @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, ref, defineAsyncComponent } from 'vue'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; const props = defineProps<{ fileId: string; diff --git a/packages/frontend/src/pages/explore.vue b/packages/frontend/src/pages/explore.vue index 85b9fe4932..bcece47e35 100644 --- a/packages/frontend/src/pages/explore.vue +++ b/packages/frontend/src/pages/explore.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -25,7 +25,7 @@ import XFeatured from './explore.featured.vue'; import XUsers from './explore.users.vue'; import XRoles from './explore.roles.vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import { definePage } from '@/page.js'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/pages/flash/flash-index.vue b/packages/frontend/src/pages/flash/flash-index.vue index 98ab587b55..4ef33cbe0f 100644 --- a/packages/frontend/src/pages/flash/flash-index.vue +++ b/packages/frontend/src/pages/flash/flash-index.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -43,7 +43,7 @@ import { computed, ref } from 'vue'; import MkFlashPreview from '@/components/MkFlashPreview.vue'; import MkPagination from '@/components/MkPagination.vue'; import MkButton from '@/components/MkButton.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { useRouter } from '@/router.js'; diff --git a/packages/frontend/src/pages/follow-requests.vue b/packages/frontend/src/pages/follow-requests.vue index 36643b1acb..d467d875fd 100644 --- a/packages/frontend/src/pages/follow-requests.vue +++ b/packages/frontend/src/pages/follow-requests.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -52,7 +52,7 @@ import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { infoImageUrl } from '@/instance.js'; import { $i } from '@/i.js'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; const paginationComponent = useTemplateRef('paginationComponent'); diff --git a/packages/frontend/src/pages/gallery/index.vue b/packages/frontend/src/pages/gallery/index.vue index 4cf3fca83b..c6ce773ab0 100644 --- a/packages/frontend/src/pages/gallery/index.vue +++ b/packages/frontend/src/pages/gallery/index.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -50,7 +50,7 @@ import { watch, ref, computed } from 'vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue'; import MkPagination from '@/components/MkPagination.vue'; import MkGalleryPostPreview from '@/components/MkGalleryPostPreview.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import { definePage } from '@/page.js'; import { i18n } from '@/i18n.js'; import { useRouter } from '@/router.js'; diff --git a/packages/frontend/src/pages/instance-info.vue b/packages/frontend/src/pages/instance-info.vue index 66ddf627e4..fde462944c 100644 --- a/packages/frontend/src/pages/instance-info.vue +++ b/packages/frontend/src/pages/instance-info.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -153,7 +153,7 @@ import { definePage } from '@/page.js'; import { i18n } from '@/i18n.js'; import MkUserCardMini from '@/components/MkUserCardMini.vue'; import MkPagination from '@/components/MkPagination.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js'; import { dateString } from '@/filters/date.js'; import MkTextarea from '@/components/MkTextarea.vue'; diff --git a/packages/frontend/src/pages/my-clips/index.vue b/packages/frontend/src/pages/my-clips/index.vue index 1525bbef9b..5b9b3af90b 100644 --- a/packages/frontend/src/pages/my-clips/index.vue +++ b/packages/frontend/src/pages/my-clips/index.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -33,7 +33,7 @@ import { misskeyApi } from '@/utility/misskey-api.js'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { clipsCache } from '@/cache.js'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; const pagination = { endpoint: 'clips/list' as const, diff --git a/packages/frontend/src/pages/notifications.vue b/packages/frontend/src/pages/notifications.vue index 0a2bc02de5..61a1b2725c 100644 --- a/packages/frontend/src/pages/notifications.vue +++ b/packages/frontend/src/pages/notifications.vue @@ -24,7 +24,7 @@ import { computed, ref } from 'vue'; import { notificationTypes } from '@@/js/const.js'; import XNotifications from '@/components/MkNotifications.vue'; import MkNotes from '@/components/MkNotes.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; diff --git a/packages/frontend/src/pages/pages.vue b/packages/frontend/src/pages/pages.vue index c99d7f1a0f..d412bad616 100644 --- a/packages/frontend/src/pages/pages.vue +++ b/packages/frontend/src/pages/pages.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -41,7 +41,7 @@ import { computed, ref } from 'vue'; import MkPagePreview from '@/components/MkPagePreview.vue'; import MkPagination from '@/components/MkPagination.vue'; import MkButton from '@/components/MkButton.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { useRouter } from '@/router.js'; diff --git a/packages/frontend/src/pages/search.vue b/packages/frontend/src/pages/search.vue index e0cb2dcbab..814ddf3cb9 100644 --- a/packages/frontend/src/pages/search.vue +++ b/packages/frontend/src/pages/search.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only @@ -28,7 +28,7 @@ import { i18n } from '@/i18n.js'; import { definePage } from '@/page.js'; import { notesSearchAvailable } from '@/utility/check-permissions.js'; import MkInfo from '@/components/MkInfo.vue'; -import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue'; +import MkSwiper from '@/components/MkSwiper.vue'; const props = withDefaults(defineProps<{ query?: string, diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue index 58f44d7591..83c7bf45bb 100644 --- a/packages/frontend/src/pages/user/index.vue +++ b/packages/frontend/src/pages/user/index.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only

- +
@@ -57,7 +57,7 @@ SPDX-License-Identifier: AGPL-3.0-only
- +
{{ i18n.ts.ok }} diff --git a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue index a569ab7c33..f5e77cbe4e 100644 --- a/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue +++ b/packages/frontend/src/pages/admin/abuse-report/notification-recipient.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/admin/abuses.vue b/packages/frontend/src/pages/admin/abuses.vue index 2335cc3db7..3dc5c2ef7e 100644 --- a/packages/frontend/src/pages/admin/abuses.vue +++ b/packages/frontend/src/pages/admin/abuses.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/admin/ads.vue b/packages/frontend/src/pages/admin/ads.vue index aa8ba2f7c3..c5baeda7b0 100644 --- a/packages/frontend/src/pages/admin/ads.vue +++ b/packages/frontend/src/pages/admin/ads.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue index ea7f0cc73d..b2d7b4889a 100644 --- a/packages/frontend/src/pages/admin/announcements.vue +++ b/packages/frontend/src/pages/admin/announcements.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
diff --git a/packages/frontend/src/pages/admin/branding.vue b/packages/frontend/src/pages/admin/branding.vue index 2674879f90..19258216f6 100644 --- a/packages/frontend/src/pages/admin/branding.vue +++ b/packages/frontend/src/pages/admin/branding.vue @@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.search.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.search.vue index ae43507d66..9938d5cc4a 100644 --- a/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.search.vue +++ b/packages/frontend/src/pages/admin/custom-emojis-manager.local.list.search.vue @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.search }}
- +
- +
{{ i18n.ts.search }} diff --git a/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue b/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue index 566acdea31..e8e944df32 100644 --- a/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue +++ b/packages/frontend/src/pages/admin/custom-emojis-manager.register.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> From 7041a3de2a4880b4aa8fbab84de5e1a63b86eaca Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Mon, 28 Apr 2025 12:57:47 +0900 Subject: [PATCH 558/649] chore: fix Chromatic CI diff strategy (#15902) --- .github/workflows/storybook.yml | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 037e6dd7f1..57d1518d9d 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -35,10 +35,7 @@ jobs: ref: "refs/pull/${{ github.event.number }}/merge" - name: Checkout actual HEAD if: github.event_name == 'pull_request_target' - id: rev - run: | - echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT - git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) + run: git checkout "$(git rev-list --parents -n1 HEAD | cut -d" " -f3)" - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js 20.x @@ -81,21 +78,16 @@ jobs: if: github.event_name == 'pull_request_target' id: chromatic_pull_request run: | - DIFF="${{ steps.rev.outputs.base }} HEAD" - if [ "$DIFF" = "0000000000000000000000000000000000000000 HEAD" ]; then - DIFF="HEAD" - fi - CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r $(echo "$DIFF") | xargs))" + CHROMATIC_PARAMETER="$(node packages/frontend/.storybook/changes.js $(git diff-tree --no-commit-id --name-only -r origin/${GITHUB_BASE_REF}...origin/${GITHUB_HEAD_REF} | xargs))" if [ "$CHROMATIC_PARAMETER" = " --skip" ]; then echo "skip=true" >> $GITHUB_OUTPUT fi - BRANCH="${{ github.event.pull_request.head.user.login }}:$HEAD_REF" - if [ "$BRANCH" = "misskey-dev:$HEAD_REF" ]; then - BRANCH="$HEAD_REF" + BRANCH="${{ github.event.pull_request.head.user.login }}:$GITHUB_HEAD_REF" + if [ "$BRANCH" = "misskey-dev:$GITHUB_HEAD_REF" ]; then + BRANCH="$GITHUB_HEAD_REF" fi pnpm --filter frontend chromatic --exit-once-uploaded -d storybook-static --branch-name "$BRANCH" $(echo "$CHROMATIC_PARAMETER") env: - HEAD_REF: ${{ github.event.pull_request.head.ref }} CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - name: Notify that Chromatic detects changes uses: actions/github-script@v7.0.1 From b09bf25e14494030c375e6c1cbc2463ab5f8cbae Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 13:03:36 +0900 Subject: [PATCH 559/649] chore(deps): update actions/setup-node action to v4.4.0 (#15901) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/api-misskey-js.yml | 2 +- .github/workflows/changelog-check.yml | 2 +- .github/workflows/check-misskey-js-autogen.yml | 2 +- .github/workflows/get-api-diff.yml | 2 +- .github/workflows/lint.yml | 6 +++--- .github/workflows/locale.yml | 2 +- .github/workflows/on-release-created.yml | 2 +- .github/workflows/storybook.yml | 2 +- .github/workflows/test-backend.yml | 4 ++-- .github/workflows/test-federation.yml | 2 +- .github/workflows/test-frontend.yml | 4 ++-- .github/workflows/test-misskey-js.yml | 2 +- .github/workflows/test-production.yml | 2 +- .github/workflows/validate-api-json.yml | 2 +- 14 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/api-misskey-js.yml b/.github/workflows/api-misskey-js.yml index 7d085821b7..6117e69c03 100644 --- a/.github/workflows/api-misskey-js.yml +++ b/.github/workflows/api-misskey-js.yml @@ -22,7 +22,7 @@ jobs: uses: pnpm/action-setup@v4.1.0 - name: Setup Node.js - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/changelog-check.yml b/.github/workflows/changelog-check.yml index 2e94f433b7..5ca27749bb 100644 --- a/.github/workflows/changelog-check.yml +++ b/.github/workflows/changelog-check.yml @@ -14,7 +14,7 @@ jobs: - name: Checkout head uses: actions/checkout@v4.2.2 - name: Setup Node.js - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' diff --git a/.github/workflows/check-misskey-js-autogen.yml b/.github/workflows/check-misskey-js-autogen.yml index 090dc70bd5..22d500c306 100644 --- a/.github/workflows/check-misskey-js-autogen.yml +++ b/.github/workflows/check-misskey-js-autogen.yml @@ -29,7 +29,7 @@ jobs: - name: setup node id: setup-node - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: pnpm diff --git a/.github/workflows/get-api-diff.yml b/.github/workflows/get-api-diff.yml index c5a4f77336..2de73aff09 100644 --- a/.github/workflows/get-api-diff.yml +++ b/.github/workflows/get-api-diff.yml @@ -33,7 +33,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4c8b97e785..f27cce5b97 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -38,7 +38,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.3.0 + - uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -69,7 +69,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.3.0 + - uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: 'pnpm' @@ -99,7 +99,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.3.0 + - uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/locale.yml b/.github/workflows/locale.yml index cee4c27ceb..68e45fdf61 100644 --- a/.github/workflows/locale.yml +++ b/.github/workflows/locale.yml @@ -20,7 +20,7 @@ jobs: submodules: true - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - - uses: actions/setup-node@v4.3.0 + - uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/on-release-created.yml b/.github/workflows/on-release-created.yml index 9d15e0fcf1..13390f3aae 100644 --- a/.github/workflows/on-release-created.yml +++ b/.github/workflows/on-release-created.yml @@ -26,7 +26,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/storybook.yml b/.github/workflows/storybook.yml index 57d1518d9d..ba745b6a2a 100644 --- a/.github/workflows/storybook.yml +++ b/.github/workflows/storybook.yml @@ -39,7 +39,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js 20.x - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version-file: '.node-version' cache: 'pnpm' diff --git a/.github/workflows/test-backend.yml b/.github/workflows/test-backend.yml index 9c54b3665b..ba4eb27a58 100644 --- a/.github/workflows/test-backend.yml +++ b/.github/workflows/test-backend.yml @@ -62,7 +62,7 @@ jobs: fi done - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -109,7 +109,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml index dc29de4d4f..fe30deb835 100644 --- a/.github/workflows/test-federation.yml +++ b/.github/workflows/test-federation.yml @@ -44,7 +44,7 @@ jobs: fi done - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-frontend.yml b/.github/workflows/test-frontend.yml index bec5169ed9..25d263f102 100644 --- a/.github/workflows/test-frontend.yml +++ b/.github/workflows/test-frontend.yml @@ -38,7 +38,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -93,7 +93,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-misskey-js.yml b/.github/workflows/test-misskey-js.yml index 2d1bd20183..5b3aed9712 100644 --- a/.github/workflows/test-misskey-js.yml +++ b/.github/workflows/test-misskey-js.yml @@ -33,7 +33,7 @@ jobs: uses: pnpm/action-setup@v4.1.0 - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/test-production.yml b/.github/workflows/test-production.yml index b77550a01f..70685e908e 100644 --- a/.github/workflows/test-production.yml +++ b/.github/workflows/test-production.yml @@ -26,7 +26,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' diff --git a/.github/workflows/validate-api-json.yml b/.github/workflows/validate-api-json.yml index 4023815cb1..77feb2b373 100644 --- a/.github/workflows/validate-api-json.yml +++ b/.github/workflows/validate-api-json.yml @@ -27,7 +27,7 @@ jobs: - name: Setup pnpm uses: pnpm/action-setup@v4.1.0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4.3.0 + uses: actions/setup-node@v4.4.0 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' From 01230f6990f8a71246491a7189c51cb67b852c8e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 28 Apr 2025 04:08:47 +0000 Subject: [PATCH 560/649] Bump version to 2025.4.1-beta.7 --- package.json | 2 +- packages/misskey-js/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 84b445a334..2cbb3b41a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2025.4.1-beta.6", + "version": "2025.4.1-beta.7", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index bc72e74550..16a7170069 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2025.4.1-beta.6", + "version": "2025.4.1-beta.7", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From c3b9a5346fff59817b4bc165ae13bbb9715795fb Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Mon, 28 Apr 2025 18:31:13 +0900 Subject: [PATCH 561/649] chore(ci): change the Test step to terminate with error in the federation test (#15903) * chore(ci): change the Test step to terminate with error in the federation test * chore(ci): always stop servers in the federation test --- .github/workflows/test-federation.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test-federation.yml b/.github/workflows/test-federation.yml index fe30deb835..c739688dc9 100644 --- a/.github/workflows/test-federation.yml +++ b/.github/workflows/test-federation.yml @@ -71,18 +71,16 @@ jobs: docker compose logs | tail -n 300 exit 1 - name: Test - id: test - continue-on-error: true run: | cd packages/backend/test-federation docker compose run --no-deps tester - name: Log - if: ${{ steps.test.outcome == 'failure' }} + if: always() run: | cd packages/backend/test-federation docker compose logs - exit 1 - name: Stop servers + if: always() run: | cd packages/backend/test-federation docker compose down From aaa31c9d64498b9627c0ae3d0623f90bb9e589a5 Mon Sep 17 00:00:00 2001 From: zyoshoka <107108195+zyoshoka@users.noreply.github.com> Date: Mon, 28 Apr 2025 18:58:08 +0900 Subject: [PATCH 562/649] fix(backend): correct response schema of chat endpoints (#15904) --- .../api/endpoints/chat/messages/delete.ts | 3 - .../api/endpoints/chat/messages/react.ts | 3 - .../api/endpoints/chat/messages/unreact.ts | 3 - .../server/api/endpoints/chat/rooms/delete.ts | 3 - .../chat/rooms/invitations/ignore.ts | 3 - .../server/api/endpoints/chat/rooms/join.ts | 3 - .../server/api/endpoints/chat/rooms/leave.ts | 3 - .../server/api/endpoints/chat/rooms/mute.ts | 3 - packages/misskey-js/etc/misskey-js.api.md | 32 ---------- packages/misskey-js/src/autogen/endpoint.ts | 24 +++---- packages/misskey-js/src/autogen/entities.ts | 8 --- packages/misskey-js/src/autogen/types.ts | 64 +++++++------------ 12 files changed, 32 insertions(+), 120 deletions(-) diff --git a/packages/backend/src/server/api/endpoints/chat/messages/delete.ts b/packages/backend/src/server/api/endpoints/chat/messages/delete.ts index 63b75fb6a7..52a054303b 100644 --- a/packages/backend/src/server/api/endpoints/chat/messages/delete.ts +++ b/packages/backend/src/server/api/endpoints/chat/messages/delete.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchMessage: { message: 'No such message.', diff --git a/packages/backend/src/server/api/endpoints/chat/messages/react.ts b/packages/backend/src/server/api/endpoints/chat/messages/react.ts index 5f61e7e992..2197e7bf80 100644 --- a/packages/backend/src/server/api/endpoints/chat/messages/react.ts +++ b/packages/backend/src/server/api/endpoints/chat/messages/react.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchMessage: { message: 'No such message.', diff --git a/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts b/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts index 6784bb6ecf..adfcd232f9 100644 --- a/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts +++ b/packages/backend/src/server/api/endpoints/chat/messages/unreact.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchMessage: { message: 'No such message.', diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts b/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts index 82a8e1f30d..1ea81448c1 100644 --- a/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts +++ b/packages/backend/src/server/api/endpoints/chat/rooms/delete.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchRoom: { message: 'No such room.', diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/invitations/ignore.ts b/packages/backend/src/server/api/endpoints/chat/rooms/invitations/ignore.ts index b8a228089b..88ea234527 100644 --- a/packages/backend/src/server/api/endpoints/chat/rooms/invitations/ignore.ts +++ b/packages/backend/src/server/api/endpoints/chat/rooms/invitations/ignore.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchRoom: { message: 'No such room.', diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/join.ts b/packages/backend/src/server/api/endpoints/chat/rooms/join.ts index d561f9e03f..550b4da1a6 100644 --- a/packages/backend/src/server/api/endpoints/chat/rooms/join.ts +++ b/packages/backend/src/server/api/endpoints/chat/rooms/join.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchRoom: { message: 'No such room.', diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/leave.ts b/packages/backend/src/server/api/endpoints/chat/rooms/leave.ts index a3ad0c2d6f..f99b408d67 100644 --- a/packages/backend/src/server/api/endpoints/chat/rooms/leave.ts +++ b/packages/backend/src/server/api/endpoints/chat/rooms/leave.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchRoom: { message: 'No such room.', diff --git a/packages/backend/src/server/api/endpoints/chat/rooms/mute.ts b/packages/backend/src/server/api/endpoints/chat/rooms/mute.ts index 11cbe7b8b9..ee60f92505 100644 --- a/packages/backend/src/server/api/endpoints/chat/rooms/mute.ts +++ b/packages/backend/src/server/api/endpoints/chat/rooms/mute.ts @@ -16,9 +16,6 @@ export const meta = { kind: 'write:chat', - res: { - }, - errors: { noSuchRoom: { message: 'No such room.', diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md index b43906109f..7069d32317 100644 --- a/packages/misskey-js/etc/misskey-js.api.md +++ b/packages/misskey-js/etc/misskey-js.api.md @@ -1046,15 +1046,9 @@ type ChatMessagesCreateToUserResponse = operations['chat___messages___create-to- // @public (undocumented) type ChatMessagesDeleteRequest = operations['chat___messages___delete']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatMessagesDeleteResponse = operations['chat___messages___delete']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatMessagesReactRequest = operations['chat___messages___react']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatMessagesReactResponse = operations['chat___messages___react']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatMessagesRoomTimelineRequest = operations['chat___messages___room-timeline']['requestBody']['content']['application/json']; @@ -1076,9 +1070,6 @@ type ChatMessagesShowResponse = operations['chat___messages___show']['responses' // @public (undocumented) type ChatMessagesUnreactRequest = operations['chat___messages___unreact']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatMessagesUnreactResponse = operations['chat___messages___unreact']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatMessagesUserTimelineRequest = operations['chat___messages___user-timeline']['requestBody']['content']['application/json']; @@ -1103,9 +1094,6 @@ type ChatRoomsCreateResponse = operations['chat___rooms___create']['responses'][ // @public (undocumented) type ChatRoomsDeleteRequest = operations['chat___rooms___delete']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatRoomsDeleteResponse = operations['chat___rooms___delete']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatRoomsInvitationsCreateRequest = operations['chat___rooms___invitations___create']['requestBody']['content']['application/json']; @@ -1115,9 +1103,6 @@ type ChatRoomsInvitationsCreateResponse = operations['chat___rooms___invitations // @public (undocumented) type ChatRoomsInvitationsIgnoreRequest = operations['chat___rooms___invitations___ignore']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatRoomsInvitationsIgnoreResponse = operations['chat___rooms___invitations___ignore']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatRoomsInvitationsInboxRequest = operations['chat___rooms___invitations___inbox']['requestBody']['content']['application/json']; @@ -1139,15 +1124,9 @@ type ChatRoomsJoiningResponse = operations['chat___rooms___joining']['responses' // @public (undocumented) type ChatRoomsJoinRequest = operations['chat___rooms___join']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatRoomsJoinResponse = operations['chat___rooms___join']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatRoomsLeaveRequest = operations['chat___rooms___leave']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatRoomsLeaveResponse = operations['chat___rooms___leave']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatRoomsMembersRequest = operations['chat___rooms___members']['requestBody']['content']['application/json']; @@ -1157,9 +1136,6 @@ type ChatRoomsMembersResponse = operations['chat___rooms___members']['responses' // @public (undocumented) type ChatRoomsMuteRequest = operations['chat___rooms___mute']['requestBody']['content']['application/json']; -// @public (undocumented) -type ChatRoomsMuteResponse = operations['chat___rooms___mute']['responses']['200']['content']['application/json']; - // @public (undocumented) type ChatRoomsOwnedRequest = operations['chat___rooms___owned']['requestBody']['content']['application/json']; @@ -1688,9 +1664,7 @@ declare namespace entities { ChatMessagesCreateToUserRequest, ChatMessagesCreateToUserResponse, ChatMessagesDeleteRequest, - ChatMessagesDeleteResponse, ChatMessagesReactRequest, - ChatMessagesReactResponse, ChatMessagesRoomTimelineRequest, ChatMessagesRoomTimelineResponse, ChatMessagesSearchRequest, @@ -1698,31 +1672,25 @@ declare namespace entities { ChatMessagesShowRequest, ChatMessagesShowResponse, ChatMessagesUnreactRequest, - ChatMessagesUnreactResponse, ChatMessagesUserTimelineRequest, ChatMessagesUserTimelineResponse, ChatRoomsCreateRequest, ChatRoomsCreateResponse, ChatRoomsDeleteRequest, - ChatRoomsDeleteResponse, ChatRoomsInvitationsCreateRequest, ChatRoomsInvitationsCreateResponse, ChatRoomsInvitationsIgnoreRequest, - ChatRoomsInvitationsIgnoreResponse, ChatRoomsInvitationsInboxRequest, ChatRoomsInvitationsInboxResponse, ChatRoomsInvitationsOutboxRequest, ChatRoomsInvitationsOutboxResponse, ChatRoomsJoinRequest, - ChatRoomsJoinResponse, ChatRoomsJoiningRequest, ChatRoomsJoiningResponse, ChatRoomsLeaveRequest, - ChatRoomsLeaveResponse, ChatRoomsMembersRequest, ChatRoomsMembersResponse, ChatRoomsMuteRequest, - ChatRoomsMuteResponse, ChatRoomsOwnedRequest, ChatRoomsOwnedResponse, ChatRoomsShowRequest, diff --git a/packages/misskey-js/src/autogen/endpoint.ts b/packages/misskey-js/src/autogen/endpoint.ts index 6390314429..56224cdbaf 100644 --- a/packages/misskey-js/src/autogen/endpoint.ts +++ b/packages/misskey-js/src/autogen/endpoint.ts @@ -220,9 +220,7 @@ import type { ChatMessagesCreateToUserRequest, ChatMessagesCreateToUserResponse, ChatMessagesDeleteRequest, - ChatMessagesDeleteResponse, ChatMessagesReactRequest, - ChatMessagesReactResponse, ChatMessagesRoomTimelineRequest, ChatMessagesRoomTimelineResponse, ChatMessagesSearchRequest, @@ -230,31 +228,25 @@ import type { ChatMessagesShowRequest, ChatMessagesShowResponse, ChatMessagesUnreactRequest, - ChatMessagesUnreactResponse, ChatMessagesUserTimelineRequest, ChatMessagesUserTimelineResponse, ChatRoomsCreateRequest, ChatRoomsCreateResponse, ChatRoomsDeleteRequest, - ChatRoomsDeleteResponse, ChatRoomsInvitationsCreateRequest, ChatRoomsInvitationsCreateResponse, ChatRoomsInvitationsIgnoreRequest, - ChatRoomsInvitationsIgnoreResponse, ChatRoomsInvitationsInboxRequest, ChatRoomsInvitationsInboxResponse, ChatRoomsInvitationsOutboxRequest, ChatRoomsInvitationsOutboxResponse, ChatRoomsJoinRequest, - ChatRoomsJoinResponse, ChatRoomsJoiningRequest, ChatRoomsJoiningResponse, ChatRoomsLeaveRequest, - ChatRoomsLeaveResponse, ChatRoomsMembersRequest, ChatRoomsMembersResponse, ChatRoomsMuteRequest, - ChatRoomsMuteResponse, ChatRoomsOwnedRequest, ChatRoomsOwnedResponse, ChatRoomsShowRequest, @@ -789,24 +781,24 @@ export type Endpoints = { 'chat/history': { req: ChatHistoryRequest; res: ChatHistoryResponse }; 'chat/messages/create-to-room': { req: ChatMessagesCreateToRoomRequest; res: ChatMessagesCreateToRoomResponse }; 'chat/messages/create-to-user': { req: ChatMessagesCreateToUserRequest; res: ChatMessagesCreateToUserResponse }; - 'chat/messages/delete': { req: ChatMessagesDeleteRequest; res: ChatMessagesDeleteResponse }; - 'chat/messages/react': { req: ChatMessagesReactRequest; res: ChatMessagesReactResponse }; + 'chat/messages/delete': { req: ChatMessagesDeleteRequest; res: EmptyResponse }; + 'chat/messages/react': { req: ChatMessagesReactRequest; res: EmptyResponse }; 'chat/messages/room-timeline': { req: ChatMessagesRoomTimelineRequest; res: ChatMessagesRoomTimelineResponse }; 'chat/messages/search': { req: ChatMessagesSearchRequest; res: ChatMessagesSearchResponse }; 'chat/messages/show': { req: ChatMessagesShowRequest; res: ChatMessagesShowResponse }; - 'chat/messages/unreact': { req: ChatMessagesUnreactRequest; res: ChatMessagesUnreactResponse }; + 'chat/messages/unreact': { req: ChatMessagesUnreactRequest; res: EmptyResponse }; 'chat/messages/user-timeline': { req: ChatMessagesUserTimelineRequest; res: ChatMessagesUserTimelineResponse }; 'chat/rooms/create': { req: ChatRoomsCreateRequest; res: ChatRoomsCreateResponse }; - 'chat/rooms/delete': { req: ChatRoomsDeleteRequest; res: ChatRoomsDeleteResponse }; + 'chat/rooms/delete': { req: ChatRoomsDeleteRequest; res: EmptyResponse }; 'chat/rooms/invitations/create': { req: ChatRoomsInvitationsCreateRequest; res: ChatRoomsInvitationsCreateResponse }; - 'chat/rooms/invitations/ignore': { req: ChatRoomsInvitationsIgnoreRequest; res: ChatRoomsInvitationsIgnoreResponse }; + 'chat/rooms/invitations/ignore': { req: ChatRoomsInvitationsIgnoreRequest; res: EmptyResponse }; 'chat/rooms/invitations/inbox': { req: ChatRoomsInvitationsInboxRequest; res: ChatRoomsInvitationsInboxResponse }; 'chat/rooms/invitations/outbox': { req: ChatRoomsInvitationsOutboxRequest; res: ChatRoomsInvitationsOutboxResponse }; - 'chat/rooms/join': { req: ChatRoomsJoinRequest; res: ChatRoomsJoinResponse }; + 'chat/rooms/join': { req: ChatRoomsJoinRequest; res: EmptyResponse }; 'chat/rooms/joining': { req: ChatRoomsJoiningRequest; res: ChatRoomsJoiningResponse }; - 'chat/rooms/leave': { req: ChatRoomsLeaveRequest; res: ChatRoomsLeaveResponse }; + 'chat/rooms/leave': { req: ChatRoomsLeaveRequest; res: EmptyResponse }; 'chat/rooms/members': { req: ChatRoomsMembersRequest; res: ChatRoomsMembersResponse }; - 'chat/rooms/mute': { req: ChatRoomsMuteRequest; res: ChatRoomsMuteResponse }; + 'chat/rooms/mute': { req: ChatRoomsMuteRequest; res: EmptyResponse }; 'chat/rooms/owned': { req: ChatRoomsOwnedRequest; res: ChatRoomsOwnedResponse }; 'chat/rooms/show': { req: ChatRoomsShowRequest; res: ChatRoomsShowResponse }; 'chat/rooms/update': { req: ChatRoomsUpdateRequest; res: ChatRoomsUpdateResponse }; diff --git a/packages/misskey-js/src/autogen/entities.ts b/packages/misskey-js/src/autogen/entities.ts index f814d7b3da..b5370e99fa 100644 --- a/packages/misskey-js/src/autogen/entities.ts +++ b/packages/misskey-js/src/autogen/entities.ts @@ -223,9 +223,7 @@ export type ChatMessagesCreateToRoomResponse = operations['chat___messages___cre export type ChatMessagesCreateToUserRequest = operations['chat___messages___create-to-user']['requestBody']['content']['application/json']; export type ChatMessagesCreateToUserResponse = operations['chat___messages___create-to-user']['responses']['200']['content']['application/json']; export type ChatMessagesDeleteRequest = operations['chat___messages___delete']['requestBody']['content']['application/json']; -export type ChatMessagesDeleteResponse = operations['chat___messages___delete']['responses']['200']['content']['application/json']; export type ChatMessagesReactRequest = operations['chat___messages___react']['requestBody']['content']['application/json']; -export type ChatMessagesReactResponse = operations['chat___messages___react']['responses']['200']['content']['application/json']; export type ChatMessagesRoomTimelineRequest = operations['chat___messages___room-timeline']['requestBody']['content']['application/json']; export type ChatMessagesRoomTimelineResponse = operations['chat___messages___room-timeline']['responses']['200']['content']['application/json']; export type ChatMessagesSearchRequest = operations['chat___messages___search']['requestBody']['content']['application/json']; @@ -233,31 +231,25 @@ export type ChatMessagesSearchResponse = operations['chat___messages___search'][ export type ChatMessagesShowRequest = operations['chat___messages___show']['requestBody']['content']['application/json']; export type ChatMessagesShowResponse = operations['chat___messages___show']['responses']['200']['content']['application/json']; export type ChatMessagesUnreactRequest = operations['chat___messages___unreact']['requestBody']['content']['application/json']; -export type ChatMessagesUnreactResponse = operations['chat___messages___unreact']['responses']['200']['content']['application/json']; export type ChatMessagesUserTimelineRequest = operations['chat___messages___user-timeline']['requestBody']['content']['application/json']; export type ChatMessagesUserTimelineResponse = operations['chat___messages___user-timeline']['responses']['200']['content']['application/json']; export type ChatRoomsCreateRequest = operations['chat___rooms___create']['requestBody']['content']['application/json']; export type ChatRoomsCreateResponse = operations['chat___rooms___create']['responses']['200']['content']['application/json']; export type ChatRoomsDeleteRequest = operations['chat___rooms___delete']['requestBody']['content']['application/json']; -export type ChatRoomsDeleteResponse = operations['chat___rooms___delete']['responses']['200']['content']['application/json']; export type ChatRoomsInvitationsCreateRequest = operations['chat___rooms___invitations___create']['requestBody']['content']['application/json']; export type ChatRoomsInvitationsCreateResponse = operations['chat___rooms___invitations___create']['responses']['200']['content']['application/json']; export type ChatRoomsInvitationsIgnoreRequest = operations['chat___rooms___invitations___ignore']['requestBody']['content']['application/json']; -export type ChatRoomsInvitationsIgnoreResponse = operations['chat___rooms___invitations___ignore']['responses']['200']['content']['application/json']; export type ChatRoomsInvitationsInboxRequest = operations['chat___rooms___invitations___inbox']['requestBody']['content']['application/json']; export type ChatRoomsInvitationsInboxResponse = operations['chat___rooms___invitations___inbox']['responses']['200']['content']['application/json']; export type ChatRoomsInvitationsOutboxRequest = operations['chat___rooms___invitations___outbox']['requestBody']['content']['application/json']; export type ChatRoomsInvitationsOutboxResponse = operations['chat___rooms___invitations___outbox']['responses']['200']['content']['application/json']; export type ChatRoomsJoinRequest = operations['chat___rooms___join']['requestBody']['content']['application/json']; -export type ChatRoomsJoinResponse = operations['chat___rooms___join']['responses']['200']['content']['application/json']; export type ChatRoomsJoiningRequest = operations['chat___rooms___joining']['requestBody']['content']['application/json']; export type ChatRoomsJoiningResponse = operations['chat___rooms___joining']['responses']['200']['content']['application/json']; export type ChatRoomsLeaveRequest = operations['chat___rooms___leave']['requestBody']['content']['application/json']; -export type ChatRoomsLeaveResponse = operations['chat___rooms___leave']['responses']['200']['content']['application/json']; export type ChatRoomsMembersRequest = operations['chat___rooms___members']['requestBody']['content']['application/json']; export type ChatRoomsMembersResponse = operations['chat___rooms___members']['responses']['200']['content']['application/json']; export type ChatRoomsMuteRequest = operations['chat___rooms___mute']['requestBody']['content']['application/json']; -export type ChatRoomsMuteResponse = operations['chat___rooms___mute']['responses']['200']['content']['application/json']; export type ChatRoomsOwnedRequest = operations['chat___rooms___owned']['requestBody']['content']['application/json']; export type ChatRoomsOwnedResponse = operations['chat___rooms___owned']['responses']['200']['content']['application/json']; export type ChatRoomsShowRequest = operations['chat___rooms___show']['requestBody']['content']['application/json']; diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts index 9da5540bc1..b9d48f02ae 100644 --- a/packages/misskey-js/src/autogen/types.ts +++ b/packages/misskey-js/src/autogen/types.ts @@ -14594,11 +14594,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14649,11 +14647,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -14877,11 +14873,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15051,11 +15045,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15167,11 +15159,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15339,11 +15329,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15451,11 +15439,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { @@ -15566,11 +15552,9 @@ export type operations = { }; }; responses: { - /** @description OK (with results) */ - 200: { - content: { - 'application/json': unknown; - }; + /** @description OK (without any results) */ + 204: { + content: never; }; /** @description Client error */ 400: { From e5fcb5b53f3719c0bafa1d6e39805b40c999cd2f Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Mon, 28 Apr 2025 21:25:47 +0900 Subject: [PATCH 563/649] enhance(frontend): disable router view transition Fix #15723 --- .../src/components/global/RouterView.vue | 46 +------------------ 1 file changed, 2 insertions(+), 44 deletions(-) diff --git a/packages/frontend/src/components/global/RouterView.vue b/packages/frontend/src/components/global/RouterView.vue index 78ac6900a3..27f7b18559 100644 --- a/packages/frontend/src/components/global/RouterView.vue +++ b/packages/frontend/src/components/global/RouterView.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only -->