From 8169c57bd1d74ea6b60e7562228793c87c53aac3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 4 Apr 2026 11:43:37 -0400 Subject: [PATCH 01/15] fix(backend): handle array or string in alsoKnownAs (#17275) * fix: handle array or string in alsoKnownAs, closes #17274 * style: use more idiomatic toArray() for UserEntityService handling of alsoKnownAs * fix: handle array-valued or unwrapped alsoKnownAs in ApPersonService * doc: note about bugfix for alsoKnownAs --- CHANGELOG.md | 164 +++++++++--------- .../activitypub/models/ApPersonService.ts | 4 +- .../src/core/entities/UserEntityService.ts | 9 +- packages/backend/test/unit/activitypub.ts | 45 +++++ .../test/unit/entities/UserEntityService.ts | 10 ++ 5 files changed, 144 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f52942914..97b6c057d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ ### Server - Fix: `/api-doc` にアクセスできない問題を修正 - +- Fix: support `alsoKnownAs` from remote actors as either array or unwrapped singleton ## 2026.3.2 @@ -43,7 +43,7 @@ - `users/following` の `birthday` プロパティは非推奨になりました。代わりに `users/get-following-users-by-birthday` をご利用ください。 ### General -- Enhance: 「もうすぐ誕生日のユーザー」ウィジェットで、誕生日が至近のユーザーも表示できるように +- Enhance: 「もうすぐ誕生日のユーザー」ウィジェットで、誕生日が至近のユーザーも表示できるように (Cherry-picked from https://github.com/MisskeyIO/misskey) - 「今日誕生日のユーザー」は「もうすぐ誕生日のユーザー」に名称変更されました - Fix: ユーザーハッシュタグページでユーザーの読み込みが重複する問題を修正 @@ -99,9 +99,9 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Client - Enhance: デッキのUI説明を追加 - Enhance: 設定がブラウザによって消去されないようにするオプションを追加 -- Fix: バージョン表記のないPlayが正しく動作しない問題を修正 +- Fix: バージョン表記のないPlayが正しく動作しない問題を修正 バージョン表記のないものは v0.x 系として実行されます。v1.x 系で動作させたい場合は必ずバージョン表記を含めてください。 -- Fix: デッキUIでメニュー位置を下にしているとプロファイル削除ボタンが表示されないのを修正 +- Fix: デッキUIでメニュー位置を下にしているとプロファイル削除ボタンが表示されないのを修正 - Fix: 一部のUnicode絵文字のリアクションがボタンにならない問題を修正 ### Server @@ -146,11 +146,11 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: ページの内容がはみ出ることがある問題を修正 - Fix: ナビゲーションバーを下に表示しているときに、項目数が多いと表示が崩れる問題を修正 - Fix: ヘッダーメニューのチャンネルの新規作成の項目でチャンネル作成ページに飛べない問題を修正 #16816 -- Fix: ラジオボタンに空白の選択肢が表示される問題を修正 +- Fix: ラジオボタンに空白の選択肢が表示される問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1105) - Fix: 一部のシチュエーションで投稿フォームのツアーが正しく表示されない問題を修正 - Fix: 投稿フォームのリセットボタンで注釈がリセットされない問題を修正 -- Fix: PlayのAiScriptバージョン判定(v0.x系・v1.x系の判定)が正しく動作しない問題を修正 +- Fix: PlayのAiScriptバージョン判定(v0.x系・v1.x系の判定)が正しく動作しない問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1129) - Fix: フォロー申請をキャンセルする際の確認ダイアログの文言が不正確な問題を修正 - Fix: 初回読み込み時にエラーになることがある問題を修正 @@ -160,12 +160,12 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Server - Enhance: メモリ使用量を削減しました - Enhance: 依存関係の更新 -- Fix: ワードミュートの文字数計算を修正 +- Fix: ワードミュートの文字数計算を修正 - Fix: チャンネルのリアルタイム更新時に、ロックダウン設定にて非ログイン時にノートを表示しない設定にしている場合でもノートが表示されてしまう問題を修正 -- Fix: DeepL APIのAPIキー指定方式変更に対応 +- Fix: DeepL APIのAPIキー指定方式変更に対応 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1096) - 内部実装の変更にて対応可能な更新です。Misskey側の設定方法に変更はありません。 -- Fix: DBレプリケーションを利用する環境でクエリーが失敗する問題を修正 +- Fix: DBレプリケーションを利用する環境でクエリーが失敗する問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/1123) ## 2025.11.0 @@ -208,7 +208,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ## 2025.10.1 ### General -- Enhance: リモートユーザーに付与したロールバッジを表示できるように(オプトイン) +- Enhance: リモートユーザーに付与したロールバッジを表示できるように(オプトイン) パフォーマンス上の問題からデフォルトで無効化されています。「コントロールパネル > パフォーマンス」から有効化できます。 - 依存関係の更新 @@ -335,7 +335,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: レンダリングパフォーマンスの向上 - Enhance: 依存ソフトウェアの更新 - Fix: 投稿フォームでファイルのアップロードが中止または失敗した際のハンドリングを修正 -- Fix: 一部の設定検索結果が存在しないパスになる問題を修正 +- Fix: 一部の設定検索結果が存在しないパスになる問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171) - Fix: テーマエディタが動作しない問題を修正 - Fix: チャンネルのハイライトページにノートが表示されない問題を修正 @@ -495,7 +495,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: 画像の高品質なプレースホルダを無効化してパフォーマンスを向上させるオプションを追加 - Enhance: 招待されているが参加していないルームを開いたときに、招待を承認するかどうか尋ねるように - Enhance: リプライ元にアンケートがあることが表示されるように -- Enhance: ノートのサーバー情報のデザインを改善・パフォーマンス向上 +- Enhance: ノートのサーバー情報のデザインを改善・パフォーマンス向上 (Based on https://github.com/taiyme/misskey/pull/198, https://github.com/taiyme/misskey/pull/211, https://github.com/taiyme/misskey/pull/283) - Enhance: ユーザー設定でURLプレビューを無効化できるように - Enhance: ヒントとコツを追加 @@ -584,7 +584,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Server - Enhance: ジョブキューの成功/失敗したジョブも一定数・一定期間保存するようにし、後から問題を調査することを容易に -- Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように +- Enhance: フォローしているユーザーならフォロワー限定投稿のノートでもアンテナで検知できるように (Cherry-picked from https://github.com/yojo-art/cherrypick/pull/568 and https://github.com/team-shahu/misskey/pull/38) - Enhance: ユーザーごとにノートの表示が高速化するように - Fix: システムアカウントの名前がサーバー名と同期されない問題を修正 @@ -690,7 +690,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### General - Enhance: プロキシアカウントをシステムアカウントとして作成するように -- Enhance: OAuthで外部アプリからロゴが提供されている場合、それを表示できるように +- Enhance: OAuthで外部アプリからロゴが提供されている場合、それを表示できるように 書式は https://indieauth.spec.indieweb.org/20220212/#example-2 に準じます。 - Fix: システムアカウントが削除できる問題を修正 @@ -704,7 +704,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Server - Fix: 特定のケースでActivityPubの処理がデッドロックになることがあるのを修正 -- Fix: S3互換オブジェクトストレージでファイルのアップロードに失敗することがある問題を修正 +- Fix: S3互換オブジェクトストレージでファイルのアップロードに失敗することがある問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/895) @@ -725,7 +725,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: リアクションする際に確認ダイアログを表示できるように - Enhance: コントロールパネルのユーザ検索で入力された情報をページ遷移で損なわないように `#15437` - Enhance: CWの注釈で入力済みの文字数を表示 -- Enhance: ノート検索ページのデザイン調整 +- Enhance: ノート検索ページのデザイン調整 (Cherry-picked from https://github.com/taiyme/misskey/pull/273) - Fix: ノートページで、クリップ一覧が表示されないことがある問題を修正 - Fix: コンディショナルロールを手動で割り当てできる導線を削除 `#13529` @@ -742,7 +742,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: `following/invalidate`でフォロワーを解除しようとしているユーザーの情報を返すように - Fix: オブジェクトストレージの設定でPrefixを設定していなかった場合nullまたは空文字になる問題を修正 - Fix: HTTPプロキシとその除外設定を行った状態でカスタム絵文字の一括インポートをしたとき、除外設定が効かないのを修正( #8766 ) -- Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正 +- Fix: pgroongaでの検索時にはじめのキーワードのみが検索に使用される問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/886) - Fix: メールアドレスの形式が正しくなければ以降の処理を行わないように - Fix: `update-meta`でobjectStoragePrefixにS3_SAFEかつURL-safeでない文字列を使えないように @@ -752,12 +752,12 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ## 2025.2.0 ### General -- Fix: Docker のビルドに失敗する問題を修正 +- Fix: Docker のビルドに失敗する問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/883) ### Client - Fix: パスキーでパスワードレスログインが出来ない問題を修正 -- Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 +- Fix: 一部環境でセンシティブなファイルを含むノートの非表示が効かない問題 - Fix: データセーバー有効時にもユーザーページの「ファイル」タブで画像が読み込まれてしまう問題を修正 - Fix: MFMの `sparkle` エフェクトが正しく表示されない問題を修正 - Fix: ページのURLにスラッシュが含まれている場合にページが正しく表示されない問題を修正 @@ -784,14 +784,14 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` * β版として公開のため、旧画面も引き続き利用可能です ### Client -- Enhance: PC画面でチャンネルが複数列で表示されるように +- Enhance: PC画面でチャンネルが複数列で表示されるように (Cherry-picked from https://github.com/Otaku-Social/maniakey/pull/13) - Enhance: 照会に失敗した場合、その理由を表示するように - Enhance: ワードミュートで検知されたワードを表示できるように - Enhance: リモートのノートのリンクをコピーできるように - Enhance: 連合がホワイトリスト化・無効化されているサーバー向けのデザイン修正 - Enhance: AiScriptのセーブデータを明示的に削除する関数`Mk:remove`を追加 -- Enhance: ノートの添付ファイルを一覧で遡れる「ファイル」タブを追加 +- Enhance: ノートの添付ファイルを一覧で遡れる「ファイル」タブを追加 (Based on https://github.com/Otaku-Social/maniakey/pull/14) - Enhance: AiScriptの拡張API関数において引数の型チェックをより厳格に - Enhance: クエリパラメータでuiを一時的に変更できるように #15240 @@ -799,26 +799,26 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: 画面サイズが変わった際にナビゲーションバーが自動で折りたたまれない問題を修正 - Fix: サーバー情報メニューに区切り線が不足していたのを修正 - Fix: ノートがログインしているユーザーしか見れない場合にログインダイアログを閉じるとその後の動線がなくなる問題を修正 -- Fix: 公開範囲がホームのノートの埋め込みウィジェットが読み込まれない問題を修正 +- Fix: 公開範囲がホームのノートの埋め込みウィジェットが読み込まれない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/803) - Fix: 絵文字管理画面で一部の絵文字が表示されない問題を修正 - Fix: プラグイン `register_note_view_interruptor` でノートのサーバー情報の書き換えができない問題を修正 - Fix: Botプロテクションの設定変更時は実際に検証を通過しないと保存できないように( #15137 ) - Fix: ノート検索が使用できない場合でもチャンネルのノート検索欄がでていた問題を修正 - Fix: `Ui:C:select`で値の変更が画面に反映されない問題を修正 -- Fix: MiAuth認可画面で、認可処理に失敗した場合でもコールバックURLに遷移してしまう問題を修正 +- Fix: MiAuth認可画面で、認可処理に失敗した場合でもコールバックURLに遷移してしまう問題を修正 (Cherry-picked from https://github.com/TeamNijimiss/misskey/commit/800359623e41a662551d774de15b0437b6849bb4) - Fix: ノート作成画面でファイルの添付可能個数を超えてもノートボタンが押せていた問題を修正 - Fix: 「アカウントを管理」画面で、ユーザー情報の取得に失敗したアカウント(削除されたアカウントなど)が表示されない問題を修正 - Fix: MacOSでChrome系ブラウザを使用している場合に、Misskeyを閉じた際に他のタブのオーディオ機能と干渉する問題を修正 - Fix: 言語データのキャッシュ状況によっては、埋め込みウィジェットが正しく起動しない問題を修正 - Fix: 「削除して編集」でノートの引用を解除出来なかった問題を修正( #14476 ) -- Fix: RSSウィジェットが正しく表示されない問題を修正 +- Fix: RSSウィジェットが正しく表示されない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/857) - Fix: ワードミュートの保存失敗時にAPIエラーが握りつぶされる事があるのを修正 - Fix: アンケートでリモートの絵文字が正しく描画できない問題の修正 (Cherry-picked from https://github.com/yojo-art/cherrypick/pull/153) -- Fix: 非ログイン時のサーバー概要画面のメニューボタンが押せないことがあるのを修正 +- Fix: 非ログイン時のサーバー概要画面のメニューボタンが押せないことがあるのを修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/656) - Fix: URLにはじめから`#pswp`が含まれている場合に画像ビューワーがブラウザの戻るボタンで閉じられない問題を修正 - Fix: ロール作成画面で設定できるアイコンデコレーションの最大取付個数を16に制限 @@ -827,18 +827,18 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Server - Enhance: pg_bigmが利用できるよう、ノートの検索をILIKE演算子でなくLIKE演算子でLOWER()をかけたテキストに対して行うように - Enhance: ノート検索の選択肢としてpgroongaに対応 ( #14730 ) -- Enhance: チャート更新時にDBに同時接続しないように +- Enhance: チャート更新時にDBに同時接続しないように (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/830) - Enhance: config(default.yml)からSQLログ全文を出力するか否かを設定可能に ( #15266 ) - Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 ) -- Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正 +- Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737) - Fix: ノートの閲覧にログイン必須にしてもFeedでノートが表示されてしまう問題を修正 - Fix: 絵文字の連合でライセンス欄を相互にやり取りするように ( #10859, #14109 ) - Fix: ロックダウンされた期間指定のノートがStreaming経由でLTLに出現するのを修正 ( #15200 ) - Fix: disableClustering設定時の初期化ロジックを調整( #15223 ) - Fix: URLとURIが異なるエンティティの照会に失敗する問題を修正( #15039 ) -- Fix: ActivityPubリクエストかどうかの判定が正しくない問題を修正 +- Fix: ActivityPubリクエストかどうかの判定が正しくない問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/869) - Fix: `/api/pages/update`にて`name`を指定せずにリクエストするとエラーが発生する問題を修正 - Fix: AIセンシティブ判定が arm64 環境で動作しない問題を修正 @@ -864,12 +864,12 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: お知らせ作成時に画像URL入力欄を空欄に変更できないのを修正 ( #14976 ) ### Client -- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように +- Enhance: Bull DashboardでRelationship Queueの状態も確認できるように (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/751) - Enhance: ドライブでソートができるように - Enhance: アイコンデコレーション管理画面の改善 - Enhance: 「単なるラッキー」の取得条件を変更 -- Enhance: 投稿フォームでEscキーを押したときIME入力中ならフォームを閉じないように( #10866 ) +- Enhance: 投稿フォームでEscキーを押したときIME入力中ならフォームを閉じないように( #10866 ) - Enhance: MiAuth, OAuthの認可画面の改善 - どのアカウントで認証しようとしているのかがわかるように - 認証するアカウントを切り替えられるように @@ -877,29 +877,29 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: カタルーニャ語 (ca-ES) に対応 - Enhance: 個別お知らせページではMetaタグを出力するように - Enhance: ノート詳細画面にロールのバッジを表示 -- Enhance: 過去に送信したフォローリクエストを確認できるように +- Enhance: 過去に送信したフォローリクエストを確認できるように (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/663) - Enhance: サイドバーを簡単に展開・折りたたみできるように ( #14981 ) - Enhance: リノートメニューに「リノートの詳細」を追加 - Enhance: 非ログイン状態でMisskeyを開いた際のパフォーマンスを向上 - Fix: 通知の範囲指定の設定項目が必要ない通知設定でも範囲指定の設定がでている問題を修正 -- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正 +- Fix: Turnstileが失敗・期限切れした際にも成功扱いとなってしまう問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/768) - Fix: デッキのタイムラインカラムで「センシティブなファイルを含むノートを表示」設定が使用できなかった問題を修正 - Fix: Encode RSS urls with escape sequences before fetching allowing query parameters to be used - Fix: リンク切れを修正 -- Fix: ノート投稿ボタンにホバー時のスタイルが適用されていないのを修正 +- Fix: ノート投稿ボタンにホバー時のスタイルが適用されていないのを修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/305) - Fix: メールアドレス登録有効化時の「完了」ダイアログボックスの表示条件を修正 -- Fix: 画面幅が狭い環境でデザインが崩れる問題を修正 +- Fix: 画面幅が狭い環境でデザインが崩れる問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/815) -- Fix: TypeScriptの型チェック対象ファイルを限定してビルドを高速化するように +- Fix: TypeScriptの型チェック対象ファイルを限定してビルドを高速化するように (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/725) ### Server - Enhance: DockerのNode.jsを22.11.0に更新 -- Enhance: 起動前の疎通チェックで、DBとメイン以外のRedisの疎通確認も行うように - (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/588) +- Enhance: 起動前の疎通チェックで、DBとメイン以外のRedisの疎通確認も行うように + (Based on https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/588) (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/715) - Enhance: リモートユーザーの照会をオリジナルにリダイレクトするように - Fix: sharedInboxが無いActorに紐づくリモートユーザーを照会できない @@ -907,18 +907,18 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: フォロワーへのメッセージの絵文字をemojisに含めるように - Fix: Nested proxy requestsを検出した際にブロックするように [ghsa-gq5q-c77c-v236](https://github.com/misskey-dev/misskey/security/advisories/ghsa-gq5q-c77c-v236) -- Fix: 招待コードの発行可能な残り数算出に使用すべきロールポリシーの値が違う問題を修正 +- Fix: 招待コードの発行可能な残り数算出に使用すべきロールポリシーの値が違う問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/706) -- Fix: 連合への配信時に、acctの大小文字が区別されてしまい正しくメンションが処理されないことがある問題を修正 +- Fix: 連合への配信時に、acctの大小文字が区別されてしまい正しくメンションが処理されないことがある問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/711) -- Fix: ローカルユーザーへのメンションを含むノートが連合される際に正しいURLに変換されないことがある問題を修正 +- Fix: ローカルユーザーへのメンションを含むノートが連合される際に正しいURLに変換されないことがある問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/712) -- Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正 +- Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709) -- Fix: User Webhookテスト機能のMock Payloadを修正 -- Fix: アカウント削除のモデレーションログが動作していないのを修正 (#14996) +- Fix: User Webhookテスト機能のMock Payloadを修正 +- Fix: アカウント削除のモデレーションログが動作していないのを修正 (#14996) - Fix: リノートミュートが新規投稿通知に対して作用していなかった問題を修正 -- Fix: Inboxの処理で生じるエラーを誤ってActivityとして処理することがある問題を修正 +- Fix: Inboxの処理で生じるエラーを誤ってActivityとして処理することがある問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/730) - Fix: セキュリティに関する修正 @@ -945,13 +945,13 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: 個人宛のお知らせは「わかった」を押すと自動的にアーカイブされるように - Fix: `admin/emoji/update`エンドポイントのidのみ指定した時不正なエラーが発生するバグを修正 - Fix: RBT有効時、リノートのリアクションが反映されない問題を修正 -- Fix: キューのエラーログを簡略化するように +- Fix: キューのエラーログを簡略化するように (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/649) ## 2024.10.0 ### Note -- セキュリティ向上のため、サーバー初期設定時に使用する初期パスワードを設定できるようになりました。今後Misskeyサーバーを新たに設置する際には、初回の起動前にコンフィグファイルの`setupPassword`をコメントアウトし、初期パスワードを設定することをおすすめします。(すでに初期設定を完了しているサーバーについては、この変更に伴い対応する必要はありません) +- セキュリティ向上のため、サーバー初期設定時に使用する初期パスワードを設定できるようになりました。今後Misskeyサーバーを新たに設置する際には、初回の起動前にコンフィグファイルの`setupPassword`をコメントアウトし、初期パスワードを設定することをおすすめします。(すでに初期設定を完了しているサーバーについては、この変更に伴い対応する必要はありません) - ホスティングサービスを運営している場合は、コンフィグファイルを構築する際に`setupPassword`をランダムな値に設定し、ユーザーに通知するようにシステムを更新することをおすすめします。 - なお、初期パスワードが設定されていない場合でも初期設定を行うことが可能です(UI上で初期パスワードの入力欄を空欄にすると続行できます)。 - ユーザーデータを読み込む際の型が一部変更されました。 @@ -971,7 +971,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Client - Enhance: デザインの調整 - Enhance: ログイン画面の認証フローを改善 -- Fix: クライアント上での時間ベースの実績獲得動作が実績獲得後も発動していた問題を修正 +- Fix: クライアント上での時間ベースの実績獲得動作が実績獲得後も発動していた問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/657) ### Server @@ -989,7 +989,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Feat: フォローされた際のメッセージを設定できるように - Feat: 連合をホワイトリスト制にできるように - Feat: UserWebhookとSystemWebhookのテスト送信機能を追加 (#14445) -- Feat: モデレーターはユーザーにかかわらずファイルが添付されているノートを検索できるように +- Feat: モデレーターはユーザーにかかわらずファイルが添付されているノートを検索できるように (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/680) - Feat: データエクスポートが完了した際に通知を発行するように - Enhance: ユーザーによるコンテンツインポートの可否をロールポリシーで制御できるように @@ -1008,12 +1008,12 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: サーバーメトリクスが2つ以上あるとリロード直後の表示がおかしくなる問題を修正 - Fix: コントロールパネル内のAp requests内のチャートの表示がおかしかった問題を修正 - Fix: 月の違う同じ日はセパレータが表示されないのを修正 -- Fix: タッチ画面でレンジスライダーを操作するとツールチップが複数表示される問題を修正 +- Fix: タッチ画面でレンジスライダーを操作するとツールチップが複数表示される問題を修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/265) -- Fix: 縦横比が極端なカスタム絵文字を表示する際にレイアウトが崩れる箇所があるのを修正 +- Fix: 縦横比が極端なカスタム絵文字を表示する際にレイアウトが崩れる箇所があるのを修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/725) - Fix: 設定変更時のリロード確認ダイアログが複数個表示されることがある問題を修正 -- Fix: ファイルの詳細ページのファイルの説明で改行が正しく表示されない問題を修正 +- Fix: ファイルの詳細ページのファイルの説明で改行が正しく表示されない問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/bde6bb0bd2e8b0d027e724d2acdb8ae0585a8110) - Fix: 一部画面のページネーションが動作しにくくなっていたのを修正 ( #12766 , #11449 ) @@ -1022,14 +1022,14 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: アンテナの書き込み時にキーワードが与えられなかった場合のエラーをApiErrorとして投げるように - この変更により、公式フロントエンドでは入力の不備が内部エラーとして報告される代わりに一般的なエラーダイアログで報告されます - Fix: ファイルがサイズの制限を超えてアップロードされた際にエラーを返さなかった問題を修正 -- Fix: 外部ページを解析する際に、ページに紐づけられた関連リソースも読み込まれてしまう問題を修正 +- Fix: 外部ページを解析する際に、ページに紐づけられた関連リソースも読み込まれてしまう問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/26e0412fbb91447c37e8fb06ffb0487346063bb8) - Fix: Continue importing from file if single emoji import fails -- Fix: `Retry-After`ヘッダーが送信されなかった問題を修正 +- Fix: `Retry-After`ヘッダーが送信されなかった問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/commit/8a982c61c01909e7540ff1be9f019df07c3f0624) -- Fix: サーバーサイドのDOM解析完了時にリソースを開放するように +- Fix: サーバーサイドのDOM解析完了時にリソースを開放するように (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/634) -- Fix: ``を追って照会するのはOKレスポンスが返却された場合のみに +- Fix: ``を追って照会するのはOKレスポンスが返却された場合のみに (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/633) - Fix: メールにスタイルが適用されていなかった問題を修正 @@ -1058,15 +1058,15 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。 - これにより、プッシュ通知が有効な同条件下の環境において、プッシュ通知が常に発生してしまう問題も修正されます。 - Fix: Play各種エンドポイントの返り値に`visibility`が含まれていない問題を修正 -- Fix: サーバー情報取得の際にモデレーター限定の情報が取得できないことがあるのを修正 +- Fix: サーバー情報取得の際にモデレーター限定の情報が取得できないことがあるのを修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/582) -- Fix: 公開範囲がダイレクトのノートをユーザーアクティビティのチャート生成に使用しないように +- Fix: 公開範囲がダイレクトのノートをユーザーアクティビティのチャート生成に使用しないように (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/679) - Fix: ActivityPubのエンティティタイプ判定で不明なタイプを受け取った場合でも処理を継続するように - キュー処理のつまりが改善される可能性があります - Fix: リバーシの対局設定の変更が反映されないのを修正 - Fix: 無制限にストリーミングのチャンネルに接続できる問題を修正 -- Fix: ベースロールのポリシーを変更した際にモデログに記録されないのを修正 +- Fix: ベースロールのポリシーを変更した際にモデログに記録されないのを修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/700) - Fix: Prevent memory leak from memory caches (#14310) - Fix: More reliable memory cache eviction (#14311) @@ -1098,9 +1098,9 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: 内蔵APIドキュメントのデザイン・パフォーマンスを改善 - Enhance: 非ログイン時に他サーバーに遷移するアクションを追加 - Enhance: 非ログイン時のハイライトTLのデザインを改善 -- Enhance: フロントエンドのアクセシビリティ改善 +- Enhance: フロントエンドのアクセシビリティ改善 (Based on https://github.com/taiyme/misskey/pull/226) -- Enhance: サーバー情報ページ・お問い合わせページを改善 +- Enhance: サーバー情報ページ・お問い合わせページを改善 (Cherry-picked from https://github.com/taiyme/misskey/pull/238) - Enhance: AiScriptを0.19.0にアップデート - Enhance: Allow negative delay for MFM animation elements (`tada`, `jelly`, `twitch`, `shake`, `spin`, `jump`, `bounce`, `rainbow`) @@ -1109,7 +1109,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: 検索(ノート/ユーザー)において、入力に空白が含まれている場合は照会を行わないように - Enhance: 検索(ノート/ユーザー)において、照会を行うかどうか、ハッシュタグのノート/ユーザー一覧ページを表示するかどうかの確認ダイアログを出すように - Enhance: 検索(ノート/ユーザー)で `@` から始まる文字列(`@user@host`など)を入力すると、そのユーザーを照会できるように -- Enhance: ドライブのファイル・フォルダをドラッグしなくても移動できるように +- Enhance: ドライブのファイル・フォルダをドラッグしなくても移動できるように (Cherry-picked from https://github.com/nafu-at/misskey/commit/b89c2af6945c6a9f9f10e83f54d2bcf0f240b0b4, https://github.com/nafu-at/misskey/commit/8a7d710c6acb83f50c83f050bd1423c764d60a99) - Enhance: デッキのアンテナ・リスト選択画面からそれぞれを新規作成できるように - Enhance: ブラウザのコンテキストメニューを使用できるように @@ -1117,19 +1117,19 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: `/about#federation` ページなどで各インスタンスのチャートが表示されなくなっていた問題を修正 - Fix: ユーザーページの追加情報のラベルを投稿者のサーバーの絵文字で表示する (#13968) - Fix: リバーシの対局を正しく共有できないことがある問題を修正 -- Fix: コントロールパネルでベースロールのポリシーを編集してもUI上では変更が反映されない問題を修正 +- Fix: コントロールパネルでベースロールのポリシーを編集してもUI上では変更が反映されない問題を修正 - Fix: アンテナの編集画面のボタンに隙間を追加 - Fix: テーマプレビューが見れない問題を修正 -- Fix: ショートカットキーが連打できる問題を修正 +- Fix: ショートカットキーが連打できる問題を修正 (Cherry-picked from https://github.com/taiyme/misskey/pull/234) - Fix: MkSignin.vueのcredentialRequestからReactivityを削除(ProxyがPasskey認証処理に渡ることを避けるため) -- Fix: 「アニメーション画像を再生しない」がオンのときでもサーバーのバナー画像・背景画像がアニメーションしてしまう問題を修正 +- Fix: 「アニメーション画像を再生しない」がオンのときでもサーバーのバナー画像・背景画像がアニメーションしてしまう問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/574) - Fix: Twitchの埋め込みが開けない問題を修正 - Fix: 子メニューの高さがウィンドウからはみ出ることがある問題を修正 - Fix: 個人宛てのダイアログ形式のお知らせが即時表示されない問題を修正 - Fix: 一部の画像がセンシティブ指定されているときに画面に何も表示されないことがあるのを修正 -- Fix: リアクションしたユーザー一覧のユーザー名がはみ出る問題を修正 +- Fix: リアクションしたユーザー一覧のユーザー名がはみ出る問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/672) - Fix: `/share`ページにおいて絵文字ピッカーを開くことができない問題を修正 - Fix: deck uiの通知音が重なる問題 (#14029) @@ -1172,14 +1172,14 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` 4. フォローしていない非アクティブなユーザ また、自分自身のアカウントもサジェストされるようになりました。 -- Fix: 一般ユーザーから見たユーザーのバッジの一覧に公開されていないものが含まれることがある問題を修正 +- Fix: 一般ユーザーから見たユーザーのバッジの一覧に公開されていないものが含まれることがある問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/652) - Fix: ユーザーのリアクション一覧でミュート/ブロックが機能していなかった問題を修正 - Fix: FTT有効時にリモートユーザーのノートがHTLにキャッシュされる問題を修正 - Fix: 一部の通知がローカル上のリモートユーザーに対して行われていた問題を修正 - Fix: エラーメッセージの誤字を修正 (#14213) - Fix: ソーシャルタイムラインにローカルタイムラインに表示される自分へのリプライが表示されない問題を修正 -- Fix: リノートのミュートが適用されるまでに時間がかかることがある問題を修正 +- Fix: リノートのミュートが適用されるまでに時間がかかることがある問題を修正 (Cherry-picked from https://github.com/Type4ny-Project/Type4ny/commit/e9601029b52e0ad43d9131b555b614e56c84ebc1) - Fix: Steaming APIが不正なデータを受けた場合の動作が不安定である問題 #14251 - Fix: `users/search`において `@` から始まる文字列が与えられた際の処理が正しくなかった問題を修正 @@ -1206,7 +1206,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### General - Feat: エラートラッキングにSentryを使用できるようになりました - Enhance: URLプレビューの有効化・無効化を設定できるように #13569 -- Enhance: アンテナでBotによるノートを除外できるように +- Enhance: アンテナでBotによるノートを除外できるように (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545) - Enhance: クリップのノート数を表示するように - Enhance: コンディショナルロールの条件として以下を新たに追加 (#13667) @@ -1225,7 +1225,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Client - Feat: アップロードするファイルの名前をランダム文字列にできるように -- Feat: 個別のお知らせにリンクで飛べるように +- Feat: 個別のお知らせにリンクで飛べるように (Based on https://github.com/MisskeyIO/misskey/pull/639) - Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように - Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように @@ -1255,9 +1255,9 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Fix: 一部のページ内リンクが正しく動作しない問題を修正 - Fix: 周年の実績が閏年を考慮しない問題を修正 - Fix: ローカルURLのプレビューポップアップが左上に表示される -- Fix: WebGL2をサポートしないブラウザで「季節に応じた画面の演出」が有効になっているとき、Misskeyが起動できなくなる問題を修正 +- Fix: WebGL2をサポートしないブラウザで「季節に応じた画面の演出」が有効になっているとき、Misskeyが起動できなくなる問題を修正 (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/459) -- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正 +- Fix: ページタイトルでローカルユーザーとリモートユーザーの区別がつかない問題を修正 (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/528) - Fix: コードブロックのシンタックスハイライトで使用される定義ファイルをCDNから取得するように #13177 - CDNから取得せずMisskey本体にバンドルする場合は`pacakges/frontend/vite.config.ts`を修正してください。 @@ -1280,13 +1280,13 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: ドライブのファイルがNSFWかどうか個別に連合されるように (#13756) - 可能な場合、ノートの添付ファイルのセンシティブ判定がファイル単位になります - Fix: リモートから配送されたアクティビティにJSON-LD compactionをかける -- Fix: フォローリクエストを作成する際に既存のものは削除するように +- Fix: フォローリクエストを作成する際に既存のものは削除するように (Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/440) - Fix: エンドポイント`notes/translate`のエラーを改善 - Fix: CleanRemoteFilesProcessorService report progress from 100% (#13632) - Fix: 一部の音声ファイルが映像ファイルとして扱われる問題を修正 - Fix: リプライのみの引用リノートと、CWのみの引用リノートが純粋なリノートとして誤って扱われてしまう問題を修正 -- Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように +- Fix: 登録にメール認証が必須になっている場合、登録されているメールアドレスを削除できないように (Cherry-picked from https://github.com/MisskeyIO/misskey/pull/606) - Fix: Add Cache-Control to Bull Board - Fix: nginx経由で/files/にRangeリクエストされた場合に正しく応答できないのを修正 @@ -1479,10 +1479,10 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### Note - 依存関係の更新に伴い、Node.js 20.10.0が最小要件になりました - 絵文字の追加辞書を既にインストールしている場合は、お手数ですが再インストールのほどお願いします -- 絵文字ピッカーにピン留め表示する絵文字設定が「リアクション用」と「絵文字入力用」に分かれました。以前の設定は「リアクション用」として使用されます。 +- 絵文字ピッカーにピン留め表示する絵文字設定が「リアクション用」と「絵文字入力用」に分かれました。以前の設定は「リアクション用」として使用されます。 - **影響:** - それにより、投稿フォームから表示される絵文字ピッカーのピン留め絵文字がリセットされたように感じるかもしれません(新設された"ピン留め(全般)"の設定が使われるため)。 + **影響:** + それにより、投稿フォームから表示される絵文字ピッカーのピン留め絵文字がリセットされたように感じるかもしれません(新設された"ピン留め(全般)"の設定が使われるため)。 投稿用のピン留め絵文字をアップデート前の状態にするには、以下の手順で操作します。 1. 「設定」メニューに移動し、「絵文字ピッカー」タブを選択します。 @@ -1529,7 +1529,7 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` - Enhance: Unicode 15.0のサポート - Enhance: コードブロックのハイライト機能を利用するには言語を明示的に指定させるように - MFMでコードブロックを利用する際に意図しないハイライトが起こらないようになりました - - 逆に、MFMでコードハイライトを利用したい際は言語を明示的に指定する必要があります + - 逆に、MFMでコードハイライトを利用したい際は言語を明示的に指定する必要があります (例: ` ```js ` → Javascript, ` ```ais ` → AiScript) - Enhance: 絵文字などのオートコンプリートでShift+Tabを押すと前の候補を選択できるように - Enhance: チャンネルに新規の投稿がある場合にバッジを表示させる @@ -1936,9 +1936,9 @@ v2025.12.0で行われた「configの`trustProxy`のデフォルト値を`false` ### General - 招待機能を改善しました - * 過去に発行した招待コードを確認できるようになりました - * ロールごとに招待コードの発行数制限と制限対象期間、有効期限を設定できるようになりました - * 招待コードを作成したユーザーと使用したユーザーを確認できるようになりました + * 過去に発行した招待コードを確認できるようになりました + * ロールごとに招待コードの発行数制限と制限対象期間、有効期限を設定できるようになりました + * 招待コードを作成したユーザーと使用したユーザーを確認できるようになりました - ユーザーにロールが期限付きでアサインされている場合、その期限をユーザーのモデレーションページで確認できるようになりました - identicon生成を無効にしてパフォーマンスを向上させることができるようになりました - サーバーのマシン情報の公開を無効にしてパフォーマンスを向上させることができるようになりました @@ -2101,9 +2101,9 @@ Meilisearchの設定に`index`が必要になりました。値はMisskeyサー * 「フォロワーのみ」の投稿は検索結果に表示されません。 - 新規登録前に簡潔なルールをユーザーに表示できる、サーバールール機能を追加 - ユーザーへの自分用メモ機能 - * ユーザーに対して、自分だけが見られるメモを追加できるようになりました。 + * ユーザーに対して、自分だけが見られるメモを追加できるようになりました。 (自分自身に対してもメモを追加できます。) - * ユーザーメニューから追加できます。 + * ユーザーメニューから追加できます。 (デスクトップ表示ではusernameの右側のボタンからも追加可能) - チャンネルに色を設定できるようになりました。各ノートに設定した色のインジケーターが表示されます。 - チャンネルをアーカイブできるようになりました。 diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts index ebe8e9c964..39396cb741 100644 --- a/packages/backend/src/core/activitypub/models/ApPersonService.ts +++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts @@ -376,7 +376,7 @@ export class ApPersonService implements OnModuleInit { isLocked: person.manuallyApprovesFollowers, movedToUri: person.movedTo, movedAt: person.movedTo ? new Date() : null, - alsoKnownAs: person.alsoKnownAs, + alsoKnownAs: toArray(person.alsoKnownAs), isExplorable: person.discoverable, username: person.preferredUsername, usernameLower: person.preferredUsername?.toLowerCase(), @@ -568,7 +568,7 @@ export class ApPersonService implements OnModuleInit { isCat: (person as any).isCat === true, isLocked: person.manuallyApprovesFollowers, movedToUri: person.movedTo ?? null, - alsoKnownAs: person.alsoKnownAs ?? null, + alsoKnownAs: person.alsoKnownAs ? toArray(person.alsoKnownAs) : null, isExplorable: person.discoverable, ...(await this.resolveAvatarAndBanner(exist, person.icon, person.image).catch(() => ({}))), } as Partial & Pick; diff --git a/packages/backend/src/core/entities/UserEntityService.ts b/packages/backend/src/core/entities/UserEntityService.ts index 0f4051e7b8..996f0bad2e 100644 --- a/packages/backend/src/core/entities/UserEntityService.ts +++ b/packages/backend/src/core/entities/UserEntityService.ts @@ -51,6 +51,7 @@ import { ChatService } from '@/core/ChatService.js'; import type { OnModuleInit } from '@nestjs/common'; import type { NoteEntityService } from './NoteEntityService.js'; import type { PageEntityService } from './PageEntityService.js'; +import { toArray } from '@/misc/prelude/array.js'; const Ajv = _Ajv.default; const ajv = new Ajv(); @@ -527,10 +528,10 @@ export class UserEntityService implements OnModuleInit { url: profile!.url, uri: user.uri, movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null, - alsoKnownAs: user.alsoKnownAs - ? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) - .then(xs => xs.length === 0 ? null : xs.filter(x => x != null)) - : null, + alsoKnownAs: user.alsoKnownAs ? + Promise.all(toArray(user.alsoKnownAs).map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null))) + .then(xs => xs.length === 0 ? null : xs.filter(x => x != null)) + : null, createdAt: this.idService.parse(user.id).date.toISOString(), updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null, lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null, diff --git a/packages/backend/test/unit/activitypub.ts b/packages/backend/test/unit/activitypub.ts index c6e09bdda2..3022818b68 100644 --- a/packages/backend/test/unit/activitypub.ts +++ b/packages/backend/test/unit/activitypub.ts @@ -224,6 +224,51 @@ describe('ActivityPub', () => { }); }); + describe('alsoKnownAs field', () => { + test('Handle alsoKnownAs as an array', async () => { + const actor = { + ...createRandomActor(), + alsoKnownAs: ['https://example.com/users/alice', 'https://example.com/users/alice2'], + }; + + resolver.register(actor.id, actor); + + const user = await personService.createPerson(actor.id, resolver); + + assert.deepStrictEqual(user.alsoKnownAs, actor.alsoKnownAs); + }); + + test('Handle alsoKnownAs as a string', async () => { + const actor = { + ...createRandomActor(), + alsoKnownAs: 'https://example.com/users/alice', + }; + + resolver.register(actor.id, actor); + + const user = await personService.createPerson(actor.id, resolver); + + assert.deepStrictEqual(user.alsoKnownAs, [actor.alsoKnownAs]); + }); + + test('Update person with alsoKnownAs as a string', async () => { + const actor = createRandomActor(); + resolver.register(actor.id, actor); + const user = await personService.createPerson(actor.id, resolver); + + const updatedActor = { + ...actor, + alsoKnownAs: 'https://example.com/users/alice', + }; + resolver.register(actor.id, updatedActor); + + await personService.updatePerson(actor.id, resolver, updatedActor); + + const updatedUser = await personService.fetchPerson(actor.id); + assert.deepStrictEqual(updatedUser?.alsoKnownAs, [updatedActor.alsoKnownAs]); + }); + }); + describe('Collection visibility', () => { test('Public following/followers', async () => { const actor = createRandomActor(); diff --git a/packages/backend/test/unit/entities/UserEntityService.ts b/packages/backend/test/unit/entities/UserEntityService.ts index ca6a639be8..706c4a85c3 100644 --- a/packages/backend/test/unit/entities/UserEntityService.ts +++ b/packages/backend/test/unit/entities/UserEntityService.ts @@ -248,6 +248,16 @@ describe('UserEntityService', () => { expect(actual.achievements).toEqual(achievements); }); + test('alsoKnownAs as string does not throw', async () => { + const me = await createUser(); + const who = await createUser(); + + const whoWithStringAlsoKnownAs: MiUser = { ...who, alsoKnownAs: 'https://remote.example.com/users/alice' as any }; + + const actual = await service.pack(whoWithStringAlsoKnownAs, me, { schema: 'UserDetailedNotMe' }) as any; + expect(Array.isArray(actual.alsoKnownAs)).toBe(true); + }); + describe('packManyによるpreloadがある時、preloadが無い時とpackの結果が同じになるか見たい', () => { test('no-preload', async() => { const me = await createUser(); From 0b7b59f1e2c2d6782c5dfddb86f3037815d73c61 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: Sun, 5 Apr 2026 17:22:17 +0900 Subject: [PATCH 02/15] =?UTF-8?q?enhance(frontend):=20=E3=83=81=E3=83=A3?= =?UTF-8?q?=E3=83=B3=E3=83=8D=E3=83=AB=E6=8C=87=E5=AE=9A=E3=83=AA=E3=83=8E?= =?UTF-8?q?=E3=83=BC=E3=83=88=E3=81=A7=E3=83=AA=E3=83=8E=E3=83=BC=E3=83=88?= =?UTF-8?q?=E5=85=88=E3=81=AE=E3=83=81=E3=83=A3=E3=83=B3=E3=83=8D=E3=83=AB?= =?UTF-8?q?=E3=81=AB=E7=A7=BB=E5=8B=95=E3=81=A7=E3=81=8D=E3=82=8B=E3=82=88?= =?UTF-8?q?=E3=81=86=E3=81=AB=20(#17280)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * enhance(frontend): チャンネル指定リノートでリノート先のチャンネルに移動できるように * Update Changelog * fix condition * refactor --- CHANGELOG.md | 2 +- locales/ja-JP.yml | 1 + packages/frontend/src/components/MkNote.vue | 22 ++++++--- .../src/components/MkNoteDetailed.vue | 45 +++++++++++++------ .../components/MkStreamingNotesTimeline.vue | 3 +- packages/frontend/src/di.ts | 3 +- packages/i18n/src/autogen/locale.ts | 4 ++ 7 files changed, 59 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 97b6c057d3..b5d712db13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - ### Client -- +- Enhance: チャンネル指定リノートでリノート先のチャンネルに移動できるように ### Server - Fix: `/api-doc` にアクセスできない問題を修正 diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 4af17dd39e..93679aa24b 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1408,6 +1408,7 @@ frame: "フレーム" presets: "プリセット" zeroPadding: "ゼロ埋め" nothingToConfigure: "設定項目はありません" +viewRenotedChannel: "リノート先のチャンネルを見る" _imageEditing: _vars: diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index c78cc44425..ba68971034 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -263,7 +263,7 @@ const emit = defineEmits<{ const inTimeline = inject('inTimeline', false); const tl_withSensitive = inject>('tl_withSensitive', ref(true)); -const inChannel = inject('inChannel', null); +const inChannel = inject(DI.inChannel, null); const currentClip = inject | null>('currentClip', null); let note = deepClone(props.note); @@ -650,23 +650,35 @@ async function showRenoteMenu() { }; } - const renoteDetailsMenu: MenuItem = { + const renoteDetailsMenu: MenuItem[] = [{ type: 'link', text: i18n.ts.renoteDetails, icon: 'ti ti-info-circle', to: notePage(note), - }; + }]; + + if ( + props.note.channelId != null && + (inChannel == null || props.note.channelId !== inChannel.value) + ) { + renoteDetailsMenu.push({ + type: 'link', + text: i18n.ts.viewRenotedChannel, + icon: 'ti ti-device-tv', + to: `/channels/${props.note.channelId}`, + }); + } if (isMyRenote) { os.popupMenu([ - renoteDetailsMenu, + ...renoteDetailsMenu, getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote), { type: 'divider' }, getUnrenote(), ], renoteTime.value); } else { os.popupMenu([ - renoteDetailsMenu, + ...renoteDetailsMenu, getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote), { type: 'divider' }, getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote), diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index 083e3e5da0..114edc6204 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -238,6 +238,7 @@ import { isLink } from '@@/js/is-link.js'; import { host } from '@@/js/config.js'; import type { OpenOnRemoteOptions } from '@/utility/please-login.js'; import type { Keymap } from '@/utility/hotkey.js'; +import type { MenuItem } from '@/types/menu.js'; import MkNoteSub from '@/components/MkNoteSub.vue'; import MkNoteSimple from '@/components/MkNoteSimple.vue'; import MkReactionsViewer from '@/components/MkReactionsViewer.vue'; @@ -286,7 +287,7 @@ const props = withDefaults(defineProps<{ initialTab: 'replies', }); -const inChannel = inject('inChannel', null); +const inChannel = inject(DI.inChannel, null); let note = deepClone(props.note); @@ -581,18 +582,36 @@ async function showRenoteMenu() { const isLoggedIn = await pleaseLogin({ openOnRemote: pleaseLoginContext.value }); if (!isLoggedIn) return; - os.popupMenu([{ - text: i18n.ts.unrenote, - icon: 'ti ti-trash', - danger: true, - action: () => { - misskeyApi('notes/delete', { - noteId: note.id, - }).then(() => { - globalEvents.emit('noteDeleted', note.id); - }); - }, - }], renoteTime.value); + const menu: MenuItem[] = []; + + if (isMyRenote) { + menu.push({ + text: i18n.ts.unrenote, + icon: 'ti ti-trash', + danger: true, + action: () => { + misskeyApi('notes/delete', { + noteId: note.id, + }).then(() => { + globalEvents.emit('noteDeleted', note.id); + }); + }, + }); + } + + if ( + props.note.channelId != null && + (inChannel == null || props.note.channelId !== inChannel.value) + ) { + menu.push({ + type: 'link', + text: i18n.ts.viewRenotedChannel, + icon: 'ti ti-device-tv', + to: `/channels/${props.note.channelId}`, + }); + } + + os.popupMenu(menu, renoteTime.value); } function focus() { diff --git a/packages/frontend/src/components/MkStreamingNotesTimeline.vue b/packages/frontend/src/components/MkStreamingNotesTimeline.vue index 9784d8e017..00fd778a5e 100644 --- a/packages/frontend/src/components/MkStreamingNotesTimeline.vue +++ b/packages/frontend/src/components/MkStreamingNotesTimeline.vue @@ -74,6 +74,7 @@ import { store } from '@/store.js'; import MkNote from '@/components/MkNote.vue'; import MkButton from '@/components/MkButton.vue'; import { i18n } from '@/i18n.js'; +import { DI } from '@/di.js'; import { globalEvents, useGlobalEvent } from '@/events.js'; import { isSeparatorNeeded, getSeparatorInfo } from '@/utility/timeline-date-separate.js'; import { Paginator } from '@/utility/paginator.js'; @@ -101,7 +102,7 @@ const props = withDefaults(defineProps<{ provide('inTimeline', true); provide('tl_withSensitive', computed(() => props.withSensitive)); -provide('inChannel', computed(() => props.src === 'channel')); +provide(DI.inChannel, computed(() => props.src === 'channel' ? props.channel ?? null : null)); let paginator: IPaginator; diff --git a/packages/frontend/src/di.ts b/packages/frontend/src/di.ts index f09782ea38..eddb0dcb35 100644 --- a/packages/frontend/src/di.ts +++ b/packages/frontend/src/di.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import type { InjectionKey, Ref } from 'vue'; +import type { InjectionKey, Ref, ComputedRef } from 'vue'; import type { PageMetadata } from '@/page.js'; import type { Router } from '@/router.js'; @@ -18,4 +18,5 @@ export const DI = { mfmEmojiReactCallback: Symbol() as InjectionKey<(emoji: string) => void>, inModal: Symbol() as InjectionKey, inAppSearchMarkerId: Symbol() as InjectionKey>, + inChannel: Symbol() as InjectionKey | null>, // 現在開いているチャンネルのID }; diff --git a/packages/i18n/src/autogen/locale.ts b/packages/i18n/src/autogen/locale.ts index 05a2195374..69e7346a59 100644 --- a/packages/i18n/src/autogen/locale.ts +++ b/packages/i18n/src/autogen/locale.ts @@ -5647,6 +5647,10 @@ export interface Locale extends ILocale { * 設定項目はありません */ "nothingToConfigure": string; + /** + * リノート先のチャンネルを見る + */ + "viewRenotedChannel": string; "_imageEditing": { "_vars": { /** From a18c909ba3ddbb5c3268b70cc05a3d384bf8ff6f 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: Mon, 6 Apr 2026 20:15:57 +0900 Subject: [PATCH 03/15] Revert "deps: Update vite to v8" (#17283) Revert "deps: Update vite to v8 (#17238)" This reverts commit e601fcb729445c3d20ac6e0447e0143348491a43. --- packages/backend/package.json | 2 +- .../locale-inliner/collect-modifications.ts | 22 +- packages/frontend-builder/package.json | 5 +- .../rollup-plugin-remove-unref-i18n.ts | 27 +- packages/frontend-embed/build.ts | 2 +- packages/frontend-embed/package.json | 5 +- packages/frontend-embed/vite.config.ts | 27 +- .../vite-plugin-json5.ts => vite.json5.ts} | 7 +- ...lugin-unwind-css-module-class-name.test.ts | 879 ++++++++---------- ...lup-plugin-unwind-css-module-class-name.ts | 351 ++++--- .../lib/vite-plugin-create-search-index.ts | 39 +- .../frontend/lib/vite-plugin-watch-locales.ts | 6 +- packages/frontend/package.json | 16 +- packages/frontend/vite.config.ts | 40 +- .../vite-plugin-json5.ts => vite.json5.ts} | 7 +- pnpm-lock.yaml | 853 +++-------------- 16 files changed, 735 insertions(+), 1553 deletions(-) rename packages/frontend-embed/{lib/vite-plugin-json5.ts => vite.json5.ts} (90%) rename packages/frontend/{lib/vite-plugin-json5.ts => vite.json5.ts} (90%) diff --git a/packages/backend/package.json b/packages/backend/package.json index 40d963f3c7..6b2e76480b 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -228,6 +228,6 @@ "pid-port": "2.1.0", "simple-oauth2": "5.1.0", "supertest": "7.2.2", - "vite": "8.0.2" + "vite": "7.3.1" } } diff --git a/packages/frontend-builder/locale-inliner/collect-modifications.ts b/packages/frontend-builder/locale-inliner/collect-modifications.ts index 2e92a407c9..59e5d96517 100644 --- a/packages/frontend-builder/locale-inliner/collect-modifications.ts +++ b/packages/frontend-builder/locale-inliner/collect-modifications.ts @@ -3,11 +3,10 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { parseAst } from 'rolldown/parseAst'; +import { parseAst } from 'vite'; import * as estreeWalker from 'estree-walker'; import { assertNever, assertType } from '../utils.js'; -import type { ESTree as RolldownESTree } from 'rolldown/utils'; -import type { AstNode } from 'rollup'; +import type { AstNode, ProgramNode } from 'rollup'; import type * as estree from 'estree'; import type { LocaleInliner, TextModification } from '../locale-inliner.js'; import type { Logger } from '../logger.js'; @@ -18,7 +17,7 @@ interface WalkerContext { } export function collectModifications(sourceCode: string, fileName: string, fileLogger: Logger, inliner: LocaleInliner): TextModification[] { - let programNode: RolldownESTree.Program; + let programNode: ProgramNode; try { programNode = parseAst(sourceCode); } catch (err) { @@ -36,8 +35,7 @@ export function collectModifications(sourceCode: string, fileName: string, fileL // 1) replace all `scripts/` path literals with locale code // 2) replace all `localStorage.getItem("lang")` with `localeName` variable // 3) replace all `await window.fetch(`/assets/locales/${d}.${x}.json`).then(u=>u.json())` with `localeJson` variable - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(programNode, { + estreeWalker.walk(programNode, { enter(this: WalkerContext, node: Node) { assertType(node); @@ -120,9 +118,8 @@ export function collectModifications(sourceCode: string, fileName: string, fileL // Check if the identifier is already declared in the file. // If it is, we may overwrite it and cause issues so we skip inlining let isSupported = true; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(programNode, { - enter(node: Node) { + estreeWalker.walk(programNode, { + enter(node) { if (node.type === 'VariableDeclaration') { assertType(node); for (const id of node.declarations.flatMap(x => declsOfPattern(x.id))) { @@ -148,9 +145,8 @@ export function collectModifications(sourceCode: string, fileName: string, fileL const toSkip = new Set(); toSkip.add(i18nImport); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(programNode, { - enter(this: WalkerContext, node: Node, parent: Node | null, property: string | number | symbol | null | undefined) { + estreeWalker.walk(programNode, { + enter(this: WalkerContext, node, parent, property) { assertType(node); assertType(parent); if (toSkip.has(node)) { @@ -383,7 +379,7 @@ type SpecifierResult = | { type: 'specifier', localI18nIdentifier: string, importNode: estree.ImportDeclaration & AstNode } ; -function findImportSpecifier(programNode: RolldownESTree.Program, i18nFileName: string, i18nSymbol: string): SpecifierResult { +function findImportSpecifier(programNode: ProgramNode, i18nFileName: string, i18nSymbol: string): SpecifierResult { const imports = programNode.body.filter(x => x.type === 'ImportDeclaration'); const importNode = imports.find(x => x.source.value === `./${i18nFileName}`) as estree.ImportDeclaration | undefined; if (!importNode) return { type: 'no-import' }; diff --git a/packages/frontend-builder/package.json b/packages/frontend-builder/package.json index 28bcc47d63..f4326907d2 100644 --- a/packages/frontend-builder/package.json +++ b/packages/frontend-builder/package.json @@ -17,10 +17,9 @@ "rollup": "4.60.0" }, "dependencies": { - "estree-walker": "3.0.3", "i18n": "workspace:*", + "estree-walker": "3.0.3", "magic-string": "0.30.21", - "rolldown": "1.0.0-rc.11", - "vite": "8.0.2" + "vite": "7.3.1" } } diff --git a/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts b/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts index 6ff62b8f77..4a2bfa67d9 100644 --- a/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts +++ b/packages/frontend-builder/rollup-plugin-remove-unref-i18n.ts @@ -4,11 +4,11 @@ */ import * as estreeWalker from 'estree-walker'; -import { RolldownMagicString } from 'rolldown'; +import MagicString from 'magic-string'; import { assertType } from './utils.js'; -import type { ESTree } from 'rolldown/utils'; import type { Plugin } from 'vite'; -import type { CallExpression, Expression } from 'estree'; +import type { CallExpression, Expression, Program } from 'estree'; +import type { AstNode } from 'rollup'; // This plugin transforms `unref(i18n)` to `i18n` in the code, which is useful for removing unnecessary unref calls // and helps locale inliner runs after vite build to inline the locale data into the final build. @@ -23,13 +23,12 @@ export function pluginRemoveUnrefI18n( } = {}): Plugin { return { name: 'UnwindCssModuleClassName', - renderChunk(code, _chunk, _options, meta) { + renderChunk(code) { if (!code.includes('unref(i18n)')) return null; - const ast = this.parse(code); - const magicString = meta.magicString ?? new RolldownMagicString(code); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (estreeWalker.walk as any)(ast, { - enter(node: ESTree.Node) { + const ast = this.parse(code) as Program; + const magicString = new MagicString(code); + estreeWalker.walk(ast, { + enter(node) { if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'unref' && node.arguments.length === 1) { // calls to unref with single argument @@ -37,16 +36,18 @@ export function pluginRemoveUnrefI18n( if (arg.type === 'Identifier' && arg.name === i18nSymbolName) { // this is unref(i18n) so replace it with i18n // to replace, remove the 'unref(' and the trailing ')' - assertType(node); - assertType(arg); + assertType(node); + assertType(arg); magicString.remove(node.start, arg.start); magicString.remove(arg.end, node.end); } } }, }); - - return magicString; + return { + code: magicString.toString(), + map: magicString.generateMap({ hires: true }), + }; }, }; } diff --git a/packages/frontend-embed/build.ts b/packages/frontend-embed/build.ts index 0b4058f33a..4e1f588802 100644 --- a/packages/frontend-embed/build.ts +++ b/packages/frontend-embed/build.ts @@ -3,7 +3,7 @@ import url from 'node:url'; import path from 'node:path'; import { execa } from 'execa'; import locales from 'i18n'; -import { LocaleInliner } from '../frontend-builder/locale-inliner.js'; +import { LocaleInliner } from '../frontend-builder/locale-inliner.js' import { createLogger } from '../frontend-builder/logger'; // requires node 21 or later diff --git a/packages/frontend-embed/package.json b/packages/frontend-embed/package.json index 3bb8e00d59..fa5ba3038e 100644 --- a/packages/frontend-embed/package.json +++ b/packages/frontend-embed/package.json @@ -12,6 +12,7 @@ "dependencies": { "@discordapp/twemoji": "16.0.1", "@rollup/plugin-json": "6.1.0", + "@rollup/plugin-replace": "6.0.3", "@rollup/pluginutils": "5.3.0", "@twemoji/parser": "16.0.0", "@vitejs/plugin-vue": "6.0.5", @@ -25,9 +26,11 @@ "misskey-js": "workspace:*", "punycode.js": "2.3.1", "rollup": "4.60.0", + "sass": "1.98.0", "shiki": "3.23.0", "tinycolor2": "1.6.0", "uuid": "13.0.0", + "vite": "7.3.1", "vue": "3.5.30" }, "devDependencies": { @@ -54,10 +57,8 @@ "msw": "2.12.14", "nodemon": "3.1.14", "prettier": "3.8.1", - "sass-embedded": "1.98.0", "start-server-and-test": "2.1.5", "tsx": "4.21.0", - "vite": "8.0.2", "vite-plugin-turbosnap": "1.0.3", "vue-component-type-helpers": "3.2.6", "vue-eslint-parser": "10.4.0", diff --git a/packages/frontend-embed/vite.config.ts b/packages/frontend-embed/vite.config.ts index 7f5be591e8..9e5c24f9d4 100644 --- a/packages/frontend-embed/vite.config.ts +++ b/packages/frontend-embed/vite.config.ts @@ -7,10 +7,10 @@ import { promises as fsp } from 'fs'; import locales from 'i18n'; import meta from '../../package.json'; import packageInfo from './package.json' with { type: 'json' }; -import pluginJson5 from './lib/vite-plugin-json5.js'; +import pluginJson5 from './vite.json5.js'; import { pluginRemoveUnrefI18n } from '../frontend-builder/rollup-plugin-remove-unref-i18n'; -const url = process.env.NODE_ENV === 'development' ? (yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')) as any).url : null; +const url = process.env.NODE_ENV === 'development' ? yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')).url : null; const host = url ? (new URL(url)).hostname : undefined; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -113,6 +113,11 @@ export function getConfig(): UserConfig { } }, }, + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, }, define: { @@ -132,10 +137,7 @@ export function getConfig(): UserConfig { 'safari16', ], manifest: 'manifest.json', - rolldownOptions: { - experimental: { - nativeMagicString: true, - }, + rollupOptions: { input: { i18n: './src/i18n.ts', entry: './src/boot.ts', @@ -143,15 +145,10 @@ export function getConfig(): UserConfig { external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', output: { - codeSplitting: { - groups: [{ - name: 'vue', - test: /node_modules[\\/]vue/, - }, { - // dependencies of i18n.ts - name: 'config', - test: /@@[\\/]js[\\/]config\.js/, - }], + manualChunks: { + vue: ['vue'], + // dependencies of i18n.ts + 'config': ['@@/js/config.js'], }, entryFileNames: `scripts/${localesHash}-[hash:8].js`, chunkFileNames: `scripts/${localesHash}-[hash:8].js`, diff --git a/packages/frontend-embed/lib/vite-plugin-json5.ts b/packages/frontend-embed/vite.json5.ts similarity index 90% rename from packages/frontend-embed/lib/vite-plugin-json5.ts rename to packages/frontend-embed/vite.json5.ts index 921324b67a..87b67c2142 100644 --- a/packages/frontend-embed/lib/vite-plugin-json5.ts +++ b/packages/frontend-embed/vite.json5.ts @@ -1,10 +1,7 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ +// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json import JSON5 from 'json5'; -import { Plugin } from 'vite'; +import { Plugin } from 'rollup'; import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { RollupJsonOptions } from '@rollup/plugin-json'; diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts index 0a5000f46d..ccfa08575b 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.test.ts @@ -3,15 +3,15 @@ * SPDX-License-Identifier: AGPL-3.0-only */ +import { parse } from 'acorn'; +import { generate } from 'astring'; import { describe, expect, it } from 'vitest'; import { normalizeClass, unwindCssModuleClassName } from './rollup-plugin-unwind-css-module-class-name.js'; -import { parseAst } from 'rolldown/parseAst'; -import type { ESTree } from 'rolldown/utils'; -import { RolldownMagicString } from 'rolldown'; +import type * as estree from 'estree'; -function parseExpression(code: string): ESTree.Expression { - const program = parseAst(code, { sourceType: 'module' }); - const statement = program.body[0] as ESTree.ExpressionStatement; +function parseExpression(code: string): estree.Expression { + const program = parse(code, { ecmaVersion: 'latest', sourceType: 'module' }) as unknown as estree.Program; + const statement = program.body[0] as estree.ExpressionStatement; return statement.expression; } @@ -57,7 +57,7 @@ describe(normalizeClass.name, () => { }); it('Composition API (standard)', () => { - const code = ` + const ast = parse(` import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; import { M as MkContainer } from './MkContainer-!~{03M}~.js'; import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; @@ -170,19 +170,17 @@ const cssModules = { const index_photos = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); export { index_photos as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - expect(magicString.toString()).toBe( - ` -import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; -import { M as MkContainer } from './MkContainer-!~{03M}~.js'; -import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; +`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); + unwindCssModuleClassName(ast); + expect(generate(ast)).toBe(` +import {c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js'; +import {M as MkContainer} from './MkContainer-!~{03M}~.js'; +import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js'; import './photoswipe-!~{003}~.js'; - -const _hoisted_1 = /* @__PURE__ */ createBaseVNode("i", { class: "ti ti-photo" }, null, -1); -const index_photos = /* @__PURE__ */ defineComponent({ +const _hoisted_1 = createBaseVNode("i", { + class: "ti ti-photo" +}, null, -1); +const index_photos = defineComponent({ __name: "index.photos", props: { user: {} @@ -195,20 +193,12 @@ const index_photos = /* @__PURE__ */ defineComponent({ return store.s.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; } onMounted(() => { - const image = [ - "image/jpeg", - "image/webp", - "image/avif", - "image/png", - "image/gif", - "image/apng", - "image/vnd.mozilla.apng" - ]; + const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"]; api("users/notes", { userId: props.user.id, fileType: image, limit: 10 - }).then((notes) => { + }).then(notes => { for (const note of notes) { for (const file of note.files) { images.value.push({ @@ -223,508 +213,387 @@ const index_photos = /* @__PURE__ */ defineComponent({ return (_ctx, _cache) => { const _component_MkLoading = resolveComponent("MkLoading"); const _component_MkA = resolveComponent("MkA"); - return openBlock(), createBlock(MkContainer, { + return (openBlock(), createBlock(MkContainer, { "max-height": 300, foldable: true }, { - icon: withCtx(() => [ - _hoisted_1 - ]), - header: withCtx(() => [ - createTextVNode(toDisplayString(unref(i18n).ts.images), 1) - ]), - default: withCtx(() => [ - createBaseVNode("div", { - class: "xenMW" - }, [ - unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { key: 0 })) : createCommentVNode("", true), - !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { - key: 1, - class: "xaZzf" - }, [ - (openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), (image) => { - return openBlock(), createBlock(_component_MkA, { - key: image.note.id + image.file.id, - class: "xtA8t", - to: unref(notePage)(image.note) - }, { - default: withCtx(() => [ - createVNode(ImgWithBlurhash, { - hash: image.file.blurhash, - src: thumbnail(image.file), - title: image.file.name - }, null, 8, ["hash", "src", "title"]) - ]), - _: 2 - }, 1032, ["class", "to"]); - }), 128)) - ], 2)) : createCommentVNode("", true), - !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { - key: 2, - class: "xhYKj" - }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true) - ], 2) - ]), + icon: withCtx(() => [_hoisted_1]), + header: withCtx(() => [createTextVNode(toDisplayString(unref(i18n).ts.images), 1)]), + default: withCtx(() => [createBaseVNode("div", { + class: "xenMW" + }, [unref(fetching) ? (openBlock(), createBlock(_component_MkLoading, { + key: 0 + })) : createCommentVNode("", true), !unref(fetching) && unref(images).length > 0 ? (openBlock(), createElementBlock("div", { + key: 1, + class: "xaZzf" + }, [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(images), image => { + return (openBlock(), createBlock(_component_MkA, { + key: image.note.id + image.file.id, + class: "xtA8t", + to: unref(notePage)(image.note) + }, { + default: withCtx(() => [createVNode(ImgWithBlurhash, { + hash: image.file.blurhash, + src: thumbnail(image.file), + title: image.file.name + }, null, 8, ["hash", "src", "title"])]), + _: 2 + }, 1032, ["class", "to"])); + }), 128))], 2)) : createCommentVNode("", true), !unref(fetching) && unref(images).length == 0 ? (openBlock(), createElementBlock("p", { + key: 2, + class: "xhYKj" + }, toDisplayString(unref(i18n).ts.nothing), 3)) : createCommentVNode("", true)], 2)]), _: 1 - }); + })); }; } }); - const root = "xenMW"; const stream = "xaZzf"; const img = "xtA8t"; const empty = "xhYKj"; const style0 = { - root: root, - stream: stream, - img: img, - empty: empty + root: root, + stream: stream, + img: img, + empty: empty }; - const cssModules = { "$style": style0 }; - - -export { index_photos as default }; -`.slice(1), - ); -}); - -it('Composition API (with `useCssModule()`)', () => { - const code = ` -import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; -import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; - -function isDebuggerEnabled(id) { - try { - return localStorage.getItem(\`DEBUG_\${id}\`) !== null; - } catch { - return false; - } -} -function stackTraceInstances() { - let instance = getCurrentInstance(); - const stack = []; - while (instance) { - stack.push(instance); - instance = instance.parent; - } - return stack; -} - -const _sfc_main = defineComponent({ - props: { - items: { - type: Array, - required: true - }, - direction: { - type: String, - required: false, - default: "down" - }, - reversed: { - type: Boolean, - required: false, - default: false - }, - noGap: { - type: Boolean, - required: false, - default: false - }, - ad: { - type: Boolean, - required: false, - default: false - } - }, - setup(props, { slots, expose }) { - const $style = useCssModule(); - function getDateText(time) { - const date = new Date(time).getDate(); - const month = new Date(time).getMonth() + 1; - return i18n.t("monthAndDay", { - month: month.toString(), - day: date.toString() - }); - } - if (props.items.length === 0) - return; - const renderChildrenImpl = () => props.items.map((item, i) => { - if (!slots || !slots.default) - return; - const el = slots.default({ - item - })[0]; - if (el.key == null && item.id) - el.key = item.id; - if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { - const separator = h("div", { - class: $style["separator"], - key: item.id + ":separator" - }, h("p", { - class: $style["date"] - }, [ - h("span", { - class: $style["date-1"] - }, [ - h("i", { - class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` - }), - getDateText(item.createdAt) - ]), - h("span", { - class: $style["date-2"] - }, [ - getDateText(props.items[i + 1].createdAt), - h("i", { - class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` - }) - ]) - ])); - return [el, separator]; - } else { - if (props.ad && item._shouldInsertAd_) { - return [h(MkAd, { - key: item.id + ":ad", - prefer: ["horizontal", "horizontal-big"] - }), el]; - } else { - return el; - } - } - }); - const renderChildren = () => { - const children = renderChildrenImpl(); - if (isDebuggerEnabled(6864)) { - const nodes = children.flatMap((node) => node ?? []); - const keys = new Set(nodes.map((node) => node.key)); - if (keys.size !== nodes.length) { - const id = crypto.randomUUID(); - const instances = stackTraceInstances(); - toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); - console.warn({ id, debugId: 6864, stack: instances }); - } - } - return children; - }; - function onBeforeLeave(el) { - el.style.top = \`\${el.offsetTop}px\`; - el.style.left = \`\${el.offsetLeft}px\`; - } - function onLeaveCanceled(el) { - el.style.top = ""; - el.style.left = ""; - } - return () => h( - prefer.s.animation ? TransitionGroup : "div", - { - class: { - [$style["date-separated-list"]]: true, - [$style["date-separated-list-nogap"]]: props.noGap, - [$style["reversed"]]: props.reversed, - [$style["direction-down"]]: props.direction === "down", - [$style["direction-up"]]: props.direction === "up" - }, - ...prefer.s.animation ? { - name: "list", - tag: "div", - onBeforeLeave, - onLeaveCanceled - } : {} - }, - { default: renderChildren } - ); - } -}); - -const reversed = "xxiZh"; -const separator = "xxeDx"; -const date = "xxawD"; -const style0 = { - "date-separated-list": "xfKPa", - "date-separated-list-nogap": "xf9zr", - "direction-up": "x7AeO", - "direction-down": "xBIqc", - reversed: reversed, - separator: separator, - date: date, - "date-1": "xwtmh", - "date-1-icon": "xsNPa", - "date-2": "x1xvw", - "date-2-icon": "x9ZiG" -}; - -const cssModules = { - "$style": style0 -}; -const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); - -export { MkDateSeparatedList as M }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - expect(magicString.toString()).toBe( - ` -import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; -import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; - -function isDebuggerEnabled(id) { - try { - return localStorage.getItem(\`DEBUG_\${id}\`) !== null; - } catch { - return false; - } -} -function stackTraceInstances() { - let instance = getCurrentInstance(); - const stack = []; - while (instance) { - stack.push(instance); - instance = instance.parent; - } - return stack; -} - -const _sfc_main = defineComponent({ - props: { - items: { - type: Array, - required: true - }, - direction: { - type: String, - required: false, - default: "down" - }, - reversed: { - type: Boolean, - required: false, - default: false - }, - noGap: { - type: Boolean, - required: false, - default: false - }, - ad: { - type: Boolean, - required: false, - default: false - } - }, - setup(props, { slots, expose }) { - const $style = useCssModule(); - function getDateText(time) { - const date = new Date(time).getDate(); - const month = new Date(time).getMonth() + 1; - return i18n.t("monthAndDay", { - month: month.toString(), - day: date.toString() - }); - } - if (props.items.length === 0) - return; - const renderChildrenImpl = () => props.items.map((item, i) => { - if (!slots || !slots.default) - return; - const el = slots.default({ - item - })[0]; - if (el.key == null && item.id) - el.key = item.id; - if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { - const separator = h("div", { - class: $style["separator"], - key: item.id + ":separator" - }, h("p", { - class: $style["date"] - }, [ - h("span", { - class: $style["date-1"] - }, [ - h("i", { - class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` - }), - getDateText(item.createdAt) - ]), - h("span", { - class: $style["date-2"] - }, [ - getDateText(props.items[i + 1].createdAt), - h("i", { - class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` - }) - ]) - ])); - return [el, separator]; - } else { - if (props.ad && item._shouldInsertAd_) { - return [h(MkAd, { - key: item.id + ":ad", - prefer: ["horizontal", "horizontal-big"] - }), el]; - } else { - return el; - } - } - }); - const renderChildren = () => { - const children = renderChildrenImpl(); - if (isDebuggerEnabled(6864)) { - const nodes = children.flatMap((node) => node ?? []); - const keys = new Set(nodes.map((node) => node.key)); - if (keys.size !== nodes.length) { - const id = crypto.randomUUID(); - const instances = stackTraceInstances(); - toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); - console.warn({ id, debugId: 6864, stack: instances }); - } - } - return children; - }; - function onBeforeLeave(el) { - el.style.top = \`\${el.offsetTop}px\`; - el.style.left = \`\${el.offsetLeft}px\`; - } - function onLeaveCanceled(el) { - el.style.top = ""; - el.style.left = ""; - } - return () => h( - prefer.s.animation ? TransitionGroup : "div", - { - class: { - [$style["date-separated-list"]]: true, - [$style["date-separated-list-nogap"]]: props.noGap, - [$style["reversed"]]: props.reversed, - [$style["direction-down"]]: props.direction === "down", - [$style["direction-up"]]: props.direction === "up" - }, - ...prefer.s.animation ? { - name: "list", - tag: "div", - onBeforeLeave, - onLeaveCanceled - } : {} - }, - { default: renderChildren } - ); - } -}); - -const reversed = "xxiZh"; -const separator = "xxeDx"; -const date = "xxawD"; -const style0 = { - "date-separated-list": "xfKPa", - "date-separated-list-nogap": "xf9zr", - "direction-up": "x7AeO", - "direction-down": "xBIqc", - reversed: reversed, - separator: separator, - date: date, - "date-1": "xwtmh", - "date-1-icon": "xsNPa", - "date-2": "x1xvw", - "date-2-icon": "x9ZiG" -}; - -const cssModules = { - "$style": style0 -}; -const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); - -export { MkDateSeparatedList as M }; +export {index_photos as default}; `.slice(1)); }); -it('Composition API (inlined output)', () => { - const code = ` -import { a as normalizeClass, b as defineComponent, c as _export_sfc } from './runtime.js'; +it('Composition API (with `useCssModule()`)', () => { + const ast = parse(` +import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; +import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; -const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ - __name: "CurrentComponent", - setup() { - return (e, n) => h("div", { - class: normalizeClass([e.$style.root, "extra"]) - }, null, 2); +function isDebuggerEnabled(id) { + try { + return localStorage.getItem(\`DEBUG_\${id}\`) !== null; + } catch { + return false; } -}), [["__cssModules", { - "$style": { - root: "x1234" +} +function stackTraceInstances() { + let instance = getCurrentInstance(); + const stack = []; + while (instance) { + stack.push(instance); + instance = instance.parent; } -}]]); + return stack; +} -export { CurrentComponent as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - const output = magicString.toString(); - expect(output).toContain('class: "x1234 extra"'); - expect(output).toContain('defineComponent({'); - expect(output).toContain('}), []);'); - expect(output).not.toContain('$style'); +const _sfc_main = defineComponent({ + props: { + items: { + type: Array, + required: true + }, + direction: { + type: String, + required: false, + default: "down" + }, + reversed: { + type: Boolean, + required: false, + default: false + }, + noGap: { + type: Boolean, + required: false, + default: false + }, + ad: { + type: Boolean, + required: false, + default: false + } + }, + setup(props, { slots, expose }) { + const $style = useCssModule(); + function getDateText(time) { + const date = new Date(time).getDate(); + const month = new Date(time).getMonth() + 1; + return i18n.t("monthAndDay", { + month: month.toString(), + day: date.toString() + }); + } + if (props.items.length === 0) + return; + const renderChildrenImpl = () => props.items.map((item, i) => { + if (!slots || !slots.default) + return; + const el = slots.default({ + item + })[0]; + if (el.key == null && item.id) + el.key = item.id; + if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { + const separator = h("div", { + class: $style["separator"], + key: item.id + ":separator" + }, h("p", { + class: $style["date"] + }, [ + h("span", { + class: $style["date-1"] + }, [ + h("i", { + class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` + }), + getDateText(item.createdAt) + ]), + h("span", { + class: $style["date-2"] + }, [ + getDateText(props.items[i + 1].createdAt), + h("i", { + class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` + }) + ]) + ])); + return [el, separator]; + } else { + if (props.ad && item._shouldInsertAd_) { + return [h(MkAd, { + key: item.id + ":ad", + prefer: ["horizontal", "horizontal-big"] + }), el]; + } else { + return el; + } + } + }); + const renderChildren = () => { + const children = renderChildrenImpl(); + if (isDebuggerEnabled(6864)) { + const nodes = children.flatMap((node) => node ?? []); + const keys = new Set(nodes.map((node) => node.key)); + if (keys.size !== nodes.length) { + const id = crypto.randomUUID(); + const instances = stackTraceInstances(); + toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); + console.warn({ id, debugId: 6864, stack: instances }); + } + } + return children; + }; + function onBeforeLeave(el) { + el.style.top = \`\${el.offsetTop}px\`; + el.style.left = \`\${el.offsetLeft}px\`; + } + function onLeaveCanceled(el) { + el.style.top = ""; + el.style.left = ""; + } + return () => h( + prefer.s.animation ? TransitionGroup : "div", + { + class: { + [$style["date-separated-list"]]: true, + [$style["date-separated-list-nogap"]]: props.noGap, + [$style["reversed"]]: props.reversed, + [$style["direction-down"]]: props.direction === "down", + [$style["direction-up"]]: props.direction === "up" + }, + ...prefer.s.animation ? { + name: "list", + tag: "div", + onBeforeLeave, + onLeaveCanceled + } : {} + }, + { default: renderChildren } + ); + } }); -it('should keep cssModules when unresolved references remain', () => { - const code = ` -import { a as normalizeClass, b as defineComponent, c as _export_sfc } from './runtime.js'; +const reversed = "xxiZh"; +const separator = "xxeDx"; +const date = "xxawD"; +const style0 = { + "date-separated-list": "xfKPa", + "date-separated-list-nogap": "xf9zr", + "direction-up": "x7AeO", + "direction-down": "xBIqc", + reversed: reversed, + separator: separator, + date: date, + "date-1": "xwtmh", + "date-1-icon": "xsNPa", + "date-2": "x1xvw", + "date-2-icon": "x9ZiG" +}; -const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ - __name: "CurrentComponent", - setup() { - return (e, n) => h("div", { - class: normalizeClass([e.$style.root, e.$style[side]]) - }, null, 2); - } -}), [["__cssModules", { - "$style": { - root: "x1234" - } -}]]); +const cssModules = { + "$style": style0 +}; +const MkDateSeparatedList = /* @__PURE__ */ _export_sfc(_sfc_main, [["__cssModules", cssModules]]); -export { CurrentComponent as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - const output = magicString.toString(); - expect(output).toContain('e.$style[side]'); - expect(output).toContain('__cssModules'); - expect(output).not.toContain('}), []);'); +export { MkDateSeparatedList as M }; +`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); + unwindCssModuleClassName(ast); + expect(generate(ast)).toBe(` +import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js'; +import {d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js'; +function isDebuggerEnabled(id) { + try { + return localStorage.getItem(\`DEBUG_\${id}\`) !== null; + } catch { + return false; + } +} +function stackTraceInstances() { + let instance = getCurrentInstance(); + const stack = []; + while (instance) { + stack.push(instance); + instance = instance.parent; + } + return stack; +} +const _sfc_main = defineComponent({ + props: { + items: { + type: Array, + required: true + }, + direction: { + type: String, + required: false, + default: "down" + }, + reversed: { + type: Boolean, + required: false, + default: false + }, + noGap: { + type: Boolean, + required: false, + default: false + }, + ad: { + type: Boolean, + required: false, + default: false + } + }, + setup(props, {slots, expose}) { + const $style = useCssModule(); + function getDateText(time) { + const date = new Date(time).getDate(); + const month = new Date(time).getMonth() + 1; + return i18n.t("monthAndDay", { + month: month.toString(), + day: date.toString() + }); + } + if (props.items.length === 0) return; + const renderChildrenImpl = () => props.items.map((item, i) => { + if (!slots || !slots.default) return; + const el = slots.default({ + item + })[0]; + if (el.key == null && item.id) el.key = item.id; + if (i !== props.items.length - 1 && new Date(item.createdAt).getDate() !== new Date(props.items[i + 1].createdAt).getDate()) { + const separator = h("div", { + class: $style["separator"], + key: item.id + ":separator" + }, h("p", { + class: $style["date"] + }, [h("span", { + class: $style["date-1"] + }, [h("i", { + class: \`ti ti-chevron-up \${$style["date-1-icon"]}\` + }), getDateText(item.createdAt)]), h("span", { + class: $style["date-2"] + }, [getDateText(props.items[i + 1].createdAt), h("i", { + class: \`ti ti-chevron-down \${$style["date-2-icon"]}\` + })])])); + return [el, separator]; + } else { + if (props.ad && item._shouldInsertAd_) { + return [h(MkAd, { + key: item.id + ":ad", + prefer: ["horizontal", "horizontal-big"] + }), el]; + } else { + return el; + } + } + }); + const renderChildren = () => { + const children = renderChildrenImpl(); + if (isDebuggerEnabled(6864)) { + const nodes = children.flatMap(node => node ?? []); + const keys = new Set(nodes.map(node => node.key)); + if (keys.size !== nodes.length) { + const id = crypto.randomUUID(); + const instances = stackTraceInstances(); + toast(instances.reduce((a, c) => \`\${a} at \${c.type.name}\`, \`[DEBUG_6864 (\${id})]: \${nodes.length - keys.size} duplicated keys found\`)); + console.warn({ + id, + debugId: 6864, + stack: instances + }); + } + } + return children; + }; + function onBeforeLeave(el) { + el.style.top = \`\${el.offsetTop}px\`; + el.style.left = \`\${el.offsetLeft}px\`; + } + function onLeaveCanceled(el) { + el.style.top = ""; + el.style.left = ""; + } + return () => h(prefer.s.animation ? TransitionGroup : "div", { + class: { + [$style["date-separated-list"]]: true, + [$style["date-separated-list-nogap"]]: props.noGap, + [$style["reversed"]]: props.reversed, + [$style["direction-down"]]: props.direction === "down", + [$style["direction-up"]]: props.direction === "up" + }, + ...prefer.s.animation ? { + name: "list", + tag: "div", + onBeforeLeave, + onLeaveCanceled + } : {} + }, { + default: renderChildren + }); + } }); - -it('should inline cssModules references used inside class expressions', () => { - const code = ` -import { a as classHelper, b as defineComponent, c as _export_sfc } from './runtime.js'; - -const CurrentComponent = /* @__PURE__ */ _export_sfc(defineComponent({ - __name: "CurrentComponent", - setup() { - return (e, n) => h("div", { - class: classHelper([e.$style.root, { [e.$style.main]: isActive }]) - }, null, 2); - } -}), [["__cssModules", { - "$style": { - root: "x1234", - main: "x5678" - } -}]]); - -export { CurrentComponent as default }; -`.slice(1); - const ast = parseAst(code, { sourceType: 'module' }); - const magicString = new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - const output = magicString.toString(); - expect(output).toContain('class: classHelper(["x1234", { ["x5678"]: isActive }])'); - expect(output).toContain('}), []);'); - expect(output).not.toContain('$style'); +const reversed = "xxiZh"; +const separator = "xxeDx"; +const date = "xxawD"; +const style0 = { + "date-separated-list": "xfKPa", + "date-separated-list-nogap": "xf9zr", + "direction-up": "x7AeO", + "direction-down": "xBIqc", + reversed: reversed, + separator: separator, + date: date, + "date-1": "xwtmh", + "date-1-icon": "xsNPa", + "date-2": "x1xvw", + "date-2-icon": "x9ZiG" +}; +const cssModules = { + "$style": style0 +}; +const MkDateSeparatedList = _export_sfc(_sfc_main, [["__cssModules", cssModules]]); +export {MkDateSeparatedList as M}; +`.slice(1)); }); diff --git a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts index d82f1512fc..7ecb1e9179 100644 --- a/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts +++ b/packages/frontend/lib/rollup-plugin-unwind-css-module-class-name.ts @@ -3,16 +3,17 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import * as estreeWalker from 'estree-walker'; +import { generate } from 'astring'; +import { walk } from '../node_modules/estree-walker/src/index.js'; +import type * as estree from 'estree'; +import type * as estreeWalker from 'estree-walker'; import type { Plugin } from 'vite'; -import type { ESTree } from 'rolldown/utils'; -import { RolldownMagicString } from 'rolldown'; -function isFalsyIdentifier(identifier: Extract): boolean { +function isFalsyIdentifier(identifier: estree.Identifier): boolean { return identifier.name === 'undefined' || identifier.name === 'NaN'; } -function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): string | null { +function normalizeClassWalker(tree: estree.Node, stack: string | undefined): string | null { if (tree.type === 'Identifier') return isFalsyIdentifier(tree) ? '' : null; if (tree.type === 'Literal') return typeof tree.value === 'string' ? tree.value : ''; if (tree.type === 'BinaryExpression') { @@ -25,7 +26,7 @@ function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): str if (tree.type === 'TemplateLiteral') { if (tree.expressions.some((x) => x.type !== 'Literal' && (x.type !== 'Identifier' || !isFalsyIdentifier(x)))) return null; return tree.quasis.reduce((a, c, i) => { - const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial>).value; + const v = i === tree.quasis.length - 1 ? '' : (tree.expressions[i] as Partial).value; return a + c.value.raw + (typeof v === 'string' ? v : ''); }, ''); } @@ -71,144 +72,44 @@ function normalizeClassWalker(tree: ESTree.Node, stack: string | undefined): str tree.type !== 'ChainExpression' && tree.type !== 'ConditionalExpression' && tree.type !== 'LogicalExpression' && - tree.type !== 'MemberExpression' - ) { + tree.type !== 'MemberExpression') { console.error(stack ? `Unexpected node type: ${tree.type} (in ${stack})` : `Unexpected node type: ${tree.type}`); } return null; } -export function normalizeClass(tree: ESTree.Node, stack?: string): string | null { +export function normalizeClass(tree: estree.Node, stack?: string): string | null { const walked = normalizeClassWalker(tree, stack); return walked && walked.replace(/^\s+|\s+(?=\s)|\s+$/g, ''); } -function getPropertyName(node: ESTree.Node, computed: boolean): string | null { - if (node.type === 'Identifier') return computed ? null : node.name; - if (node.type === 'Literal' && typeof node.value === 'string') return node.value; - return null; -} - -function getMemberPropertyName(node: ESTree.MemberExpression['property'], computed: boolean): string | null { - if (node.type === 'Identifier') return computed ? null : node.name; - if (node.type === 'Literal' && typeof node.value === 'string') return node.value; - return null; -} - -function findVariableDeclaration(program: ESTree.Program, name: string): ESTree.VariableDeclaration | null { - return program.body.find((x) => { - if (x.type !== 'VariableDeclaration') return false; - if (x.declarations.length !== 1) return false; - if (x.declarations[0].id.type !== 'Identifier') return false; - return x.declarations[0].id.name === name; - }) as ESTree.VariableDeclaration | null; -} - -function resolveObjectExpression(program: ESTree.Program, tree: ESTree.Expression): ESTree.ObjectExpression | null { - if (tree.type === 'ObjectExpression') return tree; - if (tree.type !== 'Identifier') return null; - const declaration = findVariableDeclaration(program, tree.name); - if (declaration?.declarations[0].init?.type !== 'ObjectExpression') return null; - return declaration.declarations[0].init; -} - -function resolveComponentOptions(program: ESTree.Program, tree: ESTree.Expression): ESTree.ObjectExpression | null { - const target = tree.type === 'Identifier' - ? findVariableDeclaration(program, tree.name)?.declarations[0].init ?? null - : tree; - if (target?.type === 'ObjectExpression') return target; - if (target?.type !== 'CallExpression') return null; - if (target.arguments.length !== 1) return null; - if (target.arguments[0].type !== 'ObjectExpression') return null; - return target.arguments[0]; -} - -function resolveModuleTree(program: ESTree.Program, tree: ESTree.Expression): Map | null { - const objectExpression = resolveObjectExpression(program, tree); - if (objectExpression === null) return null; - return new Map(objectExpression.properties.flatMap((property) => { - if (property.type !== 'Property') return []; - const actualKey = getPropertyName(property.key, property.computed); - if (actualKey === null) return []; - if (property.value.type === 'Literal') { - return typeof property.value.value === 'string' ? [[actualKey, property.value.value]] : []; - } - if (property.value.type === 'Identifier') { - const actualValue = findVariableDeclaration(program, property.value.name); - if (actualValue?.declarations[0].init?.type !== 'Literal') return []; - return typeof actualValue.declarations[0].init.value === 'string' ? [[actualKey, actualValue.declarations[0].init.value]] : []; - } - return []; - })); -} - -function resolveModuleForest(program: ESTree.Program, tree: ESTree.Expression): Map> | null { - const objectExpression = resolveObjectExpression(program, tree); - if (objectExpression === null) return null; - return new Map(objectExpression.properties.flatMap((property) => { - if (property.type !== 'Property') return []; - const actualKey = getPropertyName(property.key, property.computed); - if (actualKey === null) return []; - const moduleTree = resolveModuleTree(program, property.value); - return moduleTree === null ? [] : [[actualKey, moduleTree]]; - })); -} - -function findRenderArrow(options: ESTree.ObjectExpression): Extract | null { - const setup = options.properties.find((x) => { - if (x.type !== 'Property') return false; - return getPropertyName(x.key, x.computed) === 'setup'; - }) as Extract | undefined; - if (setup?.value.type !== 'FunctionExpression' && setup?.value.type !== 'ArrowFunctionExpression') return null; - if (setup.value.body == null) return null; - if (setup.value.body.type !== 'BlockStatement') return null; - const render = setup.value.body.body.find((x) => x.type === 'ReturnStatement'); - if (render?.type !== 'ReturnStatement') return null; - return render.argument?.type === 'ArrowFunctionExpression' ? render.argument : null; -} - -function isCssModuleAccess(node: ESTree.Node, ctxName: string, key: string): node is Extract { - if (node.type !== 'MemberExpression') return false; - if (node.object.type !== 'MemberExpression') return false; - if (node.object.object.type !== 'Identifier') return false; - if (node.object.object.name !== ctxName) return false; - return getMemberPropertyName(node.object.property, node.object.computed) === key; - } - -function isCssModuleReference(node: ESTree.Node, ctxName: string, key: string): node is Extract { - if (!isCssModuleAccess(node, ctxName, key)) return false; - return getMemberPropertyName(node.property, node.computed) !== null; -} - -function isClassProperty(node: ESTree.Node | null): node is Extract { - return node?.type === 'Property' && getPropertyName(node.key, node.computed) === 'class'; -} - -export function unwindCssModuleClassName(ast: ESTree.Node, magicString: RolldownMagicString): void { - (estreeWalker.walk as any)(ast, { - enter(node: ESTree.Node, parent: ESTree.Node | null): void { +export function unwindCssModuleClassName(ast: estree.Node): void { + (walk as typeof estreeWalker.walk)(ast, { + enter(node, parent): void { //#region if (parent?.type !== 'Program') return; - if (ast.type !== 'Program') return; if (node.type !== 'VariableDeclaration') return; if (node.declarations.length !== 1) return; if (node.declarations[0].id.type !== 'Identifier') return; const name = node.declarations[0].id.name; if (node.declarations[0].init?.type !== 'CallExpression') return; + if (node.declarations[0].init.callee.type !== 'Identifier') return; + if (node.declarations[0].init.callee.name !== '_export_sfc') return; if (node.declarations[0].init.arguments.length !== 2) return; - const componentNode = node.declarations[0].init.arguments[0]; - if (componentNode.type !== 'Identifier' && componentNode.type !== 'CallExpression' && componentNode.type !== 'ObjectExpression') return; + if (node.declarations[0].init.arguments[0].type !== 'Identifier') return; + const ident = node.declarations[0].init.arguments[0].name; + if (!ident.startsWith('_sfc_main')) return; if (node.declarations[0].init.arguments[1].type !== 'ArrayExpression') return; if (node.declarations[0].init.arguments[1].elements.length === 0) return; - const cssModulesEntry = node.declarations[0].init.arguments[1].elements.find((x) => { + const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.findIndex((x) => { if (x?.type !== 'ArrayExpression') return false; if (x.elements.length !== 2) return false; if (x.elements[0]?.type !== 'Literal') return false; if (x.elements[0].value !== '__cssModules') return false; + if (x.elements[1]?.type !== 'Identifier') return false; return true; - }) as ESTree.ArrayExpression | undefined; - const __cssModulesIndex = node.declarations[0].init.arguments[1].elements.indexOf(cssModulesEntry ?? null); - if (cssModulesEntry === undefined || __cssModulesIndex < 0) return; + }); + if (!~__cssModulesIndex) return; /* This region assumeed that the entered node looks like the following code. * * ```ts @@ -217,10 +118,21 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - const cssModuleForest = cssModulesEntry.elements[1]; - if (cssModuleForest?.type !== 'Identifier' && cssModuleForest?.type !== 'ObjectExpression') return; - const moduleForest = resolveModuleForest(ast, cssModuleForest); - if (moduleForest === null) return; + const cssModuleForestName = ((node.declarations[0].init.arguments[1].elements[__cssModulesIndex] as estree.ArrayExpression).elements[1] as estree.Identifier).name; + const cssModuleForestNode = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== cssModuleForestName) return false; + if (x.declarations[0].init?.type !== 'ObjectExpression') return false; + return true; + }) as unknown as estree.VariableDeclaration; + const moduleForest = new Map((cssModuleForestNode.declarations[0].init as estree.ObjectExpression).properties.flatMap((property) => { + if (property.type !== 'Property') return []; + if (property.key.type !== 'Literal') return []; + if (property.value.type !== 'Identifier') return []; + return [[property.key.value as string, property.value.name as string]]; + })); /* This region collected a VariableDeclaration node in the module that looks like the following code. * * ```ts @@ -231,13 +143,35 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - const options = resolveComponentOptions(ast, componentNode); - if (options === null) return; - const render = findRenderArrow(options); - if (render === null) return; - if (render.params.length !== 2) return; - const ctx = render.params[0]; + const sfcMain = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== ident) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (sfcMain.declarations[0].init?.type !== 'CallExpression') return; + if (sfcMain.declarations[0].init.callee.type !== 'Identifier') return; + if (sfcMain.declarations[0].init.callee.name !== 'defineComponent') return; + if (sfcMain.declarations[0].init.arguments.length !== 1) return; + if (sfcMain.declarations[0].init.arguments[0].type !== 'ObjectExpression') return; + const setup = sfcMain.declarations[0].init.arguments[0].properties.find((x) => { + if (x.type !== 'Property') return false; + if (x.key.type !== 'Identifier') return false; + if (x.key.name !== 'setup') return false; + return true; + }) as unknown as estree.Property; + if (setup.value.type !== 'FunctionExpression') return; + const render = setup.value.body.body.find((x) => { + if (x.type !== 'ReturnStatement') return false; + return true; + }) as unknown as estree.ReturnStatement; + if (render.argument?.type !== 'ArrowFunctionExpression') return; + if (render.argument.params.length !== 2) return; + const ctx = render.argument.params[0]; if (ctx.type !== 'Identifier') return; + if (ctx.name !== '_ctx') return; + if (render.argument.body.type !== 'BlockStatement') return; /* This region assumed that `sfcMain` looks like the following code. * * ```ts @@ -252,8 +186,33 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown * ``` */ //#endregion - for (const [key, moduleTree] of moduleForest) { + for (const [key, value] of moduleForest) { //#region + const cssModuleTreeNode = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== value) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (cssModuleTreeNode.declarations[0].init?.type !== 'ObjectExpression') return; + const moduleTree = new Map(cssModuleTreeNode.declarations[0].init.properties.flatMap((property) => { + if (property.type !== 'Property') return []; + const actualKey = property.key.type === 'Identifier' ? property.key.name : property.key.type === 'Literal' ? property.key.value : null; + if (typeof actualKey !== 'string') return []; + if (property.value.type === 'Literal') return [[actualKey, property.value.value as string]]; + if (property.value.type !== 'Identifier') return []; + const labelledValue = property.value.name; + const actualValue = parent.body.find((x) => { + if (x.type !== 'VariableDeclaration') return false; + if (x.declarations.length !== 1) return false; + if (x.declarations[0].id.type !== 'Identifier') return false; + if (x.declarations[0].id.name !== labelledValue) return false; + return true; + }) as unknown as estree.VariableDeclaration; + if (actualValue.declarations[0].init?.type !== 'Literal') return []; + return [[actualKey, actualValue.declarations[0].init.value as string]]; + })); /* This region collected VariableDeclaration nodes in the module that looks like the following code. * * ```ts @@ -267,14 +226,17 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node) { - if (!isCssModuleReference(childNode, ctx.name, key)) return; - const actualKey = getMemberPropertyName(childNode.property, childNode.computed); - if (actualKey === null) return; - const actualValue = moduleTree.get(actualKey); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'MemberExpression') return; + if (childNode.object.type !== 'MemberExpression') return; + if (childNode.object.object.type !== 'Identifier') return; + if (childNode.object.object.name !== ctx.name) return; + if (childNode.object.property.type !== 'Identifier') return; + if (childNode.object.property.name !== key) return; + if (childNode.property.type !== 'Identifier') return; + const actualValue = moduleTree.get(childNode.property.name); if (actualValue === undefined) return; - magicString.overwrite(childNode.start, childNode.end, JSON.stringify(actualValue)); this.replace({ type: 'Literal', value: actualValue, @@ -314,13 +276,20 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node) { - if (!isCssModuleReference(childNode, ctx.name, key)) return; - const actualKey = getMemberPropertyName(childNode.property, childNode.computed); - if (actualKey === null) return; - console.error(`Undefined style detected: ${key}.${actualKey} (in ${name})`); - magicString.overwrite(childNode.start, childNode.end, 'undefined'); + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { + if (childNode.type !== 'MemberExpression') return; + if (childNode.object.type !== 'MemberExpression') return; + if (childNode.object.object.type !== 'Identifier') return; + if (childNode.object.object.name !== ctx.name) return; + if (childNode.object.property.type !== 'Identifier') return; + if (childNode.object.property.name !== key) return; + if (childNode.property.type !== 'Identifier') return; + console.error(`Undefined style detected: ${key}.${childNode.property.name} (in ${name})`); + this.replace({ + type: 'Identifier', + name: 'undefined', + }); }, }); /* This region replaced the reference identifier of missing class names in the render function with `undefined`, as in the following code. @@ -331,7 +300,7 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown * ... * return (_ctx, _cache) => { * ... - * return openBlock(), createElementBlock('div', { + * return openBlock(), createElementBlock("div", { * class: normalizeClass(_ctx.$style.hoge), * }, null); * }; @@ -347,7 +316,7 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown * ... * return (_ctx, _cache) => { * ... - * return openBlock(), createElementBlock('div', { + * return openBlock(), createElementBlock("div", { * class: normalizeClass(undefined), * }, null); * }; @@ -357,15 +326,18 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion //#region - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node, childParent: ESTree.Node | null) { + (walk as typeof estreeWalker.walk)(render.argument.body, { + enter(childNode) { if (childNode.type !== 'CallExpression') return; + if (childNode.callee.type !== 'Identifier') return; + if (childNode.callee.name !== 'normalizeClass') return; if (childNode.arguments.length !== 1) return; - if (childNode.callee.type === 'Identifier' && childNode.callee.name !== 'normalizeClass' && !isClassProperty(childParent)) return; - if (childNode.callee.type !== 'Identifier' && !isClassProperty(childParent)) return; const normalized = normalizeClass(childNode.arguments[0], name); if (normalized === null) return; - magicString.overwrite(childNode.start, childNode.end, JSON.stringify(normalized)); + this.replace({ + type: 'Literal', + value: normalized, + }); }, }); /* This region compiled the `normalizeClass` call into a pseudo-AOT compilation, as in the following code. @@ -402,34 +374,19 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown */ //#endregion } - const hasRemainingCssModuleReference = Array.from(moduleForest.keys()).some((key) => { - let found = false; - (estreeWalker.walk as any)(render.body, { - enter(childNode: ESTree.Node) { - if (!isCssModuleAccess(childNode, ctx.name, key)) return; - found = true; - this.skip(); - }, - }); - return found; - }); - if (hasRemainingCssModuleReference) return; //#region if (node.declarations[0].init.arguments[1].elements.length === 1) { - if (componentNode.type === 'Identifier') { - (estreeWalker.walk as any)(ast, { - enter(childNode: ESTree.Node) { - if (childNode.type !== 'Identifier') return; - if (childNode.name !== componentNode.name) return; - magicString.overwrite(childNode.start, childNode.end, name); - }, - }); - magicString.remove(node.start, node.end); - } else { - const removeStart = cssModulesEntry.start; - const removeEnd = node.declarations[0].init.arguments[1].end - 1; - magicString.remove(removeStart, removeEnd); - } + (walk as typeof estreeWalker.walk)(ast, { + enter(childNode) { + if (childNode.type !== 'Identifier') return; + if (childNode.name !== ident) return; + this.replace({ + type: 'Identifier', + name: node.declarations[0].id.name, + }); + }, + }); + this.remove(); /* NOTE: The above logic is valid as long as the following two conditions are met. * * - the uniqueness of `ident` is kept throughout the module @@ -454,10 +411,31 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown }); */ } else { - const nextElement = node.declarations[0].init.arguments[1].elements[__cssModulesIndex + 1]; - const removeStart = node.declarations[0].init.arguments[1].elements[__cssModulesIndex]!.start; - const removeEnd = nextElement ? nextElement.start : node.declarations[0].init.arguments[1].end - 1; - magicString.remove(removeStart, removeEnd); + this.replace({ + type: 'VariableDeclaration', + declarations: [{ + type: 'VariableDeclarator', + id: { + type: 'Identifier', + name: node.declarations[0].id.name, + }, + init: { + type: 'CallExpression', + callee: { + type: 'Identifier', + name: '_export_sfc', + }, + arguments: [{ + type: 'Identifier', + name: ident, + }, { + type: 'ArrayExpression', + elements: node.declarations[0].init.arguments[1].elements.slice(0, __cssModulesIndex).concat(node.declarations[0].init.arguments[1].elements.slice(__cssModulesIndex + 1)), + }], + }, + }], + kind: 'const', + }); } /* This region removed the `__cssModules` reference from the second argument of `_export_sfc`, as in the following code. * @@ -496,11 +474,10 @@ export function unwindCssModuleClassName(ast: ESTree.Node, magicString: Rolldown export default function pluginUnwindCssModuleClassName(): Plugin { return { name: 'UnwindCssModuleClassName', - renderChunk(code, _chunk, _options, meta) { - const ast = ('ast' in meta ? meta.ast ?? this.parse(code) : this.parse(code)) as ESTree.Program; - const magicString = meta.magicString ?? new RolldownMagicString(code); - unwindCssModuleClassName(ast, magicString); - return magicString; + renderChunk(code): { code: string } { + const ast = this.parse(code) as unknown as estree.Node; + unwindCssModuleClassName(ast); + return { code: generate(ast) }; }, }; } diff --git a/packages/frontend/lib/vite-plugin-create-search-index.ts b/packages/frontend/lib/vite-plugin-create-search-index.ts index 4126a4f8c0..cfbba0823c 100644 --- a/packages/frontend/lib/vite-plugin-create-search-index.ts +++ b/packages/frontend/lib/vite-plugin-create-search-index.ts @@ -13,12 +13,11 @@ import { type LogOptions, normalizePath, type Plugin, - type PluginOption, + type PluginOption } from 'vite'; import fs from 'node:fs'; import JSON5 from 'json5'; -import { RolldownMagicString } from 'rolldown'; -import type { TransformResult } from 'rolldown'; +import MagicString, { SourceMap } from 'magic-string'; import path from 'node:path' import { hash, toBase62 } from '../vite.config'; import { minimatch } from 'minimatch'; @@ -64,7 +63,7 @@ interface MarkerRelation { let logger = { info: (msg: string, options?: LogOptions) => { }, warn: (msg: string, options?: LogOptions) => { }, - error: (msg: string, options?: LogErrorOptions) => { }, + error: (msg: string, options?: LogErrorOptions | unknown) => { }, }; let loggerInitialized = false; @@ -461,18 +460,9 @@ function propertyAccessProxy(path: string[]): AccessProxy { const i18nProxy = propertyAccessProxy(['i18n']); -export function collectFileMarkers(id: string, code: string | RolldownMagicString | undefined): SearchIndexItem[] { +export function collectFileMarkers(id: string, code: string): SearchIndexItem[] { try { - let codeStr: string; - if (typeof code === 'string') { - codeStr = code; - } else if (code != null) { - codeStr = code.toString(); - } else { - throw new Error(`Code is undefined for file ${id}`); - } - - const { descriptor, errors } = vueSfcParse(codeStr, { + const { descriptor, errors } = vueSfcParse(code, { filename: id, }); @@ -483,8 +473,7 @@ export function collectFileMarkers(id: string, code: string | RolldownMagicStrin return extractUsageInfoFromTemplateAst(descriptor.template?.ast, id); } catch (error) { - let _error = error instanceof Error ? error : new Error(String(error)); - logger.error(`Error analyzing file ${id}:`, { error: _error }); + logger.error(`Error analyzing file ${id}:`, error); } return []; @@ -492,7 +481,10 @@ export function collectFileMarkers(id: string, code: string | RolldownMagicStrin // endregion -type TransformedCode = Exclude; +type TransformedCode = { + code: string, + map: SourceMap, +}; export class MarkerIdAssigner { // key: file id @@ -517,12 +509,13 @@ export class MarkerIdAssigner { } #processImpl(id: string, code: string): TransformedCode { - const s = new RolldownMagicString(code); // magic-string のインスタンスを作成 + const s = new MagicString(code); // magic-string のインスタンスを作成 const parsed = vueSfcParse(code, { filename: id }); if (!parsed.descriptor.template) { return { - code, // テンプレートがない場合は元のコードを返す + code, + map: s.generateMap({ source: id, includeContent: true }), }; } const ast = parsed.descriptor.template.ast; // テンプレート AST を取得 @@ -530,7 +523,8 @@ export class MarkerIdAssigner { if (!ast) { return { - code, + code: s.toString(), // 変更後のコードを返す + map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生成 (sourceMap: true が必要) }; } @@ -617,6 +611,7 @@ export class MarkerIdAssigner { return { code: s.toString(), // 変更後のコードを返す + map: s.generateMap({ source: id, includeContent: true }), // ソースマップも生成 (sourceMap: true が必要) }; } @@ -647,7 +642,7 @@ export class MarkerIdAssigner { } } -// Vite プラグインとして export +// Rollup プラグインとして export export default function pluginCreateSearchIndex(options: Options): PluginOption { const assigner = new MarkerIdAssigner(); return [ diff --git a/packages/frontend/lib/vite-plugin-watch-locales.ts b/packages/frontend/lib/vite-plugin-watch-locales.ts index 2fed7f60fa..372e9039d5 100644 --- a/packages/frontend/lib/vite-plugin-watch-locales.ts +++ b/packages/frontend/lib/vite-plugin-watch-locales.ts @@ -3,16 +3,16 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import path from 'node:path'; +import path from 'node:path' import locales from 'i18n'; -import type { Plugin } from 'vite'; const localesDir = path.resolve(__dirname, '../../../locales') /** * 外部ファイルを監視し、必要に応じてwebSocketでメッセージを送るViteプラグイン + * @returns {import('vite').Plugin} */ -export default function pluginWatchLocales(): Plugin { +export default function pluginWatchLocales() { return { name: 'watch-locales', diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 7bcf097ec4..a99918e7b6 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -21,7 +21,10 @@ "@github/webauthn-json": "2.1.1", "@mcaptcha/core-glue": "0.1.0-alpha-5", "@misskey-dev/browser-image-resizer": "2024.1.0", - "@sentry/vue": "10.40.0", + "@rollup/plugin-json": "6.1.0", + "@rollup/plugin-replace": "6.0.3", + "@rollup/pluginutils": "5.3.0", + "@sentry/vue": "10.45.0", "@syuilo/aiscript": "1.2.1", "@syuilo/aiscript-0-19-0": "npm:@syuilo/aiscript@^0.19.0", "@twemoji/parser": "16.0.0", @@ -61,20 +64,21 @@ "punycode.js": "2.3.1", "qr-code-styling": "1.9.2", "qr-scanner": "1.4.2", - "sanitize-html": "2.17.1", + "rollup": "4.60.0", + "sanitize-html": "2.17.2", + "sass": "1.98.0", "shiki": "3.23.0", "textarea-caret": "3.1.0", "three": "0.183.2", "throttle-debounce": "5.0.2", "tinycolor2": "1.6.0", "v-code-diff": "1.13.1", + "vite": "7.3.1", "vue": "3.5.30", "wanakana": "5.3.1" }, "devDependencies": { "@misskey-dev/summaly": "5.2.5", - "@rollup/plugin-json": "6.1.0", - "@rollup/pluginutils": "5.3.0", "@storybook/addon-essentials": "8.6.18", "@storybook/addon-interactions": "8.6.18", "@storybook/addon-links": "10.3.3", @@ -119,6 +123,7 @@ "estree-walker": "3.0.3", "happy-dom": "20.8.8", "intersection-observer": "0.12.2", + "magic-string": "0.30.21", "micromatch": "4.0.8", "minimatch": "10.2.4", "msw": "2.12.14", @@ -127,14 +132,11 @@ "prettier": "3.8.1", "react": "19.2.4", "react-dom": "19.2.4", - "rolldown": "1.0.0-rc.11", - "sass-embedded": "1.98.0", "seedrandom": "3.0.5", "start-server-and-test": "2.1.5", "storybook": "10.3.3", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "tsx": "4.21.0", - "vite": "8.0.2", "vite-plugin-glsl": "1.5.6", "vite-plugin-turbosnap": "1.0.3", "vitest": "4.1.1", diff --git a/packages/frontend/vite.config.ts b/packages/frontend/vite.config.ts index b061733333..260d1215df 100644 --- a/packages/frontend/vite.config.ts +++ b/packages/frontend/vite.config.ts @@ -1,7 +1,7 @@ import path from 'path'; +import pluginReplace from '@rollup/plugin-replace'; import pluginVue from '@vitejs/plugin-vue'; import pluginGlsl from 'vite-plugin-glsl'; -import { replacePlugin } from 'rolldown/plugins'; import type { UserConfig } from 'vite'; import { defineConfig } from 'vite'; import * as yaml from 'js-yaml'; @@ -11,13 +11,13 @@ import locales from 'i18n'; import meta from '../../package.json'; import packageInfo from './package.json' with { type: 'json' }; import pluginUnwindCssModuleClassName from './lib/rollup-plugin-unwind-css-module-class-name.js'; -import pluginJson5 from './lib/vite-plugin-json5.js'; +import pluginJson5 from './vite.json5.js'; import type { Options as SearchIndexOptions } from './lib/vite-plugin-create-search-index.js'; import pluginCreateSearchIndex from './lib/vite-plugin-create-search-index.js'; import pluginWatchLocales from './lib/vite-plugin-watch-locales.js'; import { pluginRemoveUnrefI18n } from '../frontend-builder/rollup-plugin-remove-unref-i18n.js'; -const url = process.env.NODE_ENV === 'development' ? (yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')) as any).url : null; +const url = process.env.NODE_ENV === 'development' ? yaml.load(await fsp.readFile('../../.config/default.yml', 'utf-8')).url : null; const host = url ? (new URL(url)).hostname : undefined; const extensions = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.json', '.json5', '.svg', '.sass', '.scss', '.css', '.vue']; @@ -121,10 +121,11 @@ export function getConfig(): UserConfig { pluginGlsl({ minify: true }), ...process.env.NODE_ENV === 'production' ? [ - replacePlugin({ - 'isChromatic()': JSON.stringify(false), - }, { + pluginReplace({ preventAssignment: true, + values: { + 'isChromatic()': JSON.stringify(false), + }, }), ] : [], @@ -153,6 +154,11 @@ export function getConfig(): UserConfig { } }, }, + preprocessorOptions: { + scss: { + api: 'modern-compiler', + }, + }, }, define: { @@ -172,10 +178,7 @@ export function getConfig(): UserConfig { 'safari16', ], manifest: 'manifest.json', - rolldownOptions: { - experimental: { - nativeMagicString: true, - }, + rollupOptions: { input: { i18n: './src/i18n.ts', entry: './src/_boot_.ts', @@ -183,18 +186,11 @@ export function getConfig(): UserConfig { external: externalPackages.map(p => p.match), preserveEntrySignatures: 'allow-extension', output: { - codeSplitting: { - groups: [{ - name: 'vue', - test: /node_modules[\\/]vue/, - }, { - name: 'photoswipe', - test: /node_modules[\\/]photoswipe/, - }, { - // dependencies of i18n.ts - name: 'config', - test: /@@[\\/]js[\\/]config\.js/, - }], + manualChunks: { + vue: ['vue'], + photoswipe: ['photoswipe', 'photoswipe/lightbox', 'photoswipe/style.css'], + // dependencies of i18n.ts + 'config': ['@@/js/config.js'], }, entryFileNames: `scripts/${localesHash}-[hash:8].js`, chunkFileNames: `scripts/${localesHash}-[hash:8].js`, diff --git a/packages/frontend/lib/vite-plugin-json5.ts b/packages/frontend/vite.json5.ts similarity index 90% rename from packages/frontend/lib/vite-plugin-json5.ts rename to packages/frontend/vite.json5.ts index 921324b67a..87b67c2142 100644 --- a/packages/frontend/lib/vite-plugin-json5.ts +++ b/packages/frontend/vite.json5.ts @@ -1,10 +1,7 @@ -/* - * SPDX-FileCopyrightText: syuilo and misskey-project - * SPDX-License-Identifier: AGPL-3.0-only - */ +// Original: https://github.com/rollup/plugins/tree/8835dd2aed92f408d7dc72d7cc25a9728e16face/packages/json import JSON5 from 'json5'; -import { Plugin } from 'vite'; +import { Plugin } from 'rollup'; import { createFilter, dataToEsm } from '@rollup/pluginutils'; import { RollupJsonOptions } from '@rollup/plugin-json'; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32f051d31d..1c16139fa4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -557,8 +557,8 @@ importers: specifier: 7.2.2 version: 7.2.2 vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@swc/core-android-arm64': specifier: 1.3.11 @@ -665,9 +665,18 @@ importers: '@misskey-dev/browser-image-resizer': specifier: 2024.1.0 version: 2024.1.0 + '@rollup/plugin-json': + specifier: 6.1.0 + version: 6.1.0(rollup@4.60.0) + '@rollup/plugin-replace': + specifier: 6.0.3 + version: 6.0.3(rollup@4.60.0) + '@rollup/pluginutils': + specifier: 5.3.0 + version: 5.3.0(rollup@4.60.0) '@sentry/vue': - specifier: 10.40.0 - version: 10.40.0(vue@3.5.30(typescript@5.9.3)) + specifier: 10.45.0 + version: 10.45.0(vue@3.5.30(typescript@5.9.3)) '@syuilo/aiscript': specifier: 1.2.1 version: 1.2.1 @@ -679,7 +688,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) aiscript-vscode: specifier: github:aiscript-dev/aiscript-vscode#v0.1.16 version: https://codeload.github.com/aiscript-dev/aiscript-vscode/tar.gz/1dc7f60cda78d030dadfc518a33c472202b2ef67 @@ -785,9 +794,15 @@ importers: qr-scanner: specifier: 1.4.2 version: 1.4.2 + rollup: + specifier: 4.60.0 + version: 4.60.0 sanitize-html: - specifier: 2.17.1 - version: 2.17.1 + specifier: 2.17.2 + version: 2.17.2 + sass: + specifier: 1.98.0 + version: 1.98.0 shiki: specifier: 3.23.0 version: 3.23.0 @@ -806,6 +821,9 @@ importers: v-code-diff: specifier: 1.13.1 version: 1.13.1(vue@3.5.30(typescript@5.9.3)) + vite: + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -816,12 +834,6 @@ importers: '@misskey-dev/summaly': specifier: 5.2.5 version: 5.2.5 - '@rollup/plugin-json': - specifier: 6.1.0 - version: 6.1.0(rollup@4.60.0) - '@rollup/pluginutils': - specifier: 5.3.0 - version: 5.3.0(rollup@4.60.0) '@storybook/addon-essentials': specifier: 8.6.18 version: 8.6.18(@types/react@19.2.2)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) @@ -857,7 +869,7 @@ importers: version: 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) '@storybook/react-vite': specifier: 10.3.3 - version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/test': specifier: 8.6.18 version: 8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6)) @@ -872,7 +884,7 @@ importers: version: 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) '@storybook/vue3-vite': specifier: 10.3.3 - version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) '@tabler/icons-webfont': specifier: 3.35.0 version: 3.35.0 @@ -923,7 +935,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/compiler-core': specifier: 3.5.30 version: 3.5.30 @@ -954,6 +966,9 @@ importers: intersection-observer: specifier: 0.12.2 version: 0.12.2 + magic-string: + specifier: 0.30.21 + version: 0.30.21 micromatch: specifier: 4.0.8 version: 4.0.8 @@ -978,12 +993,6 @@ importers: react-dom: specifier: 19.2.4 version: 19.2.4(react@19.2.4) - rolldown: - specifier: 1.0.0-rc.11 - version: 1.0.0-rc.11 - sass-embedded: - specifier: 1.98.0 - version: 1.98.0 seedrandom: specifier: 3.0.5 version: 3.0.5 @@ -999,21 +1008,18 @@ importers: tsx: specifier: 4.21.0 version: 4.21.0 - vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vite-plugin-glsl: specifier: 1.5.6 - version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 vitest: specifier: 4.1.1 - version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-fetch-mock: specifier: 0.4.5 - version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) vue-component-type-helpers: specifier: 3.2.6 version: 3.2.6 @@ -1035,12 +1041,9 @@ importers: magic-string: specifier: 0.30.21 version: 0.30.21 - rolldown: - specifier: 1.0.0-rc.11 - version: 1.0.0-rc.11 vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) devDependencies: '@types/estree': specifier: 1.0.8 @@ -1066,6 +1069,9 @@ importers: '@rollup/plugin-json': specifier: 6.1.0 version: 6.1.0(rollup@4.60.0) + '@rollup/plugin-replace': + specifier: 6.0.3 + version: 6.0.3(rollup@4.60.0) '@rollup/pluginutils': specifier: 5.3.0 version: 5.3.0(rollup@4.60.0) @@ -1074,7 +1080,7 @@ importers: version: 16.0.0 '@vitejs/plugin-vue': specifier: 6.0.5 - version: 6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) + version: 6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3)) buraha: specifier: 0.0.1 version: 0.0.1 @@ -1105,6 +1111,9 @@ importers: rollup: specifier: 4.60.0 version: 4.60.0 + sass: + specifier: 1.98.0 + version: 1.98.0 shiki: specifier: 3.23.0 version: 3.23.0 @@ -1114,6 +1123,9 @@ importers: uuid: specifier: 13.0.0 version: 13.0.0 + vite: + specifier: 7.3.1 + version: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: specifier: 3.5.30 version: 3.5.30(typescript@5.9.3) @@ -1153,7 +1165,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) '@vue/runtime-core': specifier: 3.5.30 version: 3.5.30 @@ -1187,18 +1199,12 @@ importers: prettier: specifier: 3.8.1 version: 3.8.1 - sass-embedded: - specifier: 1.98.0 - version: 1.98.0 start-server-and-test: specifier: 2.1.5 version: 2.1.5 tsx: specifier: 4.21.0 version: 4.21.0 - vite: - specifier: 8.0.2 - version: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vite-plugin-turbosnap: specifier: 1.0.3 version: 1.0.3 @@ -1371,7 +1377,7 @@ importers: version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) '@vitest/coverage-v8': specifier: 4.1.1 - version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) esbuild: specifier: 0.27.4 version: 0.27.4 @@ -1389,10 +1395,10 @@ importers: version: 0.33.0 vitest: specifier: 4.1.1 - version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + version: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) vitest-websocket-mock: specifier: 0.5.0 - version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) + version: 0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))) packages/misskey-js/generator: devDependencies: @@ -1865,9 +1871,6 @@ packages: '@borewit/text-codec@0.1.1': resolution: {integrity: sha512-5L/uBxmjaCIX5h8Z+uu+kA9BQLkc/Wl06UGR5ajNRxu+/XjonB5i8JpgFMrPj3LXTCPA0pv8yxUvbUi+QthGGA==} - '@bufbuild/protobuf@2.11.0': - resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} - '@canvas/image-data@1.1.0': resolution: {integrity: sha512-QdObRRjRbcXGmM1tmJ+MrHcaz1MftF2+W7YI+MsphnsCrmtyfS0d5qJbk0MeSbUeyM/jCb0hmnkXPsy026L7dA==} @@ -1952,15 +1955,9 @@ packages: '@discordapp/twemoji@16.0.1': resolution: {integrity: sha512-figLiBWzjS5cyrAjLaGjM8AAaowO3qvK8rg5bA2dElB4qsaPMvBVlFDMO2d3x+nC1igt7kgWH4dvNmvvUHUF8w==} - '@emnapi/core@1.9.1': - resolution: {integrity: sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA==} - '@emnapi/runtime@1.7.1': resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - '@emnapi/wasi-threads@1.2.0': - resolution: {integrity: sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==} - '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -2877,9 +2874,6 @@ packages: resolution: {integrity: sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@1.1.1': - resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==} - '@nestjs/common@11.1.17': resolution: {integrity: sha512-hLODw5Abp8OQgA+mUO4tHou4krKgDtUcM9j5Ihxncst9XeyxYBTt2bwZm4e4EQr5E352S4Fyy6V3iFx9ggxKAg==} peerDependencies: @@ -3179,9 +3173,6 @@ packages: peerDependencies: '@opentelemetry/api': ^1.1.0 - '@oxc-project/types@0.122.0': - resolution: {integrity: sha512-oLAl5kBpV4w69UtFZ9xqcmTi+GENWOcPF7FCrczTiBbmC0ibXxCwyvZGbO39rCVEuLGAZM84DH0pUIyyv/YJzA==} - '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -3352,104 +3343,6 @@ packages: resolution: {integrity: sha512-2+O+riuIUgVSuLl3Lyh5AplWZyVMNuG2F98/o6NrutKJfW4/GTZdPpZlIphS0HGgcOHgmWcCSHj+dWFlZaGSHw==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - '@rolldown/binding-android-arm64@1.0.0-rc.11': - resolution: {integrity: sha512-SJ+/g+xNnOh6NqYxD0V3uVN4W3VfnrGsC9/hoglicgTNfABFG9JjISvkkU0dNY84MNHLWyOgxP9v9Y9pX4S7+A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.0-rc.11': - resolution: {integrity: sha512-7WQgR8SfOPwmDZGFkThUvsmd/nwAWv91oCO4I5LS7RKrssPZmOt7jONN0cW17ydGC1n/+puol1IpoieKqQidmg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-rc.11': - resolution: {integrity: sha512-39Ks6UvIHq4rEogIfQBoBRusj0Q0nPVWIvqmwBLaT6aqQGIakHdESBVOPRRLacy4WwUPIx4ZKzfZ9PMW+IeyUQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.0.0-rc.11': - resolution: {integrity: sha512-jfsm0ZHfhiqrvWjJAmzsqiIFPz5e7mAoCOPBNTcNgkiid/LaFKiq92+0ojH+nmJmKYkre4t71BWXUZDNp7vsag==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': - resolution: {integrity: sha512-zjQaUtSyq1nVe3nxmlSCuR96T1LPlpvmJ0SZy0WJFEsV4kFbXcq2u68L4E6O0XeFj4aex9bEauqjW8UQBeAvfQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-WMW1yE6IOnehTcFE9eipFkm3XN63zypWlrJQ2iF7NrQ9b2LDRjumFoOGJE8RJJTJCTBAdmLMnJ8uVitACUUo1Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': - resolution: {integrity: sha512-jfndI9tsfm4APzjNt6QdBkYwre5lRPUgHeDHoI7ydKUuJvz3lZeCfMsI56BZj+7BYqiKsJm7cfd/6KYV7ubrBg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-ZlFgw46NOAGMgcdvdYwAGu2Q+SLFA9LzbJLW+iyMOJyhj5wk6P3KEE9Gct4xWwSzFoPI7JCdYmYMzVtlgQ+zfw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-hIOYmuT6ofM4K04XAZd3OzMySEO4K0/nc9+jmNcxNAxRi6c5UWpqfw3KMFV4MVFWL+jQsSh+bGw2VqmaPMTLyw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': - resolution: {integrity: sha512-qXBQQO9OvkjjQPLdUVr7Nr2t3QTZI7s4KZtfw7HzBgjbmAPSFwSv4rmET9lLSgq3rH/ndA3ngv3Qb8l2njoPNA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': - resolution: {integrity: sha512-/tpFfoSTzUkH9LPY+cYbqZBDyyX62w5fICq9qzsHLL8uTI6BHip3Q9Uzft0wylk/i8OOwKik8OxW+QAhDmzwmg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': - resolution: {integrity: sha512-mcp3Rio2w72IvdZG0oQ4bM2c2oumtwHfUfKncUM6zGgz0KgPz4YmDPQfnXEiY5t3+KD/i8HG2rOB/LxdmieK2g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': - resolution: {integrity: sha512-LXk5Hii1Ph9asuGRjBuz8TUxdc1lWzB7nyfdoRgI0WGPZKmCxvlKk8KfYysqtr4MfGElu/f/pEQRh8fcEgkrWw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': - resolution: {integrity: sha512-dDwf5otnx0XgRY1yqxOC4ITizcdzS/8cQ3goOWv3jFAo4F+xQYni+hnMuO6+LssHHdJW7+OCVL3CoU4ycnh35Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': - resolution: {integrity: sha512-LN4/skhSggybX71ews7dAj6r2geaMJfm3kMbK2KhFMg9B10AZXnKoLCVVgzhMHL0S+aKtr4p8QbAW8k+w95bAA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.0-rc.11': - resolution: {integrity: sha512-xQO9vbwBecJRv9EUcQ/y0dzSTJgA7Q6UVN7xp6B81+tBGSLVAK03yJ9NkJaUA7JFD91kbjxRSC/mDnmvXzbHoQ==} - '@rolldown/pluginutils@1.0.0-rc.2': resolution: {integrity: sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==} @@ -3462,6 +3355,15 @@ packages: rollup: optional: true + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + '@rollup/pluginutils@5.3.0': resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} engines: {node: '>=14.0.0'} @@ -3645,18 +3547,10 @@ packages: '@sec-ant/readable-stream@0.4.1': resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} - '@sentry-internal/browser-utils@10.40.0': - resolution: {integrity: sha512-3CDeVNBXYOIvBVdT0SOdMZx5LzYDLuhGK/z7A14sYZz4Cd2+f4mSeFDaEOoH/g2SaY2CKR5KGkAADy8IyjZ21w==} - engines: {node: '>=18'} - '@sentry-internal/browser-utils@10.45.0': resolution: {integrity: sha512-ZPZpeIarXKScvquGx2AfNKcYiVNDA4wegMmjyGVsTA2JPmP0TrJoO3UybJS6KGDeee8V3I3EfD/ruauMm7jOFQ==} engines: {node: '>=18'} - '@sentry-internal/feedback@10.40.0': - resolution: {integrity: sha512-V/ixkcdCNMo04KgsCEeNEu966xUUTD6czKT2LOAO5siZACqFjT/Rp9VR1n7QQrVo3sL7P3QNiTHtX0jaeWbwzg==} - engines: {node: '>=18'} - '@sentry-internal/feedback@10.45.0': resolution: {integrity: sha512-vCSurazFVq7RUeYiM5X326jA5gOVrWYD6lYX2fbjBOMcyCEhDnveNxMT62zKkZDyNT/jyD194nz/cjntBUkyWA==} engines: {node: '>=18'} @@ -3665,34 +3559,18 @@ packages: resolution: {integrity: sha512-oLHVYurqZfADPh5hvmQYS5qx8t0UZzT2u6+/68VXsFruQEOnYJTODKgU3BVLmemRs3WE6kCJjPeFdHVYOQGSzQ==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.40.0': - resolution: {integrity: sha512-wzQwilFHO2baeCt0dTMf0eW+rgK8O+mkisf9sQzPXzG3Krr/iVtFg1T5T1Th3YsCsEdn6yQ3hcBPLEXjMSvccg==} - engines: {node: '>=18'} - '@sentry-internal/replay-canvas@10.45.0': resolution: {integrity: sha512-nvq/AocdZTuD7y0KSiWi3gVaY0s5HOFy86mC/v1kDZmT/jsBAzN5LDkk/f1FvsWma1peqQmpUqxvhC+YIW294Q==} engines: {node: '>=18'} - '@sentry-internal/replay@10.40.0': - resolution: {integrity: sha512-vsH2Ut0KIIQIHNdS3zzEGLJ2C9btbpvJIWAVk7l7oft66JzlUNC89qNaQ5SAypjLQx4Ln2V/ZTqfEoNzXOAsoQ==} - engines: {node: '>=18'} - '@sentry-internal/replay@10.45.0': resolution: {integrity: sha512-vjosRoGA1bzhVAEO1oce+CsRdd70quzBeo7WvYqpcUnoLe/Rv8qpOMqWX3j26z7XfFHMExWQNQeLxmtYOArvlw==} engines: {node: '>=18'} - '@sentry/browser@10.40.0': - resolution: {integrity: sha512-nCt3FKUMFad0C6xl5wCK0Jz+qT4Vev4fv6HJRn0YoNRRDQCfsUVxAz7pNyyiPNGM/WCDp9wJpGJsRvbBRd2anw==} - engines: {node: '>=18'} - '@sentry/browser@10.45.0': resolution: {integrity: sha512-e/a8UMiQhqqv706McSIcG6XK+AoQf9INthi2pD+giZfNRTzXTdqHzUT5OIO5hg8Am6eF63nDJc+vrYNPhzs51Q==} engines: {node: '>=18'} - '@sentry/core@10.40.0': - resolution: {integrity: sha512-/wrcHPp9Avmgl6WBimPjS4gj810a1wU5oX9fF1bzJfeIIbF3jTsAbv0oMbgDp0cSDnkwv2+NvcPnn3+c5J6pBA==} - engines: {node: '>=18'} - '@sentry/core@10.45.0': resolution: {integrity: sha512-s69UXxvefeQxuZ5nY7/THtTrIEvJxNVCp3ns4kwoCw1qMpgpvn/296WCKVmM7MiwnaAdzEKnAvLAwaxZc2nM7Q==} engines: {node: '>=18'} @@ -3743,19 +3621,6 @@ packages: engines: {node: '>=18'} hasBin: true - '@sentry/vue@10.40.0': - resolution: {integrity: sha512-VnsGlSgG4RBgxcsGwS5+5XNUZackUsApgKdCjmwkwWchvLMm1S/RXMXBHT01BabcmUNjxmzWEfI7aboVUoLiGA==} - engines: {node: '>=18'} - peerDependencies: - '@tanstack/vue-router': ^1.64.0 - pinia: 2.x || 3.x - vue: 2.x || 3.x - peerDependenciesMeta: - '@tanstack/vue-router': - optional: true - pinia: - optional: true - '@sentry/vue@10.45.0': resolution: {integrity: sha512-p6ghTgQtiCBZ+Yw0B2xmC69S8AdCRRsYvbTHW7MJYspwNnJDs7rqgCBqOxNhvr3tsKdDuEOEHLtf/5hbKi+8xQ==} engines: {node: '>=18'} @@ -4535,9 +4400,6 @@ packages: '@twemoji/parser@16.0.0': resolution: {integrity: sha512-jmuIjkp3OIaEemwMy3sArBwZSuZkRqmueGwRe2Zk4cFzbUJISFBJSZLDUUBNIgq3c+nY49ideYN2OiII6JUqwA==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} - '@types/accepts@1.3.7': resolution: {integrity: sha512-Pay9fq2lM2wXPWbteBsRAGiWH2hig4ZE2asK+mm7kUzlxRTfL961rj89I6zV/E3PcIkDqyuBEcMxFT7rccugeQ==} @@ -5916,9 +5778,6 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - colorjs.io@0.5.2: - resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} - colors@1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} engines: {node: '>=0.1.90'} @@ -7225,9 +7084,6 @@ packages: htmlparser2@10.1.0: resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} - htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} @@ -7989,80 +7845,6 @@ packages: light-my-request@6.6.0: resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - libc: [musl] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [glibc] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - libc: [musl] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -9708,11 +9490,6 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - rolldown@1.0.0-rc.11: - resolution: {integrity: sha512-NRjoKMusSjfRbSYiH3VSumlkgFe7kYAa3pzVOsVYVFY3zb5d7nS+a3KGQ7hJKXuYWbzJKPVQ9Wxq2UvyK+ENpw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - rollup@4.60.0: resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -9763,129 +9540,9 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.17.1: - resolution: {integrity: sha512-ehFCW+q1a4CSOWRAdX97BX/6/PDEkCqw7/0JXZAGQV57FQB3YOkTa/rrzHPeJ+Aghy4vZAFfWMYyfxIiB7F/gw==} - sanitize-html@2.17.2: resolution: {integrity: sha512-EnffJUl46VE9uvZ0XeWzObHLurClLlT12gsOk1cHyP2Ol1P0BnBnsXmShlBmWVJM+dKieQI68R0tsPY5m/B+Jg==} - sass-embedded-all-unknown@1.98.0: - resolution: {integrity: sha512-6n4RyK7/1mhdfYvpP3CClS3fGoYqDvRmLClCESS6I7+SAzqjxvGG6u5Fo+cb1nrPNbbilgbM4QKdgcgWHO9NCA==} - cpu: ['!arm', '!arm64', '!riscv64', '!x64'] - - sass-embedded-android-arm64@1.98.0: - resolution: {integrity: sha512-M9Ra98A6vYJHpwhoC/5EuH1eOshQ9ZyNwC8XifUDSbRl/cGeQceT1NReR9wFj3L7s1pIbmes1vMmaY2np0uAKQ==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [android] - - sass-embedded-android-arm@1.98.0: - resolution: {integrity: sha512-LjGiMhHgu7VL1n7EJxTCre1x14bUsWd9d3dnkS2rku003IWOI/fxc7OXgaKagoVzok1kv09rzO3vFXJR5ZeONQ==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [android] - - sass-embedded-android-riscv64@1.98.0: - resolution: {integrity: sha512-WPe+0NbaJIZE1fq/RfCZANMeIgmy83x4f+SvFOG7LhUthHpZWcOcrPTsCKKmN3xMT3iw+4DXvqTYOCYGRL3hcQ==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [android] - - sass-embedded-android-x64@1.98.0: - resolution: {integrity: sha512-zrD25dT7OHPEgLWuPEByybnIfx4rnCtfge4clBgjZdZ3lF6E7qNLRBtSBmoFflh6Vg0RlEjJo5VlpnTMBM5MQQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [android] - - sass-embedded-darwin-arm64@1.98.0: - resolution: {integrity: sha512-cgr1z9rBnCdMf8K+JabIaYd9Rag2OJi5mjq08XJfbJGMZV/TA6hFJCLGkr5/+ZOn4/geTM5/3aSfQ8z5EIJAOg==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [darwin] - - sass-embedded-darwin-x64@1.98.0: - resolution: {integrity: sha512-OLBOCs/NPeiMqTdOrMFbVHBQFj19GS3bSVSxIhcCq16ZyhouUkYJEZjxQgzv9SWA2q6Ki8GCqp4k6jMeUY9dcA==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [darwin] - - sass-embedded-linux-arm64@1.98.0: - resolution: {integrity: sha512-axOE3t2MTBwCtkUCbrdM++Gj0gC0fdHJPrgzQ+q1WUmY9NoNMGqflBtk5mBZaWUeha2qYO3FawxCB8lctFwCtw==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - libc: glibc - - sass-embedded-linux-arm@1.98.0: - resolution: {integrity: sha512-03baQZCxVyEp8v1NWBRlzGYrmVT/LK7ZrHlF1piscGiGxwfdxoLXVuxsylx3qn/dD/4i/rh7Bzk7reK1br9jvQ==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - libc: glibc - - sass-embedded-linux-musl-arm64@1.98.0: - resolution: {integrity: sha512-LeqNxQA8y4opjhe68CcFvMzCSrBuJqYVFbwElEj9bagHXQHTp9xVPJRn6VcrC+0VLEDq13HVXMv7RslIuU0zmA==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - libc: musl - - sass-embedded-linux-musl-arm@1.98.0: - resolution: {integrity: sha512-OBkjTDPYR4hSaueOGIM6FDpl9nt/VZwbSRpbNu9/eEJcxE8G/vynRugW8KRZmCFjPy8j/jkGBvvS+k9iOqKV3g==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - libc: musl - - sass-embedded-linux-musl-riscv64@1.98.0: - resolution: {integrity: sha512-7w6hSuOHKt8FZsmjRb3iGSxEzM87fO9+M8nt5JIQYMhHTj5C+JY/vcske0v715HCVj5e1xyTnbGXf8FcASeAIw==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [linux] - libc: musl - - sass-embedded-linux-musl-x64@1.98.0: - resolution: {integrity: sha512-QikNyDEJOVqPmxyCFkci8ZdCwEssdItfjQFJB+D+Uy5HFqcS5Lv3d3GxWNX/h1dSb23RPyQdQc267ok5SbEyJw==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - libc: musl - - sass-embedded-linux-riscv64@1.98.0: - resolution: {integrity: sha512-E7fNytc/v4xFBQKzgzBddV/jretA4ULAPO6XmtBiQu4zZBdBozuSxsQLe2+XXeb0X4S2GIl72V7IPABdqke/vA==} - engines: {node: '>=14.0.0'} - cpu: [riscv64] - os: [linux] - libc: glibc - - sass-embedded-linux-x64@1.98.0: - resolution: {integrity: sha512-VsvP0t/uw00mMNPv3vwyYKUrFbqzxQHnRMO+bHdAMjvLw4NFf6mscpym9Bzf+NXwi1ZNKnB6DtXjmcpcvqFqYg==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - libc: glibc - - sass-embedded-unknown-all@1.98.0: - resolution: {integrity: sha512-C4MMzcAo3oEDQnW7L8SBgB9F2Fq5qHPnaYTZRMOH3Mp/7kM4OooBInXpCiiFjLnjY95hzP4KyctVx0uYR6MYlQ==} - os: ['!android', '!darwin', '!linux', '!win32'] - - sass-embedded-win32-arm64@1.98.0: - resolution: {integrity: sha512-nP/10xbAiPbhQkMr3zQfXE4TuOxPzWRQe1Hgbi90jv2R4TbzbqQTuZVOaJf7KOAN4L2Bo6XCTRjK5XkVnwZuwQ==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [win32] - - sass-embedded-win32-x64@1.98.0: - resolution: {integrity: sha512-/lbrVsfbcbdZQ5SJCWcV0NVPd6YRs+FtAnfedp4WbCkO/ZO7Zt/58MvI4X2BVpRY/Nt5ZBo1/7v2gYcQ+J4svQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [win32] - - sass-embedded@1.98.0: - resolution: {integrity: sha512-Do7u6iRb6K+lrllcTkB1BXcHwOxcKe3rEfOF/GcCLE2w3WpddakRAosJOHFUR37DpsvimQXEt5abs3NzUjEIqg==} - engines: {node: '>=16.0.0'} - hasBin: true - sass@1.98.0: resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} engines: {node: '>=14.0.0'} @@ -10445,14 +10102,6 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - sync-child-process@1.0.2: - resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} - engines: {node: '>=16.0.0'} - - sync-message-port@1.2.0: - resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} - engines: {node: '>=16.0.0'} - systeminformation@5.31.5: resolution: {integrity: sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==} engines: {node: '>=8.0.0'} @@ -10970,9 +10619,6 @@ packages: validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - varint@6.0.0: - resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -11003,16 +10649,15 @@ packages: vite-plugin-turbosnap@1.0.3: resolution: {integrity: sha512-p4D8CFVhZS412SyQX125qxyzOgIFouwOcvjZWk6bQbNPR1wtaEzFT6jZxAjf1dejlGqa6fqHcuCvQea6EWUkUA==} - vite@8.0.2: - resolution: {integrity: sha512-1gFhNi+bHhRE/qKZOJXACm6tX4bA3Isy9KuKF15AgSRuRazNBOJfdDemPBU16/mpMxApDPrWvZ08DcLPEoRnuA==} + vite@7.3.1: + resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.0 - esbuild: ^0.27.0 jiti: '>=1.21.0' less: ^4.0.0 + lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -11023,14 +10668,12 @@ packages: peerDependenciesMeta: '@types/node': optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true jiti: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true sass-embedded: @@ -12150,8 +11793,6 @@ snapshots: '@borewit/text-codec@0.1.1': {} - '@bufbuild/protobuf@2.11.0': {} - '@canvas/image-data@1.1.0': {} '@chainsafe/is-ip@2.1.0': {} @@ -12290,22 +11931,11 @@ snapshots: jsonfile: 5.0.0 universalify: 0.1.2 - '@emnapi/core@1.9.1': - dependencies: - '@emnapi/wasi-threads': 1.2.0 - tslib: 2.8.1 - optional: true - '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.2.0': - dependencies: - tslib: 2.8.1 - optional: true - '@epic-web/invariant@1.0.0': {} '@esbuild/aix-ppc64@0.27.4': @@ -12916,11 +12546,11 @@ snapshots: '@types/yargs': 17.0.34 chalk: 4.1.2 - '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@joshwooding/vite-plugin-react-docgen-typescript@0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: glob: 13.0.1 react-docgen-typescript: 2.4.0(typescript@5.9.3) - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: typescript: 5.9.3 @@ -13204,13 +12834,6 @@ snapshots: '@napi-rs/nice-win32-x64-msvc': 1.1.1 optional: true - '@napi-rs/wasm-runtime@1.1.1': - dependencies: - '@emnapi/core': 1.9.1 - '@emnapi/runtime': 1.7.1 - '@tybys/wasm-util': 0.10.1 - optional: true - '@nestjs/common@11.1.17(reflect-metadata@0.2.2)(rxjs@7.8.2)': dependencies: file-type: 21.3.2 @@ -13565,8 +13188,6 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.6.0(@opentelemetry/api@1.9.0) - '@oxc-project/types@0.122.0': {} - '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 @@ -13791,55 +13412,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@rolldown/binding-android-arm64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-darwin-x64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.11': - optional: true - - '@rolldown/binding-linux-x64-musl@1.0.0-rc.11': - optional: true - - '@rolldown/binding-openharmony-arm64@1.0.0-rc.11': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.0-rc.11': - dependencies: - '@napi-rs/wasm-runtime': 1.1.1 - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.11': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.11': - optional: true - - '@rolldown/pluginutils@1.0.0-rc.11': {} - '@rolldown/pluginutils@1.0.0-rc.2': {} '@rollup/plugin-json@6.1.0(rollup@4.60.0)': @@ -13848,6 +13420,13 @@ snapshots: optionalDependencies: rollup: 4.60.0 + '@rollup/plugin-replace@6.0.3(rollup@4.60.0)': + dependencies: + '@rollup/pluginutils': 5.3.0(rollup@4.60.0) + magic-string: 0.30.21 + optionalDependencies: + rollup: 4.60.0 + '@rollup/pluginutils@5.3.0(rollup@4.60.0)': dependencies: '@types/estree': 1.0.8 @@ -13974,18 +13553,10 @@ snapshots: '@sec-ant/readable-stream@0.4.1': {} - '@sentry-internal/browser-utils@10.40.0': - dependencies: - '@sentry/core': 10.40.0 - '@sentry-internal/browser-utils@10.45.0': dependencies: '@sentry/core': 10.45.0 - '@sentry-internal/feedback@10.40.0': - dependencies: - '@sentry/core': 10.40.0 - '@sentry-internal/feedback@10.45.0': dependencies: '@sentry/core': 10.45.0 @@ -13995,34 +13566,16 @@ snapshots: detect-libc: 2.1.2 node-abi: 3.85.0 - '@sentry-internal/replay-canvas@10.40.0': - dependencies: - '@sentry-internal/replay': 10.40.0 - '@sentry/core': 10.40.0 - '@sentry-internal/replay-canvas@10.45.0': dependencies: '@sentry-internal/replay': 10.45.0 '@sentry/core': 10.45.0 - '@sentry-internal/replay@10.40.0': - dependencies: - '@sentry-internal/browser-utils': 10.40.0 - '@sentry/core': 10.40.0 - '@sentry-internal/replay@10.45.0': dependencies: '@sentry-internal/browser-utils': 10.45.0 '@sentry/core': 10.45.0 - '@sentry/browser@10.40.0': - dependencies: - '@sentry-internal/browser-utils': 10.40.0 - '@sentry-internal/feedback': 10.40.0 - '@sentry-internal/replay': 10.40.0 - '@sentry-internal/replay-canvas': 10.40.0 - '@sentry/core': 10.40.0 - '@sentry/browser@10.45.0': dependencies: '@sentry-internal/browser-utils': 10.45.0 @@ -14031,8 +13584,6 @@ snapshots: '@sentry-internal/replay-canvas': 10.45.0 '@sentry/core': 10.45.0 - '@sentry/core@10.40.0': {} - '@sentry/core@10.45.0': {} '@sentry/node-core@10.45.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.213.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.6.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.40.0)': @@ -14106,12 +13657,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@sentry/vue@10.40.0(vue@3.5.30(typescript@5.9.3))': - dependencies: - '@sentry/browser': 10.40.0 - '@sentry/core': 10.40.0 - vue: 3.5.30(typescript@5.9.3) - '@sentry/vue@10.45.0(vue@3.5.30(typescript@5.9.3))': dependencies: '@sentry/browser': 10.45.0 @@ -14670,12 +14215,12 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) - '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/builder-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/csf-plugin': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) ts-dedent: 2.2.0 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14689,14 +14234,14 @@ snapshots: dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/csf-plugin@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) unplugin: 2.3.10 optionalDependencies: esbuild: 0.27.4 rollup: 4.60.0 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@storybook/csf-plugin@8.6.18(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))': dependencies: @@ -14741,11 +14286,11 @@ snapshots: react-dom: 19.2.4(react@19.2.4) storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@storybook/react-vite@10.3.3(esbuild@0.27.4)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: - '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@joshwooding/vite-plugin-react-docgen-typescript': 0.6.4(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@rollup/pluginutils': 5.3.0(rollup@4.60.0) - '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/react': 10.3.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(typescript@5.9.3) empathic: 2.0.0 magic-string: 0.30.21 @@ -14755,7 +14300,7 @@ snapshots: resolve: 1.22.11 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) tsconfig-paths: 4.2.0 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) transitivePeerDependencies: - esbuild - rollup @@ -14803,14 +14348,14 @@ snapshots: dependencies: storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) - '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@storybook/vue3-vite@10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: - '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@storybook/builder-vite': 10.3.3(esbuild@0.27.4)(rollup@4.60.0)(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@storybook/vue3': 10.3.3(storybook@10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6))(vue@3.5.30(typescript@5.9.3)) magic-string: 0.30.21 storybook: 10.3.3(@testing-library/dom@10.4.0)(bufferutil@4.1.0)(prettier@3.8.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(utf-8-validate@6.0.6) typescript: 5.9.3 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue-component-meta: 2.2.12(typescript@5.9.3) vue-docgen-api: 4.79.2(vue@3.5.30(typescript@5.9.3)) transitivePeerDependencies: @@ -15115,11 +14660,6 @@ snapshots: '@twemoji/parser@16.0.0': {} - '@tybys/wasm-util@0.10.1': - dependencies: - tslib: 2.8.1 - optional: true - '@types/accepts@1.3.7': dependencies: '@types/node': 24.12.0 @@ -15588,13 +15128,13 @@ snapshots: '@ungap/structured-clone@1.3.0': {} - '@vitejs/plugin-vue@6.0.5(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': + '@vitejs/plugin-vue@6.0.5(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))(vue@3.5.30(typescript@5.9.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.2 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) vue: 3.5.30(typescript@5.9.3) - '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': + '@vitest/coverage-v8@4.1.1(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)))': dependencies: '@bcoe/v8-coverage': 1.0.2 '@vitest/utils': 4.1.1 @@ -15606,7 +15146,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.0.3 - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/expect@2.0.5': dependencies: @@ -15632,14 +15172,14 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.0.3 - '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': + '@vitest/mocker@4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))': dependencies: '@vitest/spy': 4.1.1 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.12.14(@types/node@24.12.0)(typescript@5.9.3) - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) '@vitest/pretty-format@2.0.5': dependencies: @@ -16763,8 +16303,6 @@ snapshots: colorette@2.0.20: {} - colorjs.io@0.5.2: {} - colors@1.4.0: optional: true @@ -18419,13 +17957,6 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 - htmlparser2@8.0.2: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - htmlparser2@9.1.0: dependencies: domelementtype: 2.3.0 @@ -19397,55 +18928,6 @@ snapshots: process-warning: 4.0.1 set-cookie-parser: 2.7.1 - lightningcss-android-arm64@1.32.0: - optional: true - - lightningcss-darwin-arm64@1.32.0: - optional: true - - lightningcss-darwin-x64@1.32.0: - optional: true - - lightningcss-freebsd-x64@1.32.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.32.0: - optional: true - - lightningcss-linux-arm64-gnu@1.32.0: - optional: true - - lightningcss-linux-arm64-musl@1.32.0: - optional: true - - lightningcss-linux-x64-gnu@1.32.0: - optional: true - - lightningcss-linux-x64-musl@1.32.0: - optional: true - - lightningcss-win32-arm64-msvc@1.32.0: - optional: true - - lightningcss-win32-x64-msvc@1.32.0: - optional: true - - lightningcss@1.32.0: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.32.0 - lightningcss-darwin-arm64: 1.32.0 - lightningcss-darwin-x64: 1.32.0 - lightningcss-freebsd-x64: 1.32.0 - lightningcss-linux-arm-gnueabihf: 1.32.0 - lightningcss-linux-arm64-gnu: 1.32.0 - lightningcss-linux-arm64-musl: 1.32.0 - lightningcss-linux-x64-gnu: 1.32.0 - lightningcss-linux-x64-musl: 1.32.0 - lightningcss-win32-arm64-msvc: 1.32.0 - lightningcss-win32-x64-msvc: 1.32.0 - lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -21291,27 +20773,6 @@ snapshots: glob: 7.2.3 optional: true - rolldown@1.0.0-rc.11: - dependencies: - '@oxc-project/types': 0.122.0 - '@rolldown/pluginutils': 1.0.0-rc.11 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.11 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.11 - '@rolldown/binding-darwin-x64': 1.0.0-rc.11 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.11 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.11 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.11 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.11 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.11 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.11 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.11 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.11 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.11 - rollup@4.60.0: dependencies: '@types/estree': 1.0.8 @@ -21399,15 +20860,6 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.17.1: - dependencies: - deepmerge: 4.3.1 - escape-string-regexp: 4.0.0 - htmlparser2: 8.0.2 - is-plain-object: 5.0.0 - parse-srcset: 1.0.2 - postcss: 8.5.8 - sanitize-html@2.17.2: dependencies: deepmerge: 4.3.1 @@ -21417,93 +20869,6 @@ snapshots: parse-srcset: 1.0.2 postcss: 8.5.8 - sass-embedded-all-unknown@1.98.0: - dependencies: - sass: 1.98.0 - optional: true - - sass-embedded-android-arm64@1.98.0: - optional: true - - sass-embedded-android-arm@1.98.0: - optional: true - - sass-embedded-android-riscv64@1.98.0: - optional: true - - sass-embedded-android-x64@1.98.0: - optional: true - - sass-embedded-darwin-arm64@1.98.0: - optional: true - - sass-embedded-darwin-x64@1.98.0: - optional: true - - sass-embedded-linux-arm64@1.98.0: - optional: true - - sass-embedded-linux-arm@1.98.0: - optional: true - - sass-embedded-linux-musl-arm64@1.98.0: - optional: true - - sass-embedded-linux-musl-arm@1.98.0: - optional: true - - sass-embedded-linux-musl-riscv64@1.98.0: - optional: true - - sass-embedded-linux-musl-x64@1.98.0: - optional: true - - sass-embedded-linux-riscv64@1.98.0: - optional: true - - sass-embedded-linux-x64@1.98.0: - optional: true - - sass-embedded-unknown-all@1.98.0: - dependencies: - sass: 1.98.0 - optional: true - - sass-embedded-win32-arm64@1.98.0: - optional: true - - sass-embedded-win32-x64@1.98.0: - optional: true - - sass-embedded@1.98.0: - dependencies: - '@bufbuild/protobuf': 2.11.0 - colorjs.io: 0.5.2 - immutable: 5.1.5 - rxjs: 7.8.2 - supports-color: 8.1.1 - sync-child-process: 1.0.2 - varint: 6.0.0 - optionalDependencies: - sass-embedded-all-unknown: 1.98.0 - sass-embedded-android-arm: 1.98.0 - sass-embedded-android-arm64: 1.98.0 - sass-embedded-android-riscv64: 1.98.0 - sass-embedded-android-x64: 1.98.0 - sass-embedded-darwin-arm64: 1.98.0 - sass-embedded-darwin-x64: 1.98.0 - sass-embedded-linux-arm: 1.98.0 - sass-embedded-linux-arm64: 1.98.0 - sass-embedded-linux-musl-arm: 1.98.0 - sass-embedded-linux-musl-arm64: 1.98.0 - sass-embedded-linux-musl-riscv64: 1.98.0 - sass-embedded-linux-musl-x64: 1.98.0 - sass-embedded-linux-riscv64: 1.98.0 - sass-embedded-linux-x64: 1.98.0 - sass-embedded-unknown-all: 1.98.0 - sass-embedded-win32-arm64: 1.98.0 - sass-embedded-win32-x64: 1.98.0 - sass@1.98.0: dependencies: chokidar: 5.0.0 @@ -21511,7 +20876,6 @@ snapshots: source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.1 - optional: true sax@1.5.0: {} @@ -22161,12 +21525,6 @@ snapshots: symbol-tree@3.2.4: optional: true - sync-child-process@1.0.2: - dependencies: - sync-message-port: 1.2.0 - - sync-message-port@1.2.0: {} - systeminformation@5.31.5: {} tagged-tag@1.0.0: {} @@ -22634,8 +21992,6 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - varint@6.0.0: {} - vary@1.1.2: {} verror@1.10.0: @@ -22654,45 +22010,44 @@ snapshots: '@types/unist': 3.0.3 vfile-message: 4.0.3 - vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): + vite-plugin-glsl@1.5.6(@rollup/pluginutils@5.3.0(rollup@4.60.0))(esbuild@0.27.4)(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) optionalDependencies: '@rollup/pluginutils': 5.3.0(rollup@4.60.0) esbuild: 0.27.4 vite-plugin-turbosnap@1.0.3: {} - vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): + vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0): dependencies: - lightningcss: 1.32.0 + esbuild: 0.27.4 + fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.8 - rolldown: 1.0.0-rc.11 + rollup: 4.60.0 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.12.0 - esbuild: 0.27.4 fsevents: 2.3.3 sass: 1.98.0 - sass-embedded: 1.98.0 terser: 5.46.1 tsx: 4.21.0 - vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): + vitest-fetch-mock@0.4.5(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): + vitest-websocket-mock@0.5.0(vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0))): dependencies: '@vitest/utils': 3.2.4 mock-socket: 9.3.1 - vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + vitest: 4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) - vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): + vitest@4.1.1(@opentelemetry/api@1.9.0)(@types/node@24.12.0)(happy-dom@20.8.8(bufferutil@4.1.0)(utf-8-validate@6.0.6))(jsdom@27.2.0(bufferutil@4.1.0)(utf-8-validate@6.0.6))(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)): dependencies: '@vitest/expect': 4.1.1 - '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) + '@vitest/mocker': 4.1.1(msw@2.12.14(@types/node@24.12.0)(typescript@5.9.3))(vite@7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)) '@vitest/pretty-format': 4.1.1 '@vitest/runner': 4.1.1 '@vitest/snapshot': 4.1.1 @@ -22709,7 +22064,7 @@ snapshots: tinyexec: 1.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vite: 8.0.2(@types/node@24.12.0)(esbuild@0.27.4)(sass-embedded@1.98.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) + vite: 7.3.1(@types/node@24.12.0)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.0 From 367766d864c686cfc88f250f43c94be052db9db6 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 6 Apr 2026 11:16:40 +0000 Subject: [PATCH 04/15] Bump version to 2026.4.0-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 b5d712db13..612ea3c371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## Unreleased +## 2026.4.0 ### General - diff --git a/package.json b/package.json index b70960417a..527fa17987 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "misskey", - "version": "2026.3.2", + "version": "2026.4.0-alpha.0", "codename": "nasubi", "repository": { "type": "git", diff --git a/packages/misskey-js/package.json b/packages/misskey-js/package.json index abf85c276c..9983e84354 100644 --- a/packages/misskey-js/package.json +++ b/packages/misskey-js/package.json @@ -1,7 +1,7 @@ { "type": "module", "name": "misskey-js", - "version": "2026.3.2", + "version": "2026.4.0-alpha.0", "description": "Misskey SDK for JavaScript", "license": "MIT", "main": "./built/index.js", From ae34578c6fb180387bc9e9107b7052e5be7b7aa0 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: Mon, 6 Apr 2026 22:28:44 +0900 Subject: [PATCH 05/15] =?UTF-8?q?refactor(frontend):=20MkButton=E3=81=AEpr?= =?UTF-8?q?ops=E7=AD=89=E6=95=B4=E7=90=86=20(#17282)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(frontend): MkButtonのprops等整理 * fix --- packages/frontend/src/components/MkButton.vue | 87 ++++++++++++------- .../src/components/MkVisitorDashboard.vue | 2 +- packages/frontend/src/pages/about.emojis.vue | 2 +- packages/frontend/src/pages/admin/abuses.vue | 2 +- packages/frontend/src/pages/channels.vue | 2 +- .../src/pages/page-editor/page-editor.vue | 2 +- .../src/pages/settings/2fa.qrdialog.vue | 2 +- .../frontend/src/pages/settings/profile.vue | 2 +- packages/frontend/src/pages/verify-email.vue | 2 +- 9 files changed, 63 insertions(+), 40 deletions(-) diff --git a/packages/frontend/src/components/MkButton.vue b/packages/frontend/src/components/MkButton.vue index 854ed31ed5..8bcd197205 100644 --- a/packages/frontend/src/components/MkButton.vue +++ b/packages/frontend/src/components/MkButton.vue @@ -4,14 +4,12 @@ SPDX-License-Identifier: AGPL-3.0-only --> - + + diff --git a/packages/frontend/src/components/MkPopupMenu.vue b/packages/frontend/src/components/MkPopupMenu.vue index 4942ffe232..11b116d430 100644 --- a/packages/frontend/src/components/MkPopupMenu.vue +++ b/packages/frontend/src/components/MkPopupMenu.vue @@ -4,8 +4,31 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -21,6 +44,8 @@ defineProps<{ width?: number; anchorElement?: HTMLElement | null; returnFocusTo?: HTMLElement | null; + debugDisablePredictionCone?: boolean; + debugShowPredictionCone?: boolean; }>(); const emit = defineEmits<{ diff --git a/packages/frontend/src/os.ts b/packages/frontend/src/os.ts index f7b59612c4..8e78127e8e 100644 --- a/packages/frontend/src/os.ts +++ b/packages/frontend/src/os.ts @@ -640,6 +640,8 @@ export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElemen width?: number; onClosing?: () => void; onClosed?: () => void; + debugDisablePredictionCone?: boolean; + debugShowPredictionCone?: boolean; }): Promise { if (!(anchorElement instanceof HTMLElement)) { anchorElement = null; @@ -653,6 +655,8 @@ export function popupMenu(items: (MenuItem | null)[], anchorElement?: HTMLElemen width: options?.width, align: options?.align, returnFocusTo, + debugDisablePredictionCone: options?.debugDisablePredictionCone, + debugShowPredictionCone: options?.debugShowPredictionCone, }, { closed: () => { resolve(); diff --git a/packages/frontend/src/pages/debug.vue b/packages/frontend/src/pages/debug.vue index 9c0761f0b1..44418d613b 100644 --- a/packages/frontend/src/pages/debug.vue +++ b/packages/frontend/src/pages/debug.vue @@ -7,30 +7,46 @@ SPDX-License-Identifier: AGPL-3.0-only
- - - - + + - - - - - - - +
+ + + + -
- Error - Warning - Info - Success - Question -
+ + + + + + + + +
+ Error + Warning + Info + Success + Question +
+
+
+ + + + +
+ select without guard + select with guard + select with guard (visualize) +
+
@@ -47,6 +63,7 @@ import MkSelect from '@/components/MkSelect.vue'; import MkButton from '@/components/MkButton.vue'; import { useMkSelect } from '@/composables/use-mkselect.js'; import * as os from '@/os.js'; +import MkFolder from '@/components/MkFolder.vue'; const { model: resultType, @@ -74,6 +91,64 @@ const { initialValue: 'info', }); +function select(ev: PointerEvent, enablePredictionCone: boolean, showPredictionCone: boolean) { + os.popupMenu([ + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', action: () => {} }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { text: 'Option', action: () => {} }, + { text: 'Option', action: () => {} }, + ] }, + { type: 'parent', text: 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', children: [ + { text: 'Option', action: () => {} }, + ] }, + ], ev.currentTarget ?? ev.target, { + debugDisablePredictionCone: !enablePredictionCone, + debugShowPredictionCone: showPredictionCone, + }).then((value) => { + console.log('Selected:', value); + }); +} + definePage(() => ({ title: 'DEBUG ROOM', icon: 'ti ti-help-circle', From b9923d0a238f54144d2cd29b72138be741d070ce Mon Sep 17 00:00:00 2001 From: syuilo <4439005+syuilo@users.noreply.github.com> Date: Tue, 7 Apr 2026 19:30:26 +0900 Subject: [PATCH 07/15] New Crowdin updates (#17260) * New translations ja-jp.yml (Thai) * New translations ja-jp.yml (Lao) * New translations ja-jp.yml (Chinese Traditional) * New translations ja-jp.yml (Italian) * New translations ja-jp.yml (Spanish) * New translations ja-jp.yml (Italian) * 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 (Korean) * New translations ja-jp.yml (Italian) --- locales/ca-ES.yml | 7 ++++--- locales/es-ES.yml | 2 +- locales/it-IT.yml | 7 ++++--- locales/ko-KR.yml | 1 + locales/lo-LA.yml | 1 + locales/th-TH.yml | 2 ++ locales/zh-CN.yml | 1 + locales/zh-TW.yml | 3 ++- 8 files changed, 16 insertions(+), 8 deletions(-) diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index f2867585c2..ae7f4a03f1 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -1073,8 +1073,8 @@ thisPostMayBeAnnoying: "Aquesta nota pot ser molesta per algú." thisPostMayBeAnnoyingHome: "Publicar a la línia de temps d'Inici" thisPostMayBeAnnoyingCancel: "Cancel·lar " thisPostMayBeAnnoyingIgnore: "Publicar de totes maneres" -collapseRenotes: "Col·lapsar les renotes que ja has vist" -collapseRenotesDescription: "Col·lapse les notes a les quals ja has reaccionat o que ja has renotat" +collapseRenotes: "Col·lapsar els impulsos que ja has vist" +collapseRenotesDescription: "Col·lapse les notes a les quals ja has reaccionat o que ja has impulsat." internalServerError: "Error intern del servidor" internalServerErrorDescription: "El servidor ha fallat de manera inexplicable." copyErrorInfo: "Copiar la informació de l'error " @@ -1408,6 +1408,7 @@ frame: "Marc" presets: "Predefinit" zeroPadding: "Sense omplir" nothingToConfigure: "No hi ha res a configurar" +viewRenotedChannel: "Mirar el canal d'impulsos " _imageEditing: _vars: caption: "Títol de l'arxiu" @@ -1687,7 +1688,7 @@ _initialTutorial: description: "Pots limitar qui pot veure les teves notes." public: "La teva nota serà visible per a tots els usuaris." home: "Publicar només a línia de temps d'Inici. La gent que visiti el teu perfil o mitjançant les remotes també la podran veure." - followers: "Només visible per a seguidors. Només els teus seguidors la podran veure i ningú més. Ningú més podrà fer renotes." + followers: "Només visible per a seguidors. Només els teus seguidors la podran veure i ningú més. Ningú més podrà fer impulsos." direct: "Només visible per a alguns seguidors, el destinatari rebre una notificació. Es pot fer servir com una alternativa als missatges directes." doNotSendConfidencialOnDirect1: "Tingues cura quan enviïs informació sensible." doNotSendConfidencialOnDirect2: "Els administradors del servidor poden veure tot el que escrius. Ves compte quan enviïs informació sensible en enviar notes directes a altres usuaris en servidors de poca confiança." diff --git a/locales/es-ES.yml b/locales/es-ES.yml index 72b7892128..3c7852cd05 100644 --- a/locales/es-ES.yml +++ b/locales/es-ES.yml @@ -3312,7 +3312,7 @@ _clientPerformanceIssueTip: _clip: tip: "Clip es una función que permite organizar varias notas." _userLists: - tip: "Las listas pueden contener cualquier usuario que especifiques al crearlas, la lista creada puede mostrarse entonces como una línea de tiempo mostrando solo los usuarios especificados." + tip: "Puedes crear listas que incluyan a cualquier usuario. Las listas creadas se pueden visualizar en forma de cronología." watermark: "Marca de Agua" defaultPreset: "Por defecto" _watermarkEditor: diff --git a/locales/it-IT.yml b/locales/it-IT.yml index 2401bd84aa..08c9197251 100644 --- a/locales/it-IT.yml +++ b/locales/it-IT.yml @@ -1,7 +1,7 @@ --- _lang_: "Italiano" headlineMisskey: "Rete collegata tramite Note" -introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n\n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n\n👍 Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n\n🚀 Esplora un nuovo mondo insieme a noi!" +introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n👍 Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n🚀 Esplora un nuovo mondo insieme a noi!" poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source Misskey." monthAndDay: "{day}/{month}" search: "Cerca" @@ -1408,6 +1408,7 @@ frame: "Cornice" presets: "Preimpostato" zeroPadding: "Al vivo" nothingToConfigure: "Niente da configurare" +viewRenotedChannel: "Visualizza il canale del Rinota" _imageEditing: _vars: caption: "Didascalia dell'immagine" @@ -3338,7 +3339,7 @@ _watermarkEditor: stripeWidth: "Larghezza della linea" stripeFrequency: "Il numero di linee" polkadot: "A pallini" - checker: "revisore" + checker: "Scacchiera" polkadotMainDotOpacity: "Opacità del punto principale" polkadotMainDotRadius: "Dimensione del punto principale" polkadotSubDotOpacity: "Opacità del punto secondario" @@ -3367,7 +3368,7 @@ _imageEffector: zoomLines: "Linea di saturazione" stripe: "Strisce" polkadot: "A pallini" - checker: "revisore" + checker: "Scacchiera" blockNoise: "Attenua rumore" tearing: "Strappa immagine" fill: "Riempimento" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 52da6d071a..294791cce3 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1408,6 +1408,7 @@ frame: "프레임" presets: "프리셋" zeroPadding: "0으로 채우기" nothingToConfigure: "설정 항목이 없습니다." +viewRenotedChannel: "리노트된 채널 보기" _imageEditing: _vars: caption: "파일 설명" diff --git a/locales/lo-LA.yml b/locales/lo-LA.yml index 7017d81733..3779155ae1 100644 --- a/locales/lo-LA.yml +++ b/locales/lo-LA.yml @@ -5,6 +5,7 @@ introMisskey: "ຍິນດີຕ້ອນຮັບ! Misskey ເປັນຊອ poweredByMisskeyDescription: "{name} ແມ່ນສ່ວນໜຶ່ງຂອງການບໍລິການທີ່ຂັບເຄື່ອນໂດຍແພລດຟອມ open source. Misskey (ເອີ້ນວ່າ \"Misskey instance\")" monthAndDay: "ເດືອນ{month} / ວັນ{day}" search: "ຄົ້ນຫາ" +reset: "ຣີເຊັດ" notifications: "ການແຈ້ງເຕືອນ" username: "ຊື່ຜູ້ໃຊ້" password: "ລະຫັດຜ່ານ" diff --git a/locales/th-TH.yml b/locales/th-TH.yml index 6bcff59979..bd53d28300 100644 --- a/locales/th-TH.yml +++ b/locales/th-TH.yml @@ -3401,6 +3401,8 @@ _imageEffector: threshold: "เทรชโฮลด์" centerX: "กลาง X" centerY: "กลาง Y" + density: "ความหนาทึบ" + zoomLinesOutlineThickness: "ความหนาของเงาเส้น" zoomLinesMaskSize: "ขนาดพื้นที่ตรงกลาง" circle: "ทรงกลม" drafts: "ร่าง" diff --git a/locales/zh-CN.yml b/locales/zh-CN.yml index 5cfa90e910..cda2fc6531 100644 --- a/locales/zh-CN.yml +++ b/locales/zh-CN.yml @@ -1408,6 +1408,7 @@ frame: "边框" presets: "预设值" zeroPadding: "填充 0" nothingToConfigure: "没有项目" +viewRenotedChannel: "查看转帖所属频道" _imageEditing: _vars: caption: "文件标题" diff --git a/locales/zh-TW.yml b/locales/zh-TW.yml index fa8a3eead8..c1347f54c0 100644 --- a/locales/zh-TW.yml +++ b/locales/zh-TW.yml @@ -10,7 +10,7 @@ notifications: "通知" username: "使用者名稱" password: "密碼" initialPasswordForSetup: "啟動初始設定的密碼" -initialPasswordIsIncorrect: "啟動初始設定的密碼錯誤。" +initialPasswordIsIncorrect: "啟動初始設定密碼錯誤。" initialPasswordForSetupDescription: "如果您自己安裝了 Misskey,請使用您在設定檔中輸入的密碼。\n如果您使用 Misskey 的託管服務之類的服務,請使用提供的密碼。\n如果您尚未設定密碼,請將其留空並繼續。" forgotPassword: "忘記密碼" fetchingAsApObject: "從聯邦宇宙取得中..." @@ -1408,6 +1408,7 @@ frame: "邊框" presets: "預設值" zeroPadding: "補零" nothingToConfigure: "無可設定的項目" +viewRenotedChannel: "顯示轉發貼文者的頻道" _imageEditing: _vars: caption: "檔案標題" From d4a5048aae13f1e2807a3d2175a0bb0cd4941197 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: Tue, 7 Apr 2026 20:35:06 +0900 Subject: [PATCH 08/15] =?UTF-8?q?fix(frontend):=20router=E3=81=8CmatchAll?= =?UTF-8?q?=E3=81=AB=E5=85=A5=E3=81=A3=E3=81=9F=E9=9A=9B=E3=81=AB=E4=B8=80?= =?UTF-8?q?=E5=BA=A6=20`location.href`=20=E3=81=AB=E3=82=88=E3=82=8B?= =?UTF-8?q?=E9=81=B7=E7=A7=BB=E3=82=92=E8=A9=A6=E3=81=BF=E3=82=8B=E6=8C=99?= =?UTF-8?q?=E5=8B=95=E3=81=AB=E9=96=A2=E3=81=99=E3=82=8B=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=20(#17281)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(frontend): follow-up of #13509 * fix: fix use of inappropriate method * Update CHANGELOG.md [ci skip] --- CHANGELOG.md | 1 + .../frontend/src/components/MkPageWindow.vue | 22 ++++- .../frontend/src/components/global/MkA.vue | 7 +- packages/frontend/src/lib/nirax.ts | 87 ++++++++++++++----- .../frontend/src/pages/drive.file.info.vue | 2 +- packages/frontend/src/router.ts | 8 ++ 6 files changed, 99 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 612ea3c371..cec53e3847 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Client - Enhance: チャンネル指定リノートでリノート先のチャンネルに移動できるように +- Fix: 一部のページ内リンクが正しく動作しない問題を修正 ### Server - Fix: `/api-doc` にアクセスできない問題を修正 diff --git a/packages/frontend/src/components/MkPageWindow.vue b/packages/frontend/src/components/MkPageWindow.vue index 4b6467fdda..f2acec32f0 100644 --- a/packages/frontend/src/components/MkPageWindow.vue +++ b/packages/frontend/src/components/MkPageWindow.vue @@ -28,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only