Compare commits

...
Author SHA1 Message Date
copilot-swe-agent[bot]andsyuilo 7805a7bd35 Add variable extraction for folder hash consistency
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-16 23:29:32 +00:00
copilot-swe-agent[bot]andsyuilo 5393045dfd Fix function declaration style for popstateHandler
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-16 23:27:29 +00:00
copilot-swe-agent[bot]andsyuilo fb864ecd6c Refine browser back button implementation using hash-based approach
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-16 03:46:10 +00:00
copilot-swe-agent[bot]andsyuilo a1c93d9b25 Implement browser back button support for FolderPageView
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-16 03:43:53 +00:00
copilot-swe-agent[bot] 384eebf3d1 Initial plan 2025-09-16 03:39:00 +00:00
syuilo df3e44f62e enhance(backend): allow upload csv by default
Related #16541
2025-09-16 12:16:18 +09:00
かっこかり e504560477 fix: サーバー設定によりコンテンツの閲覧が制限されている場合のメッセージを区別するように (#16527) 2025-09-16 11:53:20 +09:00
syuilo bcb2073715 enhance(backend): 初期設定をスキップした場合の初期状態ポリシーでインポート系をオプトインに
Resolve #16540
2025-09-16 11:26:35 +09:00
syuilo 6a80c23a50 chore(frontend): enable enableFolderPageView by default 2025-09-15 14:33:32 +09:00
syuilo 2621f468ff enhance: 広告ごとにセンシティブフラグを設定できるように 2025-09-14 15:25:22 +09:00
かっこかりandsyuilo d4654dd7bd refactor(frontend): os.select, MkSelectのitem指定をオブジェクトによる定義に統一し、型を狭める (#16475)
* refactor(frontend): MkSelectのitem指定をオブジェクトによる定義に統一

* fix

* spdx

* fix

* fix os.select

* fix lint

* add comment

* fix

* fix: os.select対応漏れを修正

* fix

* fix

* fix: MkSelectのmodelに対する型チェックを厳格化

* fix

* fix

* fix

* Update packages/frontend/src/components/MkEmbedCodeGenDialog.vue

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

* fix

* fix types

* fix

* fix

* Update packages/frontend/src/pages/admin/roles.editor.vue

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>

* fix: MkSelectに直接配列を指定している場合に正常に型が解決されるように

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-09-13 21:00:33 +09:00
renovate[bot] b7da6cad87 fix(deps): update dependency vite [security] (#16535)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-13 10:32:49 +09:00
かっこかり 5b4115e21a refactor(frontend): フロントエンドの型エラー解消(途中まで) (#16539)
* fix(frontend): FormLinkをボタンとして使用した際にエラーが出る問題を修正

* refactor(frontend): フロントエンドの型エラー解消

* remove unused ts-expect-error

* migrate

* remove unrelated changes

* fix lint

* more type fixes
2025-09-13 08:33:14 +09:00
syuilo c174c5c144 Update CHANGELOG.md 2025-09-12 17:13:13 +09:00
かっこかり aebc3f781e perf(frontend): 低精度な現在時刻を一か所で管理するように (#16479)
* perf(frontend): 低精度な現在時刻を一か所で管理するように

* lint

* fix

* remove unused imports

* fix

* Update Changelog

* [ci skip] typo

* enhance: カレンダーウィジェットの日付変更は時間通りに行うように

* [ci skip] fix
2025-09-12 17:12:50 +09:00
かっこかり f60b6291d7 chore(gh): add frontend-builder to renovate 2025-09-10 10:01:25 +09:00
taiy 7673874675 fix(eslint): add window prefix rules to frontend-embed & frontend-shared (#16531) 2025-09-10 09:22:12 +09:00
github-actions[bot] 6e3354f95d [skip ci] Update CHANGELOG.md (prepend template) 2025-09-08 12:29:30 +00:00
github-actions[bot] b9df928097 Release: 2025.9.0 2025-09-08 12:29:25 +00:00
github-actions[bot] 0754678144 Bump version to 2025.9.0-rc.0 2025-09-08 11:33:58 +00:00
tamaina a8cc51dc77 fix(frontend): Safari 26でモバイルUIが崩れる問題に対するhotfix (#16528) 2025-09-08 20:32:19 +09:00
github-actions[bot] 690edcef16 Bump version to 2025.9.0-beta.1 2025-09-08 11:21:12 +00:00
renovate[bot]andkakkokari-gtyih 2ea784f345 fix(deps): update [backend] update dependencies (#16491)
* fix(deps): update [backend] update dependencies

* fix type error

* run pnpm dedupe

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-09-08 17:11:18 +09:00
renovate[bot] 20d257b562 chore(deps): update [misskey-js] update dependencies (#16489)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-08 16:14:23 +09:00
renovate[bot] c215415613 fix(deps): update [root] update dependencies (#16490)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-08 16:08:15 +09:00
github-actions[bot] 726c03d96a Bump version to 2025.9.0-beta.0 2025-09-08 06:32:15 +00:00
syuilo e65ddb546c New Crowdin updates (#16526)
* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Russian)
2025-09-08 15:20:07 +09:00
renovate[bot] 85aea9077f fix(deps): update [frontend] update dependencies (#16492)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-08 15:16:22 +09:00
syuilo f3fffce6a9 fix type 2025-09-08 14:57:53 +09:00
syuilo eb7db5a3aa Update MkSuspense.vue 2025-09-08 14:56:58 +09:00
syuilo e33eb26863 Update CHANGELOG.md 2025-09-07 19:41:40 +09:00
かっこかり 430310f306 fix(frontend): ctrlキーを押しながらリンクをクリックしても新しいタブで開かない問題を修正 (#16453)
* fix(frontend): ctrlキーを押しながらクリックしても新しいタブで開かない問題を修正

* Update Changelog

* fix: 制御キーの場合を個別ハンドリングするのではなくブラウザ既定の挙動に任せるように

* fix
2025-09-07 09:32:32 +09:00
syuilo 1e1eea521e chore(frontend): add force cloud backup button for debugging 2025-09-07 09:16:25 +09:00
syuilo 86ad771221 New Crowdin updates (#16525)
* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (Russian)
2025-09-07 09:01:12 +09:00
syuilo 057acf471e New Crowdin updates (#16493)
* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Spanish)
2025-09-06 20:53:36 +09:00
github-actions[bot] 2bfe257879 Bump version to 2025.9.0-alpha.2 2025-09-06 08:54:34 +00:00
syuilo 6d75624aa8 Update CHANGELOG.md 2025-09-06 17:49:53 +09:00
tamaina 369f0ec88a fix(backend): webpなどの画像に対してセンシティブなメディアの検出が適用されていなかった問題を修正 (#16523)
画像をnsfwjsにかける前にsharpで均一にするようにした
2025-09-06 17:48:53 +09:00
かっこかり 788c5660ba enhance(frontend): フロントエンドのキャッシュクリア操作でブラウザの内部キャッシュも削除するように (#16522)
* enhance(frontend): フロントエンドのキャッシュクリア操作でブラウザの内部キャッシュも削除するように

* 削除するキャッシュを増やす

* Update Changelog

* fix: 何らかのエラーがあっても無視するように
2025-09-06 14:46:24 +09:00
github-actions[bot] 6cf1f86636 Bump version to 2025.9.0-alpha.1 2025-09-06 03:42:29 +00:00
syuilo 5b994b3e03 fix(frontend): プロファイルを復元後アカウントの切り替えができない問題を修正
Fix #16508
2025-09-06 12:41:27 +09:00
syuilo 7b2abb7577 enhance(frontend): クリップ/リスト/アンテナ/ロール追加系メニュー項目において、表示件数を拡張
#16510
2025-09-06 11:18:08 +09:00
github-actions[bot] b681788315 Bump version to 2025.9.0-alpha.0 2025-09-06 02:11:36 +00:00
syuilo 279af1d72f Update CHANGELOG.md 2025-09-06 11:10:41 +09:00
syuilo 9e188ca3fa Revert "refactor"
This reverts commit aa85d701b9.
2025-09-06 11:09:24 +09:00
syuilo de1b2223ff enhance(frontend): AiScriptAppウィジェットで構文エラーを検知してもダイアログではなくウィジェット内にエラーを表示するように 2025-09-05 19:44:11 +09:00
なっかあ 9b565728e7 fix #16494 (#16509) 2025-09-05 15:26:39 +09:00
饺子w (Yumechi) a92fd8856a feat(backend): Send Clear-Site-Data header on /flush (#16517)
* feat(backend): Send Clear-Site-Data header on /flush

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

* simplify check on flush.pug

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>

---------

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-09-05 13:55:37 +09:00
takaion 047773341d fix(frontend): エラー画像が横に引き伸ばされてしまう問題に対応 (#16502)
* fix(frontend): エラー画像が横に引き伸ばされてしまう問題に対応

Fix misskey-dev#15982

* Update CHANGELOG.md
2025-09-02 16:40:57 +09:00
yukineko 842670e100 fix(frontend): RSSティッカーウィジェットが正しく動作しない問題を修正 (#16498)
* fix: RSSティッカーウィジェットが正しく機能しない問題を修正

* chore: update CHANGELOG.md
2025-09-02 10:29:25 +09:00
anatawa12 ffc481a994 fix: 「自動でもっと見る」の設定ができない問題 (#16500) 2025-09-02 10:11:50 +09:00
syuilo 2ccf4f94cb refactor 2025-09-01 16:51:58 +09:00
syuilo 3566bc207f refactor 2025-09-01 16:36:15 +09:00
syuilo 4a0e968662 refactor 2025-09-01 16:23:05 +09:00
syuilo b1479ab1d8 Update misskey-js.api.md 2025-09-01 14:07:24 +09:00
syuilo 18a9ccf7af pnpm dedupe 2025-09-01 14:07:14 +09:00
syuilo 959e72b2b3 refactor 2025-09-01 14:02:14 +09:00
syuilo a3d78b2f08 refactor 2025-09-01 13:41:40 +09:00
syuilo 3c998e1f48 refactor 2025-09-01 12:59:53 +09:00
syuilo 782c9f9852 refactor 2025-09-01 12:33:44 +09:00
syuilo d27c740ab0 refactor 2025-09-01 12:31:27 +09:00
syuilo 08ecf7ca79 refactor 2025-09-01 10:19:14 +09:00
syuilo bdec4bf87a refactor 2025-09-01 10:16:33 +09:00
syuilo 7000095b44 refactor 2025-09-01 10:01:03 +09:00
syuilo 18e42cc83d refactoe 2025-09-01 09:53:38 +09:00
syuilo 11204eeb43 refactor 2025-09-01 09:50:36 +09:00
かっこかりandsyuilo c95092903a refactor(frontend): フロントエンドの型エラー解消(途中まで) (#16477)
* refactor(frontend): フロントエンドの型エラー解消

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-31 19:53:38 +09:00
github-actions[bot] 21b2b9e5f8 [skip ci] Update CHANGELOG.md (prepend template) 2025-08-31 08:42:45 +00:00
github-actions[bot] 665ec2c43c Release: 2025.8.0 2025-08-31 08:42:39 +00:00
syuilo 34bd840525 Update CHANGELOG.md 2025-08-31 15:56:07 +09:00
syuilo 3d1cbcf094 Update CHANGELOG.md 2025-08-31 15:29:22 +09:00
github-actions[bot] 5f5d88036f Bump version to 2025.8.0-rc.0 2025-08-31 01:32:06 +00:00
syuilo 24739cd040 New Crowdin updates (#16483)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Italian)
2025-08-31 10:24:41 +09:00
syuilo b491432daa fix(frontend): タッチ操作時にマウスホバー時のユーザープレビューが開くことがある問題を修正
Fix #16464
2025-08-31 10:23:29 +09:00
syuilo ebe029458e enhance(frontend): アイコンのスクロール追従を無効化する際の適用範囲を強化
Resolve #16485
2025-08-31 10:18:48 +09:00
syuilo d127d82c5b Update CHANGELOG.md 2025-08-30 19:17:11 +09:00
syuilo aabda5a956 clean up 2025-08-30 19:15:52 +09:00
syuilo bd5b38c9d9 Update CHANGELOG.md 2025-08-30 19:12:53 +09:00
syuilo 647e03bf34 update locale 2025-08-30 19:10:19 +09:00
syuilo d16db7f311 New translations ja-jp.yml (English) (#16472) 2025-08-30 16:11:27 +09:00
github-actions[bot] ec4731dee4 Bump version to 2025.8.0-beta.6 2025-08-29 07:38:45 +00:00
syuilo 65a4d77a7f fix(backend): タイムラインAPIの withRenotes: false 時のレスポンスを修正 2025-08-29 16:03:03 +09:00
かっこかり 328301ffc2 fix(misskey-js): run api extractor (#16476) 2025-08-29 13:37:17 +09:00
syuilo def148d7a6 refactor 2025-08-28 20:02:28 +09:00
syuilo aa85d701b9 refactor 2025-08-28 19:53:10 +09:00
syuilo f0833cffe9 refactor 2025-08-28 19:47:58 +09:00
github-actions[bot] 9cd918f12b Bump version to 2025.8.0-beta.5 2025-08-28 05:33:23 +00:00
syuilo 195a80622b New Crowdin updates (#16457)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (English)
2025-08-28 13:31:05 +09:00
syuilo 8b347e23e3 refactor 2025-08-28 13:30:52 +09:00
syuilo bca3602da2 refactor 2025-08-28 13:24:25 +09:00
syuilo cfd4d7c57b refactor 2025-08-28 13:20:11 +09:00
tamaina 084ccf5c9a build-misskey-js-with-types (#16471)
* build-misskey-js-with-types

* build-misskey-js-with-types
2025-08-28 11:45:46 +09:00
syuilo fc1693f768 そもそもnullになることはあり得なかった 2025-08-28 11:39:54 +09:00
syuilo ff6f115976 refactor 2025-08-28 11:30:03 +09:00
syuilo 8c2b96ad37 lint 2025-08-28 11:16:40 +09:00
syuilo 3e24419981 refactor 2025-08-28 11:15:17 +09:00
tamaina 25c2007f59 build-misskey-js-with-types (#16470) 2025-08-28 10:39:39 +09:00
syuilo 2e4c4dd555 refactor 2025-08-28 08:59:13 +09:00
taiy 653cb116ea fix(build): run build-misskey-js-with-types (#16468) 2025-08-27 19:11:05 +09:00
syuilo c9f363b215 fix i/apps schema 2025-08-27 17:21:24 +09:00
syuilo e72da587e4 型の漏れを修正 2025-08-27 17:05:29 +09:00
syuilo 439337a108 json schemaに誤りがあるのを修正 2025-08-27 17:01:02 +09:00
syuilo 5fef2332f4 refactor 2025-08-27 17:00:58 +09:00
syuilo 40a325cbe7 userのjson schemaに誤りがあるのを修正 2025-08-27 16:55:07 +09:00
syuilo 5eff31383f refactor 2025-08-27 16:52:58 +09:00
syuilo 575379a683 refactor 2025-08-27 16:48:32 +09:00
syuilo bf82b49633 refactor 2025-08-27 16:27:16 +09:00
syuilo 87d09f255d refactor 2025-08-27 15:59:39 +09:00
syuilo 98e07c3bd1 perf(frontend): use WeakMap 2025-08-27 12:41:24 +09:00
syuilo c5bb881438 refactor 2025-08-27 12:40:11 +09:00
syuilo ee96f77ef2 refactor 2025-08-27 12:09:19 +09:00
syuilo 55eb18f5a6 Update CHANGELOG.md 2025-08-27 10:29:45 +09:00
syuilo aa8daca914 chore(frontend): skip typecheck for auto-generated files 2025-08-27 10:23:41 +09:00
syuilo 3e9118af3d fix(frontend): lookupページでリモートURLを指定した際に正しく動作しない問題を修正 2025-08-27 10:15:11 +09:00
syuilo 25df56dfd0 refactor 2025-08-27 10:14:17 +09:00
syuilo 231ccae006 tweak locale 2025-08-27 09:57:33 +09:00
syuilo 2e0a34300a refactor 2025-08-27 09:46:31 +09:00
syuilo d2fd7460ed Update CHANGELOG.md
#16465
2025-08-27 00:41:11 +09:00
syuilo 5e3d8fc9b8 refactor 2025-08-26 20:17:25 +09:00
syuilo b186c67767 refactor 2025-08-26 20:04:59 +09:00
syuilo ac7c60d102 refactor and fix 2025-08-26 19:06:15 +09:00
syuilo b9dbd58a1c refactor 2025-08-26 18:54:54 +09:00
syuilo 69bbac013a refactor 2025-08-26 17:31:36 +09:00
syuilo 203296b9cb chore(frontend): tweak MkServerSetupWizard 2025-08-26 15:02:12 +09:00
syuilo 689d70ffae refactor 2025-08-26 14:38:42 +09:00
syuilo d5475d1ff6 refactor 2025-08-26 14:22:53 +09:00
syuilo 05cc8047fa refactor 2025-08-26 13:58:57 +09:00
syuilo d6a1046361 refactor 2025-08-26 13:34:41 +09:00
syuilo eb9915baf8 refactor and fix 2025-08-26 10:56:09 +09:00
syuilo dbb6c71c5c refactor 2025-08-26 09:39:23 +09:00
syuilo 9e5c8d94bf refactor 2025-08-26 09:08:00 +09:00
syuilo 120af977a9 refactoe 2025-08-26 08:57:36 +09:00
syuilo 506c8a259b refactor 2025-08-26 08:50:34 +09:00
syuilo 0c8545ec1c Update CHANGELOG.md 2025-08-26 07:44:26 +09:00
tamaina 7e7dc03796 fix(frontend): ap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正 (#16460) 2025-08-26 07:43:59 +09:00
syuilo a874def344 remove unused file 2025-08-25 20:32:07 +09:00
syuilo 44ac51f64f refactor: ReloadSuggest -> ReloadSuggestion 2025-08-25 20:31:22 +09:00
syuilo 3b65be8b91 clean up 2025-08-25 20:29:26 +09:00
syuilo 76beac41d2 refactor 2025-08-25 20:07:33 +09:00
syuilo 69cdc73f5a refactor 2025-08-25 19:55:42 +09:00
syuilo 1c966db324 refactor 2025-08-25 17:12:11 +09:00
syuilo 692284886b refactor 2025-08-25 17:04:49 +09:00
syuilo 0121d19645 refactor 2025-08-25 16:56:10 +09:00
syuilo bf8636e516 refactor 2025-08-25 16:56:05 +09:00
syuilo d336a1fb1c refactor 2025-08-25 13:51:52 +09:00
syuilo 7c761e7017 refactor 2025-08-25 13:48:09 +09:00
syuilo 7924daf7f8 refactor 2025-08-25 13:46:22 +09:00
syuilo 2b9706a68b refactor 2025-08-25 13:40:41 +09:00
syuilo f2d15f9240 refactor 2025-08-25 13:36:38 +09:00
syuilo caf6a3ab81 refactor 2025-08-25 13:34:17 +09:00
syuilo f4baa973bf refactor 2025-08-25 13:26:41 +09:00
syuilo 3741fa4b49 refactor 2025-08-25 13:25:05 +09:00
syuilo 27df7f643e fix typo
Fix #16452
2025-08-25 10:07:42 +09:00
syuilo 30987b6f1f Update CHANGELOG.md 2025-08-25 10:05:15 +09:00
anatawa12 41b5677f01 fix: Pages will be deleted when eye-catching image is moved (#16455) 2025-08-25 10:04:35 +09:00
github-actions[bot] 47d83e8930 Bump version to 2025.8.0-beta.4 2025-08-24 09:29:08 +00:00
renovate[bot] 61ff1f313b fix(deps): update [backend] update dependencies (#16450)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 18:27:14 +09:00
renovate[bot] 637ad3d479 chore(deps): update [misskey-js] update dependencies (#16448)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 16:05:06 +09:00
syuilo 2dd8c2a355 New Crowdin updates (#16442)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Turkish)
2025-08-24 12:02:36 +09:00
renovate[bot] 857a87d4b6 chore(deps): update [github actions] update dependencies (#16447)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 11:53:23 +09:00
renovate[bot] 8b4cea5c86 fix(deps): update [root] update dependencies (#16449)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-24 11:53:10 +09:00
renovate[bot]andkakkokari-gtyih 9f25d96ec3 fix(deps): update [frontend] update dependencies (#16387)
* fix(deps): update [frontend] update dependencies

* fix build error

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-08-24 09:13:04 +09:00
syuilo bd0730e5e8 fix(backend): 削除されたユーザーがチャットメッセージにリアクションしている場合chat/historyなどでエラーになる問題を修正
Fix #16445
2025-08-23 17:37:15 +09:00
syuilo 07ccb82691 Update CHANGELOG with recent feature and fix entries 2025-08-22 19:40:15 +09:00
github-actions[bot] 16030c6381 Bump version to 2025.8.0-beta.3 2025-08-22 10:39:14 +00:00
syuilo 1f6716d69b New Crowdin updates (#16436)
* New translations ja-jp.yml (Spanish)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (German)

* New translations ja-jp.yml (Italian)

* New translations ja-jp.yml (Russian)

* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Japanese, Kansai)

* New translations ja-jp.yml (Chinese Simplified)

* New translations ja-jp.yml (French)

* New translations ja-jp.yml (Korean)

* New translations ja-jp.yml (Portuguese)

* New translations ja-jp.yml (Turkish)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Vietnamese)

* New translations ja-jp.yml (Indonesian)

* New translations ja-jp.yml (Thai)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (Chinese Traditional)

* New translations ja-jp.yml (Italian)
2025-08-22 19:37:20 +09:00
かっこかりandsyuilo ade603ff7a fix(frontend): ページネーションの進行方向を指定できるように (#16433)
* fix(frontend): ページネーションの進行方向を指定できるように

* Update Changelog

* fix lint

* fix: directionをMkPaginationに移動

* fix

* fix

* fix

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-08-22 19:34:20 +09:00
かっこかり 4d215bde10 fix(frontend): follow-up of #16380 2025-08-22 19:31:27 +09:00
かっこかり 20d81696e1 fix(backend): fix test (#16441)
* fix(backend): fix test

* fix

* fix
2025-08-22 18:26:19 +09:00
syuilo 8cbbb80e3f fix(backend): notes/mentions で場合によっては並び順が正しく返されない問題を修正
Fix #16398
2025-08-21 19:10:16 +09:00
かっこかり 1eabb21d69 fix(backend): クリップ一覧APIをページネーションに対応させる (#16434)
* fix(backend): クリップ一覧APIをページネーションに対応させる

* Update Changelog
2025-08-21 19:02:21 +09:00
かっこかり 7f6ba2e501 enhance: verify-emailにフロントエンドUIを実装 (#16431)
* enhance: メールのverifyをAPIに変更

* enhance(frontend): メールのVerifyページを追加

* fix

* 🎨

* 🎨

* Update Changelog

* lint
2025-08-21 16:52:30 +09:00
450 changed files with 7142 additions and 5105 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
- name: Checkout head
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Setup Node.js
uses: actions/setup-node@v4.4.0
with:
@@ -18,7 +18,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
with:
submodules: true
persist-credentials: false
@@ -66,7 +66,7 @@ jobs:
if: ${{ github.event.pull_request.mergeable == null || github.event.pull_request.mergeable == true }}
steps:
- name: checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
with:
submodules: true
persist-credentials: false
@@ -20,7 +20,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Check version
run: |
if [ "$(jq -r '.version' package.json)" != "$(jq -r '.version' packages/misskey-js/package.json)" ]; then
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Check
run: |
counter=0
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
check_copyright_year:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
- run: |
if [ "$(grep Copyright COPYING | sed -e 's/.*2014-\([0-9]*\) .*/\1/g')" -ne "$(date +%Y)" ]; then
echo "Please change copyright year!"
@@ -28,7 +28,7 @@ jobs:
wait_time: ${{ steps.get-wait-time.outputs.wait_time }}
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Check allowed users
id: check-allowed-users
+1 -1
View File
@@ -27,7 +27,7 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
platform=${{ matrix.platform }}
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
- name: Check out the repo
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
DOCKER_CONTENT_TRUST: 1
DOCKLE_VERSION: 0.4.14
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
- name: Download and install dockle v${{ env.DOCKLE_VERSION }}
run: |
curl -L -o dockle.deb "https://github.com/goodwithtech/dockle/releases/download/v${DOCKLE_VERSION}/dockle_${DOCKLE_VERSION}_Linux-64bit.deb"
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
ref: refs/pull/${{ github.event.number }}/merge
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
ref: ${{ matrix.ref }}
submodules: true
+4 -4
View File
@@ -36,7 +36,7 @@ jobs:
pnpm_install:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
@@ -69,7 +69,7 @@ jobs:
eslint-cache-version: v1
eslint-cache-path: ${{ github.workspace }}/node_modules/.cache/eslint-${{ matrix.workspace }}
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
@@ -81,7 +81,7 @@ jobs:
cache: 'pnpm'
- run: pnpm i --frozen-lockfile
- name: Restore eslint cache
uses: actions/cache@v4.2.3
uses: actions/cache@v4.2.4
with:
path: ${{ env.eslint-cache-path }}
key: eslint-${{ env.eslint-cache-version }}-${{ matrix.workspace }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ github.ref_name }}-${{ github.sha }}
@@ -99,7 +99,7 @@ jobs:
- sw
- misskey-js
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
+1 -1
View File
@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
fetch-depth: 0
submodules: true
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+2 -2
View File
@@ -22,12 +22,12 @@ jobs:
NODE_OPTIONS: "--max_old_space_size=7168"
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
if: github.event_name != 'pull_request_target'
with:
fetch-depth: 0
submodules: true
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
if: github.event_name == 'pull_request_target'
with:
fetch-depth: 0
+3 -3
View File
@@ -50,7 +50,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
@@ -129,7 +129,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
@@ -173,7 +173,7 @@ jobs:
POSTGRES_HOST_AUTH_METHOD: trust
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+2 -2
View File
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
@@ -76,7 +76,7 @@ jobs:
- 56312:6379
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
# https://github.com/cypress-io/cypress-docker-images/issues/150
+1 -1
View File
@@ -22,7 +22,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4.2.2
uses: actions/checkout@v4.3.0
- name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+1 -1
View File
@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4.2.2
- uses: actions/checkout@v4.3.0
with:
submodules: true
- name: Setup pnpm
+49 -5
View File
@@ -1,3 +1,31 @@
## Unreleased
### General
- Enhance: 広告ごとにセンシティブフラグを設定できるようになりました
### Client
- Enhance: 時刻計算のための基準値を一か所で管理するようにし、パフォーマンスを向上
### Server
-
## 2025.9.0
### Client
- Enhance: AiScriptAppウィジェットで構文エラーを検知してもダイアログではなくウィジェット内にエラーを表示するように
- Enhance: /flushページでサイトキャッシュをクリアできるようになりました
- Enhance: クリップ/リスト/アンテナ/ロール追加系メニュー項目において、表示件数を拡張
- Enhance: 「キャッシュを削除」ボタンでブラウザの内部キャッシュの削除も行えるように
- Enhance: Ctrlキー(Commandキー)を押下しながらリンクをクリックすると新しいタブで開くように
- Fix: プッシュ通知を有効にできない問題を修正
- Fix: RSSティッカーウィジェットが正しく動作しない問題を修正
- Fix: プロファイルを復元後アカウントの切り替えができない問題を修正
- Fix: エラー画像が横に引き伸ばされてしまう問題に対応
### Server
- Fix: webpなどの画像に対してセンシティブなメディアの検出が適用されていなかった問題を修正
## 2025.8.0
### Note
@@ -6,8 +34,8 @@
### General
- ノートを削除した際、関連するノートが同時に削除されないようになりました
- APIで、「replyIdが存在しているのにreplyがnull」や「renoteIdが存在しているのにrenoteがnull」であるという、今までにはなかったパターンが表れることになります
- 定期的に参照されていない古いリモートの投稿を削除する機能が実装されました(コントロールパネル→パフォーマンス→Remote Notes Cleaning)
- 既存のサーバーでは**デフォルトでオフ**、新規サーバーでは**デフォルトでオン**になります
- 定期的に古いリモートの投稿を削除する機能が実装されました
- コントロールパネル→パフォーマンス→Remote Notes Cleaning で有効化できます
- データベースの肥大化を防止することが可能です
- 既存のサーバーで当機能を有効化した場合は、処理量が多くなるため、一時的にストレージ使用量が増加する可能性があります。
- 増加量を抑えるには、最大処理継続時間をデフォルトより短くしてください。
@@ -15,7 +43,8 @@
- サーバーの初期設定が完了するまでは連合がオンにならないようになりました
- 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました
- 実際の動作に即した名称になり、馴染みのない人でも理解しやすくなりました
- 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました
- 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが(過去のバージョンのMisskeyでも、当該機能は「チャット」ではなく「ダイレクトメッセージ」でした)、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました
- 今後、「チャット」の名称を「ダイレクトメッセージ」に戻す可能性があります
- mfm.jsをアップデートしました
- Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応
- Enhance: acctに `.` が入っているユーザーのメンションに対応
@@ -27,6 +56,7 @@
- プラグインは1.xに対応したものが必要です
- Playはそのまま動作しますが、新規に作られるプリセットは1.xになります
- 以前のバージョンから無効化されていた note_view_interruptor が有効になりました
- ハンドラは同期的である必要があります
- Feat: セーフモード
- プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます
- 以下の方法でセーフモードを起動できます
@@ -37,13 +67,16 @@
- コントロールパネル→ブランディング→エントランスページのスタイル
- Feat: ページのタブバーを下部に表示できるように
- Feat: (実験的)iOSでの触覚フィードバックを有効にできるように
- Feat: コントロールパネルを検索できるように
- Enhance: 「自動でもっと見る」オプションが有効になり、安定性が向上しました
- Enhance: コントロールパネルを検索できるように
- Enhance: トルコ語 (tr-TR) に対応
- Enhance: 不必要な翻訳データを読み込まなくなり、パフォーマンスが向上しました
- Enhance: 画像エフェクトのパラメータ名の多言語対応
- Enhance: 依存ソフトウェアの更新
- Enhance: ノートを非表示にする相対期間を1ヶ月単位で自由に指定できるように
- Enhance: メールアドレス確認画面のUIを改善
- Enhance: アイコンのスクロール追従を無効化する際の適用範囲を強化
- Enhance: レンダリングパフォーマンスの向上
- Enhance: 依存ソフトウェアの更新
- Fix: 投稿フォームでファイルのアップロードが中止または失敗した際のハンドリングを修正
- Fix: 一部の設定検索結果が存在しないパスになる問題を修正
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1171)
@@ -52,6 +85,12 @@
- Fix: カラムの名前が正しくリスト/チャンネルの名前にならない問題を修正
- Fix: 複数のメンションを1行に記述した場合に、サジェストが正しく表示されない問題を修正
- Fix: メンションとしての条件を満たしていても、特定の条件(`-`が含まれる場合など)で正しくサジェストされない問題を一部修正
- Fix: ユーザーの前後ノートを閲覧する機能が動作しない問題を修正
- Fix: 照会ダイアログでap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正
- Fix: アイコンのデコレーションを付ける際にデコレーションが表示されなくなる問題を修正
- Fix: タッチ操作時にマウスホバー時のユーザープレビューが開くことがある問題を修正
- Fix: 管理中アカウント一覧で正しい表示が行われない問題を修正
- Fix: lookupページでリモートURLを指定した際に正しく動作しない問題を修正
### Server
- Feat: サーバー管理コマンド
@@ -61,7 +100,12 @@
- Enhance: ノートの削除処理の効率化
- Enhance: 全体的なパフォーマンスの向上
- Enhance: 依存ソフトウェアの更新
- Enhance: `clips/list` APIがページネーションに対応しました
- Fix: `notes/mentions` で場合によっては並び順が正しく返されない問題を修正
- Fix: SystemWebhook設定でsecretを空に出来ない問題を修正
- Fix: 削除されたユーザーがチャットメッセージにリアクションしている場合`chat/history`などでエラーになる問題を修正
- Fix: Pageのアイキャッチ画像をドライブから消してもPageごと消えないように
- Fix: タイムラインAPIの withRenotes: false 時のレスポンスを修正
## 2025.7.0
+2 -2
View File
@@ -4,8 +4,8 @@
*/
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { action } from '@storybook/addon-actions';
import { StoryObj } from '@storybook/vue3';
import { action } from 'storybook/actions';
import type { StoryObj } from '@storybook/vue3';
import { HttpResponse, http } from 'msw';
import { abuseUserReport } from '../packages/frontend/.storybook/fakes.js';
import { commonHandlers } from '../packages/frontend/.storybook/mocks.js';
+3 -3
View File
@@ -1245,7 +1245,7 @@ releaseToRefresh: "Deixar anar per actualitzar"
refreshing: "Recarregant..."
pullDownToRefresh: "Llisca cap a baix per recarregar"
useGroupedNotifications: "Mostrar les notificacions agrupades "
signupPendingError: "Hi ha hagut un problema verificant l'adreça de correu electrònic. L'enllaç pot haver caducat."
emailVerificationFailedError: "Hem tingut un problema en verificar la teva adreça de correu electrònic. És probable que l'enllaç estigui caducat."
cwNotationRequired: "Si està activat \"Amagar contingut\" s'ha d'escriure una descripció "
doReaction: "Afegeix una reacció "
code: "Codi"
@@ -1644,7 +1644,7 @@ _serverSettings:
reactionsBufferingDescription: "Quan s'activa aquesta opció millora bastant el rendiment en recuperar les línies de temps reduint la càrrega de la base. Com a contrapunt, augmentarà l'ús de memòria de Redís. Desactiva aquesta opció en cas de tenir un servidor amb poca memòria o si tens problemes d'inestabilitat."
remoteNotesCleaning: "Neteja automàtica de notes remotes"
remoteNotesCleaning_description: "Quan activis aquesta opció, periòdicament es netejaran les notes remotes que no es consultin, això evitarà que la base de dades se"
remoteNotesCleaningMaxProcessingDuration: "D'oració màxima del temps de funcionament del procés de neteja"
remoteNotesCleaningMaxProcessingDuration: "Duració màxima del temps de funcionament del procés de neteja"
remoteNotesCleaningExpiryDaysForEachNotes: "Duració mínima de conservació de les notes"
inquiryUrl: "URL de consulta "
inquiryUrlDescription: "Escriu adreça URL per al formulari de consulta per al mantenidor del servidor o una pàgina web amb el contacte d'informació."
@@ -1668,7 +1668,7 @@ _serverSettings:
restartServerSetupWizardConfirm_text: "Algunes configuracions actuals seran restablertes."
entrancePageStyle: "Estil de la pàgina d'inici"
showTimelineForVisitor: "Mostrar la línia de temps"
showActivityiesForVisitor: "Mostrar les activitats"
showActivitiesForVisitor: "Mostrar activitat"
_userGeneratedContentsVisibilityForVisitor:
all: "Tot obert al públic "
localOnly: "Només es publiquen els continguts locals, el contingut remot es manté privat"
-1
View File
@@ -1243,7 +1243,6 @@ releaseToRefresh: "Zum Aktualisieren loslassen"
refreshing: "Wird aktualisiert..."
pullDownToRefresh: "Zum Aktualisieren ziehen"
useGroupedNotifications: "Benachrichtigungen gruppieren"
signupPendingError: "Beim Überprüfen der Mailadresse ist etwas schiefgelaufen. Der Link könnte abgelaufen sein."
cwNotationRequired: "Ist \"Inhaltswarnung verwenden\" aktiviert, muss eine Beschreibung gegeben werden."
doReaction: "Reagieren"
code: "Code"
+7 -3
View File
@@ -1218,8 +1218,8 @@ showRepliesToOthersInTimeline: "Show replies to others in timeline"
hideRepliesToOthersInTimeline: "Hide replies to others from timeline"
showRepliesToOthersInTimelineAll: "Show replies to others from everyone you follow in timeline"
hideRepliesToOthersInTimelineAll: "Hide replies to others from everyone you follow in timeline"
confirmShowRepliesAll: "This operation is irreversible. Would you really like to show replies to others from everyone you follow in your timeline?"
confirmHideRepliesAll: "This operation is irreversible. Would you really like to hide replies to others from everyone you follow in your timeline?"
confirmShowRepliesAll: "Are you sure you want to show replies from everyone you follow in your timeline? This action is irreversible."
confirmHideRepliesAll: "Are you sure you want to hide replies from everyone you follow in your timeline? This action is irreversible."
externalServices: "External Services"
sourceCode: "Source code"
sourceCodeIsNotYetProvided: "Source code is not yet available. Contact the administrator to fix this problem."
@@ -1245,7 +1245,7 @@ releaseToRefresh: "Release to refresh"
refreshing: "Refreshing..."
pullDownToRefresh: "Pull down to refresh"
useGroupedNotifications: "Display grouped notifications"
signupPendingError: "There was a problem verifying the email address. The link may have expired."
emailVerificationFailedError: "A problem occurred while verifying your email address. The link may have expired."
cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided."
doReaction: "Add reaction"
code: "Code"
@@ -1376,6 +1376,7 @@ safeModeEnabled: "Safe mode is enabled"
pluginsAreDisabledBecauseSafeMode: "All plugins are disabled because safe mode is enabled."
customCssIsDisabledBecauseSafeMode: "Custom CSS is not applied because safe mode is enabled."
themeIsDefaultBecauseSafeMode: "While safe mode is active, the default theme is used. Disabling safe mode will revert these changes."
thankYouForTestingBeta: "Thank you for helping us test the beta version!"
_order:
newest: "Newest First"
oldest: "Oldest First"
@@ -1665,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Unconditionally publishing all content on the server to the Internet, including remote content received by the server is risky. This is especially important for guests who are unaware of the distributed nature of the content, as they may mistakenly believe that even remote content is content created by users on the server."
restartServerSetupWizardConfirm_title: "Restart server setup wizard?"
restartServerSetupWizardConfirm_text: "Some current settings will be reset."
entrancePageStyle: "Entrance page style"
showTimelineForVisitor: "Show timeline"
showActivitiesForVisitor: "Show activities"
_userGeneratedContentsVisibilityForVisitor:
all: "Everything is public"
localOnly: "Only local content is published, remote content is kept private"
+8 -2
View File
@@ -1054,6 +1054,7 @@ permissionDeniedError: "Operación denegada"
permissionDeniedErrorDescription: "Esta cuenta no tiene permisos para hacer esa acción."
preset: "Predefinido"
selectFromPresets: "Escoger desde predefinidos"
custom: "Personalizado"
achievements: "Logros"
gotInvalidResponseError: "Respuesta del servidor inválida"
gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde"
@@ -1244,7 +1245,7 @@ releaseToRefresh: "Soltar para recargar"
refreshing: "Recargando..."
pullDownToRefresh: "Tira hacia abajo para recargar"
useGroupedNotifications: "Mostrar notificaciones agrupadas"
signupPendingError: "Ha habido un problema al verificar tu dirección de correo electrónico. Es posible que el enlace haya caducado."
emailVerificationFailedError: "Se ha producido un error al confirmar tu dirección de correo electrónico. Es posible que el enlace haya caducado."
cwNotationRequired: "Si se ha activado \"ocultar contenido\", es necesario proporcionar una descripción."
doReaction: "Añadir reacción"
code: "Código"
@@ -1375,6 +1376,7 @@ safeModeEnabled: "El modo seguro está activado"
pluginsAreDisabledBecauseSafeMode: "El modo seguro está activado, por lo que todos los plugins están desactivados."
customCssIsDisabledBecauseSafeMode: "El modo seguro está activado, por lo que no se aplica el CSS personalizado."
themeIsDefaultBecauseSafeMode: "Mientras el modo seguro esté activado, se utilizará el tema predeterminado. Cuando se desactive el modo seguro, se volverá al tema original."
thankYouForTestingBeta: "¡Gracias por tu colaboración en la prueba de la versión beta!"
_order:
newest: "Los más recientes primero"
oldest: "Los más antiguos primero"
@@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Publicar incondicionalmente todo el contenido del servidor en Internet, incluido el contenido remoto recibido por el servidor, es arriesgado. Esto es especialmente importante para los invitados que desconocen la naturaleza distribuida del contenido, ya que pueden creer erróneamente que incluso el contenido remoto es contenido creado por usuarios en el servidor."
restartServerSetupWizardConfirm_title: "¿Reiniciar el asistente de configuración del servidor?"
restartServerSetupWizardConfirm_text: "Algunas configuraciones actuales se restablecerán"
entrancePageStyle: "Estilo de la página de inicio"
showTimelineForVisitor: "Mostrar la línea de tiempo"
showActivitiesForVisitor: "Mostrar actividades"
_userGeneratedContentsVisibilityForVisitor:
all: "Todo es público."
localOnly: "Sólo se publica el contenido local, el remoto se mantiene privado"
@@ -2132,7 +2137,7 @@ _aboutMisskey:
_displayOfSensitiveMedia:
respect: "Esconder medios marcados como sensibles"
ignore: "Mostrar medios marcados como sensibles"
force: "Esconder todala multimedia"
force: "Esconder toda la multimedia"
_instanceTicker:
none: "No mostrar"
remote: "Mostrar a usuarios remotos"
@@ -2273,6 +2278,7 @@ _time:
minute: "Minutos"
hour: "Horas"
day: "Días"
month: "Mes(es)"
_2fa:
alreadyRegistered: "Ya has completado la configuración."
registerTOTP: "Registrar aplicación autenticadora"
-1
View File
@@ -1208,7 +1208,6 @@ releaseToRefresh: "Relâcher pour rafraîchir"
refreshing: "Rafraîchissement..."
pullDownToRefresh: "Tirer vers le bas pour rafraîchir"
useGroupedNotifications: "Grouper les notifications"
signupPendingError: "Un problème est survenu lors de la vérification de votre adresse e-mail. Le lien a peut-être expiré."
cwNotationRequired: "Si « Masquer le contenu » est activé, une description doit être fournie."
doReaction: "Réagir"
code: "Code"
-1
View File
@@ -1212,7 +1212,6 @@ releaseToRefresh: "Lepaskan untuk memuat ulang"
refreshing: "Sedang memuat ulang..."
pullDownToRefresh: "Tarik ke bawah untuk memuat ulang"
useGroupedNotifications: "Tampilkan notifikasi secara dikelompokkan"
signupPendingError: "Terdapat masalah ketika memverifikasi alamat surel. Tautan kemungkinan telah kedaluwarsa."
cwNotationRequired: "Jika \"Sembunyikan konten\" diaktifkan, deskripsi harus disediakan."
doReaction: "Tambahkan reaksi"
code: "Kode"
+5 -5
View File
@@ -5001,7 +5001,7 @@ export interface Locale extends ILocale {
/**
* メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。
*/
"signupPendingError": string;
"emailVerificationFailedError": string;
/**
* 「内容を隠す」がオンの場合は注釈の記述が必要です。
*/
@@ -6531,7 +6531,7 @@ export interface Locale extends ILocale {
*/
"remoteNotesCleaning": string;
/**
* 有効にすると、参照されていない古いリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。
* 有効にすると、一定期間経過したリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。
*/
"remoteNotesCleaning_description": string;
/**
@@ -6633,7 +6633,7 @@ export interface Locale extends ILocale {
/**
* アクティビティを表示する
*/
"showActivityiesForVisitor": string;
"showActivitiesForVisitor": string;
"_userGeneratedContentsVisibilityForVisitor": {
/**
* 全て公開
@@ -12032,11 +12032,11 @@ export interface Locale extends ILocale {
*/
"youCanConfigureMoreFederationSettingsLater": string;
/**
* 受信コンテンツの自動クリーニング
* リモートコンテンツの自動クリーニング
*/
"remoteContentsCleaning": string;
/**
* 連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、参照されていない古くなったコンテンツを自動でサーバーから削除し、ストレージを節約できます。
* 連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、一定期間経過したリモートコンテンツを自動でサーバーから削除し、ストレージを節約できます。
*/
"remoteContentsCleaning_description": string;
/**
+56 -56
View File
@@ -139,7 +139,7 @@ overwriteFromPinnedEmojis: "Sovrascrivi con le impostazioni globali"
reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere."
rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note"
attachCancel: "Rimuovi allegato"
deleteFile: "File da Drive eliminato"
deleteFile: "Elimina un file dal Drive"
markAsSensitive: "Segna come esplicito"
unmarkAsSensitive: "Non segnare come esplicito "
enterFileName: "Nome del file"
@@ -1245,7 +1245,7 @@ releaseToRefresh: "Rilascia per aggiornare"
refreshing: "Aggiornamento..."
pullDownToRefresh: "Trascinare per aggiornare"
useGroupedNotifications: "Mostra le notifiche raggruppate"
signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo."
emailVerificationFailedError: "La verifica dell'indirizzo e-mail non è andata a buon fine. Il link potrebbe essere scaduto."
cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito."
doReaction: "Reagisci"
code: "Codice"
@@ -1668,7 +1668,7 @@ _serverSettings:
restartServerSetupWizardConfirm_text: "Verranno ripristinate alcune tue impostazioni personalizzate."
entrancePageStyle: "Stile della pagina di ingresso"
showTimelineForVisitor: "Mostra la Timeline a visitatori non autenticati"
showActivityiesForVisitor: "Mostra le attività a visitatori non autenticati"
showActivitiesForVisitor: "Mostrare la propria attività"
_userGeneratedContentsVisibilityForVisitor:
all: "Tutto pubblico"
localOnly: "Pubblica solo contenuti locali, mantieni privati ​​i contenuti remoti"
@@ -2222,7 +2222,7 @@ _theme:
hashtag: "Hashtag"
mention: "Menzioni"
mentionMe: "Menzioni (di me)"
renote: "Renota"
renote: "Rinota"
modalBg: "Sfondo modale."
divider: "Interruzione di linea"
scrollbarHandle: "Maniglie della barra di scorrimento"
@@ -2663,7 +2663,7 @@ _notification:
createToken: "È stato creato un token di accesso"
createTokenDescription: "In caso contrario, eliminare il token di accesso tramite ({text})."
_types:
all: "Tutto"
all: "Tutte"
note: "Nuove Note"
follow: "Follower"
mention: "Menzioni"
@@ -2671,7 +2671,7 @@ _notification:
renote: "Rinota"
quote: "Cita"
reaction: "Reazioni"
pollEnded: "Sondaggio chiuso."
pollEnded: "Sondaggio terminato"
receiveFollowRequest: "Richieste di follow in arrivo"
followRequestAccepted: "Richieste di follow accettate"
roleAssigned: "Ruolo concesso"
@@ -2679,7 +2679,7 @@ _notification:
achievementEarned: "Risultato raggiunto"
exportCompleted: "Esportazione completata"
login: "Accessi"
createToken: "Creare un token di accesso"
createToken: "Aggiunto un token di accesso"
test: "Notifiche di test"
app: "Notifiche da applicazioni"
_actions:
@@ -2771,56 +2771,56 @@ _abuseReport:
notifiedWebhook: "Webhook da usare"
deleteConfirm: "Vuoi davvero rimuovere il destinatario della notifica?"
_moderationLogTypes:
createRole: "Ruolo creato"
deleteRole: "Ruolo eliminato"
updateRole: "Ruolo aggiornato"
assignRole: "Ruolo assegnato"
unassignRole: "Ruolo disassegnato"
suspend: "Sospensione"
unsuspend: "Sospensione rimossa"
addCustomEmoji: "Emoji personalizzata aggiunta"
updateCustomEmoji: "Emoji personalizzata aggiornata"
deleteCustomEmoji: "Emoji personalizzata eliminata"
updateServerSettings: "Impostazioni del server aggiornate"
updateUserNote: "Promemoria di moderazione aggiornato"
deleteDriveFile: "File da Drive eliminato"
deleteNote: "Nota eliminata"
createGlobalAnnouncement: "Annuncio globale creato"
createUserAnnouncement: "Annuncio ai profili iscritti creato"
updateGlobalAnnouncement: "Annuncio globale aggiornato"
updateUserAnnouncement: "Annuncio ai profili iscritti aggiornato"
deleteGlobalAnnouncement: "Annuncio globale eliminato"
deleteUserAnnouncement: "Annuncio ai profili iscritti eliminato"
resetPassword: "Password azzerata"
suspendRemoteInstance: "Istanza remota sospesa"
unsuspendRemoteInstance: "Istanza remota riattivata"
updateRemoteInstanceNote: "Aggiornamento del promemoria di moderazione per il server remoto"
markSensitiveDriveFile: "File nel Drive segnato come esplicito"
unmarkSensitiveDriveFile: "File nel Drive segnato come non esplicito"
resolveAbuseReport: "Segnalazione risolta"
forwardAbuseReport: "Segnalazione inoltrata"
updateAbuseReportNote: "Ha aggiornato la segnalazione"
createInvitation: "Genera codice di invito"
createAd: "Banner creato"
deleteAd: "Banner eliminato"
updateAd: "Banner aggiornato"
createAvatarDecoration: "Creazione decorazione della foto profilo"
updateAvatarDecoration: "Aggiornamento decorazione foto profilo"
deleteAvatarDecoration: "Eliminazione decorazione della foto profilo"
unsetUserAvatar: "Rimossa foto profilo"
unsetUserBanner: "Rimossa intestazione profilo"
createSystemWebhook: "Crea un SystemWebhook"
updateSystemWebhook: "Modifica SystemWebhook"
deleteSystemWebhook: "Elimina SystemWebhook"
createRole: "Crea un Ruolo"
deleteRole: "Elimina un Ruolo"
updateRole: "Modifica un ruolo"
assignRole: "Assegna un Ruolo"
unassignRole: "Toglie un Ruolo al Profilo"
suspend: "Sospende"
unsuspend: "Solleva la sospensione"
addCustomEmoji: "Aggiunge Emoji personalizzata"
updateCustomEmoji: "Modifica Emoji personalizzata"
deleteCustomEmoji: "Elimina Emoji personalizzata"
updateServerSettings: "Modifica le impostazioni del server"
updateUserNote: "Modifica un promemoria di moderazione"
deleteDriveFile: "Elimina un file dal Drive"
deleteNote: "Elimina una Nota"
createGlobalAnnouncement: "Crea un annuncio globale"
createUserAnnouncement: "Crea un annuncio ai profili già iscritti"
updateGlobalAnnouncement: "Modifica un annuncio globale"
updateUserAnnouncement: "Modifica un annuncio ai profili già iscritti"
deleteGlobalAnnouncement: "Elimina un annuncio globale"
deleteUserAnnouncement: "Elimina un annuncio ai profili già iscritti"
resetPassword: "Azzera la password"
suspendRemoteInstance: "Sospende una istanza remota"
unsuspendRemoteInstance: "Riattiva una istanza remota"
updateRemoteInstanceNote: "Modifica il promemoria di moderazione per il server remoto"
markSensitiveDriveFile: "Aggiunge NSFW a un file nel Drive"
unmarkSensitiveDriveFile: "Toglie NSFW da un file nel Drive"
resolveAbuseReport: "Risolve una segnalazione"
forwardAbuseReport: "Inoltra una segnalazione"
updateAbuseReportNote: "Modifica una segnalazione"
createInvitation: "Genera un codice di invito"
createAd: "Aggiunge un Banner"
deleteAd: "Elimina un Banner"
updateAd: "Modifica un Banner"
createAvatarDecoration: "Crea una decorazione della foto profilo"
updateAvatarDecoration: "Modifica una decorazione della foto profilo"
deleteAvatarDecoration: "Elimina una decorazione della foto profilo"
unsetUserAvatar: "Toglie una foto profilo"
unsetUserBanner: "Toglie una immagine di intestazione profilo"
createSystemWebhook: "Aggiunge un System Webhook"
updateSystemWebhook: "Modifica un System Webhook"
deleteSystemWebhook: "Elimina un System Webhook"
createAbuseReportNotificationRecipient: "Crea destinatario per le notifiche di segnalazioni"
updateAbuseReportNotificationRecipient: "Aggiorna destinatario notifiche di segnalazioni"
deleteAbuseReportNotificationRecipient: "Elimina destinatario notifiche di segnalazioni"
deleteAccount: "Quando viene eliminato un profilo"
deletePage: "Pagina eliminata"
deleteFlash: "Play eliminato"
deleteGalleryPost: "Eliminazione pubblicazione nella Galleria"
deleteChatRoom: "Elimina chat"
updateProxyAccountDescription: "Aggiornata la descrizione del profilo proxy"
updateAbuseReportNotificationRecipient: "Modifica un destinatario per le notifiche di segnalazioni"
deleteAbuseReportNotificationRecipient: "Elimina un destinatario per le notifiche di segnalazioni"
deleteAccount: "Elimina un profilo"
deletePage: "Elimina una Pagina"
deleteFlash: "Elimina un Play"
deleteGalleryPost: "Elimina pubblicazione nella Galleria"
deleteChatRoom: "Elimina una Chat"
updateProxyAccountDescription: "Aggiorna la descrizione del profilo proxy"
_fileViewer:
title: "Dettagli del file"
type: "Tipo di file"
+5 -5
View File
@@ -1245,7 +1245,7 @@ releaseToRefresh: "離してリロード"
refreshing: "リロード中"
pullDownToRefresh: "引っ張ってリロード"
useGroupedNotifications: "通知をグルーピング"
signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
emailVerificationFailedError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。"
doReaction: "リアクションする"
code: "コード"
@@ -1660,7 +1660,7 @@ _serverSettings:
fanoutTimelineDbFallbackDescription: "有効にすると、タイムラインがキャッシュされていない場合にDBへ追加で問い合わせを行うフォールバック処理を行います。無効にすると、フォールバック処理を行わないことでさらにサーバーの負荷を軽減することができますが、タイムラインが取得できる範囲に制限が生じます。"
reactionsBufferingDescription: "有効にすると、リアクション作成時のパフォーマンスが大幅に向上し、データベースへの負荷を軽減することが可能です。ただし、Redisのメモリ使用量は増加します。"
remoteNotesCleaning: "リモート投稿の自動クリーニング"
remoteNotesCleaning_description: "有効にすると、参照されていない古いリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。"
remoteNotesCleaning_description: "有効にすると、一定期間経過したリモートの投稿を定期的にクリーンアップしてデータベースの肥大化を抑制します。"
remoteNotesCleaningMaxProcessingDuration: "最大クリーニング処理継続時間"
remoteNotesCleaningExpiryDaysForEachNotes: "最低ノート保持日数"
inquiryUrl: "問い合わせ先URL"
@@ -1685,7 +1685,7 @@ _serverSettings:
restartServerSetupWizardConfirm_text: "現在の一部の設定はリセットされます。"
entrancePageStyle: "エントランスページのスタイル"
showTimelineForVisitor: "タイムラインを表示する"
showActivityiesForVisitor: "アクティビティを表示する"
showActivitiesForVisitor: "アクティビティを表示する"
_userGeneratedContentsVisibilityForVisitor:
all: "全て公開"
@@ -3216,8 +3216,8 @@ _serverSetupWizard:
doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。"
doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。"
youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。"
remoteContentsCleaning: "受信コンテンツの自動クリーニング"
remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、参照されていない古くなったコンテンツを自動でサーバーから削除し、ストレージを節約できます。"
remoteContentsCleaning: "リモートコンテンツの自動クリーニング"
remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、一定期間経過したリモートコンテンツを自動でサーバーから削除し、ストレージを節約できます。"
adminInfo: "管理者情報"
adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。"
adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。"
-1
View File
@@ -1239,7 +1239,6 @@ releaseToRefresh: "離したらリロード"
refreshing: "リロードしとる"
pullDownToRefresh: "引っ張ってリロードするで"
useGroupedNotifications: "通知をグループ分けして出すで"
signupPendingError: "メアド確認してたらなんか変なことなったわ。リンクの期限切れてるかもしれん。"
cwNotationRequired: "「内容を隠す」んやったら注釈書かなアカンで。"
doReaction: "ツッコむで"
code: "コード"
+2 -2
View File
@@ -1245,7 +1245,7 @@ releaseToRefresh: "놓아서 새로고침"
refreshing: "새로고침 중"
pullDownToRefresh: "아래로 내려서 새로고침"
useGroupedNotifications: "알림을 그룹화하고 표시"
signupPendingError: "메일 주소 확인중에 문제가 발생했습니다. 링크의 유효기간이 지났을 가능성이 있습니다."
emailVerificationFailedError: "메일 주소 확인에 실패했습니다. 확인에 필요한 URL의 유효기간이 지났을 가능성이 있습니다."
cwNotationRequired: "'내용을 숨기기'를 체크한 경우 주석을 써야 합니다."
doReaction: "리액션 추가"
code: "문자열"
@@ -1668,7 +1668,7 @@ _serverSettings:
restartServerSetupWizardConfirm_text: "현재 일부 설정은 리셋됩니다."
entrancePageStyle: "입구 페이지의 스타일"
showTimelineForVisitor: "타임라인 표시"
showActivityiesForVisitor: "활동 표시"
showActivitiesForVisitor: "액티비티 표시하기"
_userGeneratedContentsVisibilityForVisitor:
all: "모두 공개"
localOnly: "로컬 콘텐츠만 공개하고 리모트 콘텐츠는 비공개"
-1
View File
@@ -1243,7 +1243,6 @@ releaseToRefresh: "Solte para atualizar"
refreshing: "Atualizando..."
pullDownToRefresh: "Puxe para baixo para atualizar"
useGroupedNotifications: "Agrupar notificações"
signupPendingError: "Houve um problema ao verificar o endereço de email. O link pode ter expirado."
cwNotationRequired: "Se \"Esconder conteúdo\" está habilitado, uma descrição deve ser adicionada."
doReaction: "Adicionar reação"
code: "Código"
+17 -3
View File
@@ -1215,12 +1215,12 @@ privacyPolicyUrl: "Ссылка на Политику Конфиденциаль
tosAndPrivacyPolicy: "Условия использования и политика конфиденциальности"
avatarDecorations: "Украшения для аватара"
attach: "Прикрепить"
detachAll: "Убрать всё"
angle: "Угол"
flip: "Переворот"
showAvatarDecorations: "Показать украшения для аватара"
pullDownToRefresh: "Опустите что бы обновить"
useGroupedNotifications: "Отображать уведомления сгруппировано"
signupPendingError: "Возникла проблема с подтверждением вашего адреса электронной почты. Возможно, срок действия ссылки истёк."
cwNotationRequired: "Если включена опция «Скрыть содержимое», необходимо написать аннотацию."
doReaction: "Добавить реакцию"
code: "Код"
@@ -1254,7 +1254,7 @@ clipNoteLimitExceeded: "К этому клипу больше нельзя до
performance: "Производительность"
modified: "Изменено"
signinWithPasskey: "Войдите в систему, используя свой пароль"
unknownWebAuthnKey: "Не известный ключ "
unknownWebAuthnKey: "Неизвестный ключ"
passkeyVerificationFailed: "Ошибка проверка ключа доступа "
messageToFollower: "Сообщение подписчикам"
testCaptchaWarning: "Эта функция предназначена для тестирования CAPTCHA. <strong>Не использовать это в рабочей среде</strong>"
@@ -1269,8 +1269,11 @@ availableRoles: "Доступные роли"
federationDisabled: "Федерация отключена для этого сервера. Вы не можете взаимодействовать с пользователями на других серверах."
draft: "Черновик"
markAsSensitiveConfirm: "Отметить контент как чувствительный?"
preferences: "Основное"
resetToDefaultValue: "Сбросить настройки до стандартных"
syncBetweenDevices: "Синхронизировать между устройствами"
postForm: "Форма отправки"
textCount: "Количество символов"
information: "Описание"
inMinutes: "мин"
inDays: "сут"
@@ -1282,6 +1285,11 @@ _chat:
send: "Отправить"
_settings:
webhook: "Вебхук"
preferencesBanner: "Вы можете настроить общее поведение клиента по вашим предпочтениям"
timelineAndNote: "Лента и заметки"
_chat:
showSenderName: "Показывать имя отправителя"
sendOnEnter: "Использовать Enter для отправки"
_delivery:
stop: "Заморожено"
_type:
@@ -1530,7 +1538,7 @@ _achievements:
description: "Нажато здесь"
_justPlainLucky:
title: "Чистая удача"
description: "Может достаться с вероятностью 0,01% каждые 10 секунд."
description: "Может достаться с вероятностью 0,005% каждые 10 секунд."
_setNameToSyuilo:
title: "Комплекс бога"
description: "Установлено «syuilo» в качестве имени"
@@ -1558,6 +1566,12 @@ _achievements:
title: "Brain Diver"
description: "Опубликована ссылка на песню «Brain Diver»"
flavor: "Мисски-Мисски Ла-Ту-Ма"
_bubbleGameExplodingHead:
title: "🤯"
description: "Самый большой объект в Bubble game"
_bubbleGameDoubleExplodingHead:
title: "Двойной🤯"
description: "Два самых больших объекта в Bubble game одновременно!"
_role:
new: "Новая роль"
edit: "Изменить роль"
-1
View File
@@ -1245,7 +1245,6 @@ releaseToRefresh: "ปล่อยเพื่อรีเฟรช"
refreshing: "กำลังรีเฟรช..."
pullDownToRefresh: "ดึงลงเพื่อรีเฟรช"
useGroupedNotifications: "แสดงผลการแจ้งเตือนแบบกลุ่มแล้ว"
signupPendingError: "มีปัญหาในการตรวจสอบที่อยู่อีเมลลิงก์อาจหมดอายุแล้ว"
cwNotationRequired: "หากเปิดใช้งาน “ซ่อนเนื้อหา” จะต้องระบุคำอธิบาย"
doReaction: "เพิ่มรีแอคชั่น"
code: "โค้ด"
+33 -27
View File
@@ -31,7 +31,7 @@ openInWindow: "Pencerede aç"
profile: "Profil"
timeline: "Pano"
noAccountDescription: "Bu kullanıcı henüz biyografisini yazmamış."
login: "Giriş Yap"
login: "Oturum Aç"
loggingIn: "Giriş Yapılıyor..."
logout: "Çıkış Yap"
signup: "Kaydol"
@@ -310,7 +310,7 @@ agreeBelow: "Aşağıdakileri kabul ediyorum"
basicNotesBeforeCreateAccount: "Önemli notlar"
termsOfService: "Hizmet Şartları"
start: "Başla"
home: "Ana sayfa"
home: "Pano"
remoteUserCaution: "Bu kullanıcı uzak bir sunucudan geldiği için, gösterilen bilgiler eksik olabilir."
activity: "Etkinlik"
images: "Görseller"
@@ -360,7 +360,7 @@ whenServerDisconnected: "Sunucu ile bağlantı kesildiğinde"
disconnectedFromServer: "Sunucu bağlantısı kesildi"
reload: "Yenile"
doNothing: "Yoksay"
reloadConfirm: "Zaman çizelgesini yenilemek ister misin?"
reloadConfirm: "Panoyu yenilemek ister misin?"
watch: "İzle"
unwatch: "İzlemeyi bırak"
accept: "Kabul et"
@@ -573,9 +573,9 @@ objectStorageSetPublicRead: "Yükleme sırasında \"genel-okuma\" ayarını yap
s3ForcePathStyleDesc: "s3ForcePathStyle etkinleştirilirse, kova adı URL'nin ana bilgisayar adı yerine URL yoluna eklenmelidir. Kendi kendine barındırılan bir Minio örneği gibi hizmetleri kullanırken bu ayarı etkinleştirmen gerekebilir."
serverLogs: "Sunucu log kayıtları"
deleteAll: "Tümünü sil"
showFixedPostForm: "Gönderi formunu zaman çizelgesinin en üstünde görüntüle"
showFixedPostFormInChannel: "Gönderi formunu zaman çizelgesinin en üstünde görüntüle (Kanallar)"
withRepliesByDefaultForNewlyFollowed: "Yeni takip edilen kullanıcıların yanıtlarını varsayılan olarak zaman çizelgesine dahil et"
showFixedPostForm: "Gönderi formunu pano üstünde görüntüle"
showFixedPostFormInChannel: "Gönderi formunu pano üstünde görüntüle (Kanallar)"
withRepliesByDefaultForNewlyFollowed: "Yeni takip edilen kullanıcıların yanıtlarını varsayılan olarak panoya dahil et"
newNoteRecived: "Yeni Not'lar var"
newNote: "Yeni Not"
sounds: "Sesler"
@@ -1054,11 +1054,12 @@ permissionDeniedError: "İşlem reddedildi"
permissionDeniedErrorDescription: "Bu hesap bu işlemi gerçekleştirmek için gerekli izne sahip değildir."
preset: "Ön ayar"
selectFromPresets: "Ön ayarlardan seçim yapın"
custom: "Özel"
achievements: "Başarılar"
gotInvalidResponseError: "Geçersiz sunucu yanıtı"
gotInvalidResponseErrorDescription: "Sunucu erişilemez durumda olabilir veya bakım çalışması yapılmaktadır. Lütfen daha sonra tekrar dene."
thisPostMayBeAnnoying: "Bu not başkalarını rahatsız edebilir."
thisPostMayBeAnnoyingHome: "Ana zaman çizelgesine gönder"
thisPostMayBeAnnoyingHome: "Ana panoya gönder"
thisPostMayBeAnnoyingCancel: "İptal"
thisPostMayBeAnnoyingIgnore: "Yine de gönder"
collapseRenotes: "Daha önce görüntülenen Renote'lari kısaltılmış olarak göster"
@@ -1066,8 +1067,8 @@ collapseRenotesDescription: "Zaten yanıtladığın veya renote aldığın notla
internalServerError: "İç Sunucu Hatası"
internalServerErrorDescription: "Sunucu beklenmedik bir hatayla karşılaştı."
copyErrorInfo: "Hata ayrıntılarını kopyala"
joinThisServer: "Bu sunucuda kaydolun"
exploreOtherServers: "Başka bir sunucu arayın"
joinThisServer: "Kaydol"
exploreOtherServers: "Diğer sunucuları keşfet"
letsLookAtTimeline: "Pano'ya bir göz atın"
disableFederationConfirm: "Federasyonu cidden devre dışı bırakmak istiyor musun?"
disableFederationConfirmWarn: "Federasyondan ayrılsa bile, aksi belirtilmedikçe gönderiler herkese açık olmaya devam edecek. Genellikle bunu yapmanız gerekmez."
@@ -1217,8 +1218,8 @@ showRepliesToOthersInTimeline: "Pano'da diğer kişilere verilen yanıtları gö
hideRepliesToOthersInTimeline: "Pano'dan diğer kişilerin yanıtlarını gizle"
showRepliesToOthersInTimelineAll: "Pano'da takip ettiğin herkesin diğerlerine verdiği yanıtları göster"
hideRepliesToOthersInTimelineAll: "Pano'da takip ettiğin herkesten diğer kişilere verilen yanıtları gizle"
confirmShowRepliesAll: "Bu işlem geri alınamaz. Takip ettiğin herkesin yanıtlarını zaman çizelgende diğer kullanıcılara göstermek istiyor musun?"
confirmHideRepliesAll: "Bu işlem geri alınamaz. Şu anda takip ettiğin tüm kullanıcıların yanıtlarını zaman tünelinde cidden göstermeyecek misin?"
confirmShowRepliesAll: "Bu işlem geri alınamaz. Takip ettiğin herkesin yanıtlarını panoda diğer kullanıcılara göstermek istiyor musun?"
confirmHideRepliesAll: "Bu işlem geri alınamaz. Şu anda takip ettiğin tüm kullanıcıların yanıtlarını panoda cidden göstermeyecek misin?"
externalServices: "Dış Hizmetler"
sourceCode: "Kaynak kodu"
sourceCodeIsNotYetProvided: "Kaynak kodu henüz mevcut değildir. Bu sorunu gidermek için yöneticiyle iletişime geçin."
@@ -1244,7 +1245,7 @@ releaseToRefresh: "Yenilemek için serbest bırak"
refreshing: "Yenileniyor..."
pullDownToRefresh: "Yenilemek için aşağı çekin"
useGroupedNotifications: "Gruplandırılmış bildirimleri göster"
signupPendingError: "E-posta adresini doğrulamada bir sorun oluştu. Bağlantının süresi dolmuş olabilir."
emailVerificationFailedError: "E-posta adresi doğrulanırken bir sorun oluştu. Bağlantının geçerlilik süresi dolmuş olabilir."
cwNotationRequired: "“İçeriği gizle” seçeneği etkinleştirilirse, bir açıklama sağlanmalı."
doReaction: "Tepki ekle"
code: "Kod"
@@ -1375,6 +1376,7 @@ safeModeEnabled: "Güvenli mod etkinleştirildi"
pluginsAreDisabledBecauseSafeMode: "Güvenli mod etkinleştirildiği için tüm eklentiler devre dışı bırakılmıştır."
customCssIsDisabledBecauseSafeMode: "Güvenli mod etkin olduğu için özel CSS uygulanmıyor."
themeIsDefaultBecauseSafeMode: "Güvenli mod etkinken, varsayılan tema kullanılır. Güvenli modu devre dışı bırakmak bu değişiklikleri geri alır."
thankYouForTestingBeta: "Beta sürümünü test ettiğin için teşekkür ederiz!"
_order:
newest: "Önce yeni"
oldest: "Önce eski"
@@ -1568,9 +1570,9 @@ _initialTutorial:
description: "Burada, Misskey'i kullanmanın temellerini ve özelliklerini öğrenebilirsin."
_note:
title: "Not nedir?"
description: "Misskey'deki gönderiler “Notlar” olarak adlandırılır. Notlar zaman çizelgesinde kronolojik olarak düzenlenir ve gerçek zamanlı olarak güncellenir."
description: "Misskey'deki gönderiler “Notlar” olarak adlandırılır. Notlar panoda kronolojik olarak düzenlenir ve gerçek zamanlı olarak güncellenir."
reply: "Bir mesaja yanıt vermek için bu düğmeye tıklayın. Yanıtlara yanıt vermek de mümkündür, böylece konuşma bir konu başlığı gibi devam eder."
renote: "Bu notu kendi zaman çizelgende paylaşabilirsiniz. Ayrıca yorumlarınızla birlikte alıntı da yapabilirsin."
renote: "Bu notu kendi panonda paylaşabilirsin. Ayrıca yorumlarınla birlikte alıntı da yapabilirsin."
reaction: "Not'a tepkiler ekleyebilirsin. Daha fazla ayrıntı bir sonraki sayfada açıklanacak."
menu: "Not ayrıntılarını görüntüleyebilir, bağlantıları kopyalayabilir ve çeşitli diğer işlemleri gerçekleştirebilirsin."
_reaction:
@@ -1623,7 +1625,7 @@ _initialTutorial:
_timelineDescription:
home: "Ana Pano'da, takip ettiğin hesapların notlarını görebilirsin."
local: "Yerel Pano'da, bu sunucudaki tüm kullanıcıların notlarını görebilirsin."
social: "Sosyal Pano, Ana Sayfa ve Yerel Pano'dan gelen notları görüntüler."
social: "Pano, Sosyal Pano ve Yerel Pano'dan gelen notları görüntüler."
global: "Global Pano'da, bağlı tüm sunuculardan gelen notları görebilirsin."
_serverRules:
description: "Kayıt öncesinde gösterilecek bir dizi kural. Hizmet Şartlarının özetini belirlemen önerilir."
@@ -1638,7 +1640,7 @@ _serverSettings:
shortNameDescription: "Resmi adın uzun olması durumunda görüntülenebilen, örneğin adının kısaltması."
fanoutTimelineDescription: "Etkinleştirildiğinde Pano alma performansını büyük ölçüde artırır ve veritabanı yükünü azaltır. Bunun karşılığında Redis'in bellek kullanımı artacaktır. Sunucu belleği düşükse veya sunucu kararsızsa bunu devre dışı bırakmayı düşün."
fanoutTimelineDbFallback: "Veritabanına geri dön"
fanoutTimelineDbFallbackDescription: "Etkinleştirildiğinde, Pano önbelleğe alınmamışsa ek sorgular için veritabanına geri döner. Bu özelliği devre dışı bırakmak, geri dönüş sürecini ortadan kaldırarak sunucu yükünü daha da azaltır, ancak alınabilecek zaman çizelgelerinin aralığını sınırlar."
fanoutTimelineDbFallbackDescription: "Etkinleştirildiğinde, Pano önbelleğe alınmamışsa ek sorgular için veritabanına geri döner. Bu özelliği devre dışı bırakmak, geri dönüş sürecini ortadan kaldırarak sunucu yükünü daha da azaltır, ancak alınabilecek panoların aralığını sınırlar."
reactionsBufferingDescription: "Etkinleştirildiğinde, reaksiyon oluşturma sırasında performans büyük ölçüde artacak ve veritabanı üzerindeki yük azalacaktır. Ancak, Redis bellek kullanımı artacakt."
remoteNotesCleaning: "Uzak notların otomatik olarak temizlenmesi"
remoteNotesCleaning_description: "Etkinleştirildiğinde, kullanılmayan ve güncelliğini yitirmiş uzak notlar, veritabanının şişmesini önlemek için periyodik olarak temizlenecek."
@@ -1664,6 +1666,9 @@ _serverSettings:
userGeneratedContentsVisibilityForVisitor_description2: "Sunucu tarafından alınan uzak içerik dahil olmak üzere sunucudaki tüm içeriği koşulsuz olarak İnternet'e yayınlamak risklidir. Bu, içeriğin dağıtılmış yapısından haberdar olmayan misafirler için özellikle önemlidir, çünkü onlar yanlışlıkla uzak içeriğin bile sunucudaki kullanıcılar tarafından oluşturulan içerik olduğunu düşünebilirler."
restartServerSetupWizardConfirm_title: "Sunucu kurulum sihirbazını yeniden başlatmak ister misin?"
restartServerSetupWizardConfirm_text: "Bazı mevcut ayarlar sıfırlanacaktır."
entrancePageStyle: "Giriş sayfası stili"
showTimelineForVisitor: "Panoyu göster"
showActivitiesForVisitor: "Aktiviteleri göster"
_userGeneratedContentsVisibilityForVisitor:
all: "Her şey halka açıktır."
localOnly: "Yalnızca yerel içerik yayınlanır, uzak içerik gizli tutulur."
@@ -1872,7 +1877,7 @@ _achievements:
title: "Öz Referans"
description: "Kendi notunuzu alıntı yapın"
_htl20npm:
title: "Akış Zaman Çizelgesi"
title: "Akış Panosu"
description: "Ev zaman çizelgenizin hızı 20 npm'yi (dakika başına not sayısı) aşıyor mu?"
_viewInstanceChart:
title: "Analist"
@@ -1961,7 +1966,7 @@ _role:
asBadge: "Rozet olarak göster"
descriptionOfAsBadge: "This role's icon will be displayed next to the username of users with this role if turned on."
isExplorable: "Rolü keşfedilebilir hale getir"
descriptionOfIsExplorable: "Bu rolün zaman çizelgesi ve bu role sahip kullanıcıların listesi, etkinleştirilirse kamuya açık hale getirilecek."
descriptionOfIsExplorable: "Bu rolün panosu ve bu role sahip kullanıcıların listesi, etkinleştirilirse kamuya açık hale getirilecek."
displayOrder: "Pozisyon"
descriptionOfDisplayOrder: "Sayı ne kadar yüksekse, UI pozisyonu da o kadar yüksek olur."
preserveAssignmentOnMoveAccount: "Geçiş sırasında rol atamalarını koruyun"
@@ -1975,7 +1980,7 @@ _role:
high: "Yüksek"
_options:
gtlAvailable: "Global Pano'yu görüntüleyebilir"
ltlAvailable: "Yerel zaman çizelgesini görüntüleyebilir"
ltlAvailable: "Yerel panoyu görüntüleyebilir"
canPublicNote: "Halka açık notlar gönderebilir"
mentionMax: "Bir notta maksimum bahsetme sayısı"
canInvite: "Sunucu davet kodları oluşturabilir"
@@ -2273,6 +2278,7 @@ _time:
minute: "Dakika(lar)"
hour: "Saat(ler)"
day: "Gün(ler)"
month: "Ay"
_2fa:
alreadyRegistered: "2fa kimlik doğrulama cihazını zaten kaydettin."
registerTOTP: "Kimlik doğrulama uygulamasını kaydet"
@@ -2478,8 +2484,8 @@ _poll:
_visibility:
public: "Halka açık"
publicDescription: "Notunuz tüm kullanıcılar tarafından görülebilir olacaktır."
home: "Ana sayfa"
homeDescription: "Yalnızca ana zaman çizelgesine gönder"
home: "Pano"
homeDescription: "Yalnızca ana panoya gönder"
followers: "Takipçiler"
followersDescription: "Sadece takipçilerine görünür hale getir"
specified: "Doğrudan"
@@ -2526,7 +2532,7 @@ _exportOrImport:
userLists: "Kullanıcı listeleri"
excludeMutingUsers: "Sessize alınan kullanıcıları hariç tut"
excludeInactiveUsers: "Etkin olmayan kullanıcıları hariç tut"
withReplies: "İçe aktarılan kullanıcıların yanıtlarını zaman çizelgesine dahil edin"
withReplies: "İçe aktarılan kullanıcıların yanıtlarını panoya dahil edin"
_charts:
federation: "Federasyon"
apRequest: "Talepler"
@@ -2554,7 +2560,7 @@ _instanceCharts:
files: "Dosya sayısındaki fark"
filesTotal: "Toplam dosya sayısı"
_timelines:
home: "Ana Sayfa"
home: "Pano"
local: "Yerel"
social: "Sosyal"
global: "Global"
@@ -2672,7 +2678,7 @@ _notification:
chatRoomInvitationReceived: "Sohbet odasına davet edildi"
achievementEarned: "Başarı kilidi açıldı"
exportCompleted: "İhracat işlemi tamamlandı."
login: "Giriş Yap"
login: "Oturum Aç"
createToken: "Erişim jetonu oluştur"
test: "Bildirim testi"
app: "Bağlı uygulamalardan gelen bildirimler"
@@ -2709,7 +2715,7 @@ _deck:
main: "Ana"
widgets: "Widget'lar"
notifications: "Bildirimler"
tl: "Ana Sayfa"
tl: "Pano"
antenna: "Antenler"
list: "Liste"
channel: "Kanal"
@@ -2920,7 +2926,7 @@ _reversi:
freeMatch: "Ücretsiz Eşleştirme"
lookingForPlayer: "Rakip aranıyor..."
gameCanceled: "Oyun iptal edildi."
shareToTlTheGameWhenStart: "Oyun başlatıldığında zaman çizelgesinde paylaş"
shareToTlTheGameWhenStart: "Oyun başlatıldığında panoda paylaş"
iStartedAGame: "Oyun başladı! #MisskeyReversi"
opponentHasSettingsChanged: "Rakip ayarlarını değiştirmiş."
allowIrregularRules: "Düzensiz kurallar (tamamen ücretsiz)"
@@ -3148,7 +3154,7 @@ _clientPerformanceIssueTip:
_clip:
tip: "Klip, notları gruplandırmanıza olanak tanıyan bir özelliktir."
_userLists:
tip: "Listeler, oluşturulurken belirttiğin herhangi bir kullanıcıyı içerebilir. Oluşturulan liste, yalnızca belirtilen kullanıcıları gösteren bir zaman çizelgesi olarak görüntülenebilir."
tip: "Listeler, oluşturulurken belirttiğin herhangi bir kullanıcıyı içerebilir. Oluşturulan liste, yalnızca belirtilen kullanıcıları gösteren bir pano olarak görüntülenebilir."
watermark: "Filigran"
defaultPreset: "Varsayılan Ön Ayar"
_watermarkEditor:
-1
View File
@@ -1196,7 +1196,6 @@ showAvatarDecorations: "Hiển thị trang trí ảnh đại diện"
releaseToRefresh: "Thả để làm mới"
refreshing: "Đang làm mới"
pullDownToRefresh: "Kéo xuống để làm mới"
signupPendingError: "Đã xảy ra sự cố khi xác minh địa chỉ email của bạn. Liên kết có thể đã hết hạn."
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
decorate: "Trang trí"
lastNDays: "{n} ngày trước"
+2 -2
View File
@@ -1245,7 +1245,7 @@ releaseToRefresh: "松开以刷新"
refreshing: "刷新中"
pullDownToRefresh: "下拉以刷新"
useGroupedNotifications: "分组显示通知"
signupPendingError: "确认电子邮件时出现错误。链接可能已过期。"
emailVerificationFailedError: "确认电子邮件时出现错误。链接可能已过期。"
cwNotationRequired: "在启用「隐藏内容」时必须输入注释"
doReaction: "回应"
code: "代码"
@@ -1668,7 +1668,7 @@ _serverSettings:
restartServerSetupWizardConfirm_text: "现有的部分设定将重置。"
entrancePageStyle: "入口页面样式"
showTimelineForVisitor: "显示时间线"
showActivityiesForVisitor: "显示活动"
showActivitiesForVisitor: "显示活动"
_userGeneratedContentsVisibilityForVisitor:
all: "全部公开"
localOnly: "仅公开本地内容,隐藏远程内容"
+2 -2
View File
@@ -1245,7 +1245,7 @@ releaseToRefresh: "放開以更新內容"
refreshing: "載入更新中"
pullDownToRefresh: "往下拉來更新內容"
useGroupedNotifications: "分組顯示通知訊息"
signupPendingError: "驗證您的電子郵件地址時出現問題。連結可能已過期。"
emailVerificationFailedError: "驗證您的電子郵件地址時出現問題。連結可能已過期。"
cwNotationRequired: "如果開啟「隱藏內容」,則需要註解說明。"
doReaction: "做出反應"
code: "程式碼"
@@ -1668,7 +1668,7 @@ _serverSettings:
restartServerSetupWizardConfirm_text: "當前的部分設定將會被重設。"
entrancePageStyle: "入口頁面的樣式"
showTimelineForVisitor: "顯示時間軸"
showActivityiesForVisitor: "顯示活動"
showActivitiesForVisitor: "顯示活動"
_userGeneratedContentsVisibilityForVisitor:
all: "全部公開\n"
localOnly: "僅公開本地內容,遠端內容則不公開\n"
+12 -11
View File
@@ -1,12 +1,12 @@
{
"name": "misskey",
"version": "2025.8.0-beta.2",
"version": "2025.9.0",
"codename": "nasubi",
"repository": {
"type": "git",
"url": "https://github.com/misskey-dev/misskey.git"
},
"packageManager": "pnpm@10.14.0",
"packageManager": "pnpm@10.15.1",
"workspaces": [
"packages/frontend-shared",
"packages/frontend",
@@ -53,8 +53,8 @@
"lodash": "4.17.21"
},
"dependencies": {
"cssnano": "7.1.0",
"esbuild": "0.25.8",
"cssnano": "7.1.1",
"esbuild": "0.25.9",
"execa": "9.6.0",
"fast-glob": "3.3.3",
"glob": "11.0.3",
@@ -62,21 +62,22 @@
"js-yaml": "4.1.0",
"postcss": "8.5.6",
"tar": "7.4.3",
"terser": "5.43.1",
"terser": "5.44.0",
"typescript": "5.9.2"
},
"devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.17.1",
"@typescript-eslint/eslint-plugin": "8.39.0",
"@typescript-eslint/parser": "8.39.0",
"@types/js-yaml": "4.0.9",
"@types/node": "22.18.1",
"@typescript-eslint/eslint-plugin": "8.42.0",
"@typescript-eslint/parser": "8.42.0",
"cross-env": "7.0.3",
"cypress": "14.5.4",
"eslint": "9.33.0",
"eslint": "9.35.0",
"globals": "16.3.0",
"ncp": "2.0.0",
"pnpm": "10.14.0",
"start-server-and-test": "2.0.13"
"pnpm": "10.15.1",
"start-server-and-test": "2.1.0"
},
"optionalDependencies": {
"@tensorflow/tfjs-core": "4.22.0"
@@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class NonCascadingPageEyeCatching1756062689648 {
name = 'NonCascadingPageEyeCatching1756062689648'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa"`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "page" DROP CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa"`);
await queryRunner.query(`ALTER TABLE "page" ADD CONSTRAINT "FK_a9ca79ad939bf06066b81c9d3aa" FOREIGN KEY ("eyeCatchingImageId") REFERENCES "drive_file"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
}
@@ -0,0 +1,16 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class SensitiveAd1757823175259 {
name = 'SensitiveAd1757823175259'
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "ad" ADD "isSensitive" boolean NOT NULL DEFAULT false`);
}
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "ad" DROP COLUMN "isSensitive"`);
}
}
+31 -31
View File
@@ -39,17 +39,17 @@
},
"optionalDependencies": {
"@swc/core-android-arm64": "1.3.11",
"@swc/core-darwin-arm64": "1.13.3",
"@swc/core-darwin-x64": "1.13.3",
"@swc/core-darwin-arm64": "1.13.5",
"@swc/core-darwin-x64": "1.13.5",
"@swc/core-freebsd-x64": "1.3.11",
"@swc/core-linux-arm-gnueabihf": "1.13.3",
"@swc/core-linux-arm64-gnu": "1.13.3",
"@swc/core-linux-arm64-musl": "1.13.3",
"@swc/core-linux-x64-gnu": "1.13.3",
"@swc/core-linux-x64-musl": "1.13.3",
"@swc/core-win32-arm64-msvc": "1.13.3",
"@swc/core-win32-ia32-msvc": "1.13.3",
"@swc/core-win32-x64-msvc": "1.13.3",
"@swc/core-linux-arm-gnueabihf": "1.13.5",
"@swc/core-linux-arm64-gnu": "1.13.5",
"@swc/core-linux-arm64-musl": "1.13.5",
"@swc/core-linux-x64-gnu": "1.13.5",
"@swc/core-linux-x64-musl": "1.13.5",
"@swc/core-win32-arm64-msvc": "1.13.5",
"@swc/core-win32-ia32-msvc": "1.13.5",
"@swc/core-win32-x64-msvc": "1.13.5",
"@tensorflow/tfjs": "4.22.0",
"@tensorflow/tfjs-node": "4.22.0",
"bufferutil": "4.0.9",
@@ -69,20 +69,20 @@
"utf-8-validate": "6.0.5"
},
"dependencies": {
"@aws-sdk/client-s3": "3.864.0",
"@aws-sdk/lib-storage": "3.864.0",
"@aws-sdk/client-s3": "3.883.0",
"@aws-sdk/lib-storage": "3.883.0",
"@discordapp/twemoji": "16.0.1",
"@fastify/accepts": "5.0.2",
"@fastify/cookie": "11.0.2",
"@fastify/cors": "10.1.0",
"@fastify/express": "4.0.2",
"@fastify/http-proxy": "10.0.2",
"@fastify/multipart": "9.0.3",
"@fastify/multipart": "9.2.1",
"@fastify/static": "8.2.0",
"@fastify/view": "10.0.2",
"@misskey-dev/sharp-read-bmp": "1.2.0",
"@misskey-dev/summaly": "5.2.3",
"@napi-rs/canvas": "0.1.77",
"@napi-rs/canvas": "0.1.79",
"@nestjs/common": "11.1.6",
"@nestjs/core": "11.1.6",
"@nestjs/testing": "11.1.6",
@@ -93,7 +93,7 @@
"@sinonjs/fake-timers": "11.3.1",
"@smithy/node-http-handler": "2.5.0",
"@swc/cli": "0.7.8",
"@swc/core": "1.13.3",
"@swc/core": "1.13.5",
"@twemoji/parser": "16.0.0",
"@types/redis-info": "3.0.3",
"accepts": "1.3.8",
@@ -103,10 +103,10 @@
"bcryptjs": "2.4.3",
"blurhash": "2.0.5",
"body-parser": "1.20.3",
"bullmq": "5.56.9",
"bullmq": "5.58.5",
"cacheable-lookup": "7.0.0",
"cbor": "9.0.2",
"chalk": "5.5.0",
"chalk": "5.6.0",
"chalk-template": "1.1.0",
"chokidar": "4.0.3",
"cli-highlight": "2.1.11",
@@ -114,13 +114,13 @@
"content-disposition": "0.5.4",
"date-fns": "2.30.0",
"deep-email-validator": "0.1.21",
"fastify": "5.4.0",
"fastify": "5.6.0",
"fastify-raw-body": "5.0.0",
"feed": "4.2.2",
"file-type": "19.6.0",
"fluent-ffmpeg": "2.1.3",
"form-data": "4.0.4",
"got": "14.4.7",
"got": "14.4.8",
"happy-dom": "16.8.1",
"hpagent": "1.2.0",
"htmlescape": "1.1.1",
@@ -135,13 +135,13 @@
"jsonld": "8.3.3",
"jsrsasign": "11.1.0",
"juice": "11.0.1",
"meilisearch": "0.51.0",
"meilisearch": "0.52.0",
"mfm-js": "0.25.0",
"microformats-parser": "2.0.4",
"mime-types": "2.1.35",
"misskey-js": "workspace:*",
"misskey-reversi": "workspace:*",
"ms": "3.0.0-canary.1",
"ms": "3.0.0-canary.202508261828",
"nanoid": "5.1.5",
"nested-property": "4.0.0",
"node-fetch": "3.3.2",
@@ -151,7 +151,7 @@
"oauth2orize": "1.12.0",
"oauth2orize-pkce": "0.1.2",
"os-utils": "0.0.14",
"otpauth": "9.4.0",
"otpauth": "9.4.1",
"parse5": "7.3.0",
"pg": "8.16.3",
"pkce-challenge": "4.1.0",
@@ -175,12 +175,12 @@
"slacc": "0.0.10",
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"systeminformation": "5.27.7",
"systeminformation": "5.27.8",
"tinycolor2": "1.6.0",
"tmp": "0.2.4",
"tmp": "0.2.5",
"tsc-alias": "1.8.16",
"tsconfig-paths": "4.2.0",
"typeorm": "0.3.25",
"typeorm": "0.3.26",
"typescript": "5.9.2",
"ulid": "2.4.0",
"vary": "1.1.2",
@@ -191,7 +191,7 @@
"devDependencies": {
"@jest/globals": "29.7.0",
"@nestjs/platform-express": "10.4.20",
"@sentry/vue": "9.45.0",
"@sentry/vue": "9.46.0",
"@simplewebauthn/types": "12.0.0",
"@swc/jest": "0.2.39",
"@types/accepts": "1.3.7",
@@ -210,8 +210,8 @@
"@types/jsrsasign": "10.5.15",
"@types/mime-types": "2.1.4",
"@types/ms": "0.7.34",
"@types/node": "22.17.1",
"@types/nodemailer": "6.4.17",
"@types/node": "22.18.1",
"@types/nodemailer": "6.4.19",
"@types/oauth": "0.9.6",
"@types/oauth2orize": "1.11.5",
"@types/oauth2orize-pkce": "0.1.2",
@@ -222,7 +222,7 @@
"@types/ratelimiter": "3.4.6",
"@types/rename": "1.0.7",
"@types/sanitize-html": "2.16.0",
"@types/semver": "7.7.0",
"@types/semver": "7.7.1",
"@types/simple-oauth2": "5.0.7",
"@types/sinonjs__fake-timers": "8.1.5",
"@types/supertest": "6.0.3",
@@ -231,8 +231,8 @@
"@types/vary": "1.1.3",
"@types/web-push": "3.6.4",
"@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.39.0",
"@typescript-eslint/parser": "8.39.0",
"@typescript-eslint/eslint-plugin": "8.42.0",
"@typescript-eslint/parser": "8.42.0",
"aws-sdk-client-mock": "4.1.0",
"cross-env": "7.0.3",
"eslint-plugin-import": "2.32.0",
+2 -2
View File
@@ -29,7 +29,7 @@ export class AiService {
}
@bindThis
public async detectSensitive(path: string): Promise<nsfw.PredictionType[] | null> {
public async detectSensitive(source: string | Buffer): Promise<nsfw.PredictionType[] | null> {
try {
if (isSupportedCpu === undefined) {
isSupportedCpu = await this.computeIsSupportedCpu();
@@ -51,7 +51,7 @@ export class AiService {
});
}
const buffer = await fs.promises.readFile(path);
const buffer = source instanceof Buffer ? source : await fs.promises.readFile(source);
const image = await tf.node.decodeImage(buffer, 3) as any;
try {
const predictions = await this.model.classify(image);
+19 -10
View File
@@ -21,6 +21,7 @@ import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';
import { bindThis } from '@/decorators.js';
import type { PredictionType } from 'nsfwjs';
import { isMimeImage } from '@/misc/is-mime-image.js';
export type FileInfo = {
size: number;
@@ -204,16 +205,7 @@ export class FileInfoService {
return [sensitive, porn];
}
if ([
'image/jpeg',
'image/png',
'image/webp',
].includes(mime)) {
const result = await this.aiService.detectSensitive(source);
if (result) {
[sensitive, porn] = judgePrediction(result);
}
} else if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
if (analyzeVideo && (mime === 'image/apng' || mime.startsWith('video/'))) {
const [outDir, disposeOutDir] = await createTempDir();
try {
const command = FFmpeg()
@@ -281,6 +273,23 @@ export class FileInfoService {
} finally {
disposeOutDir();
}
} else if (isMimeImage(mime, 'sharp-convertible-image-with-bmp')) {
/*
* tfjs-node は限られた画像形式しか受け付けないため、sharp で PNG に変換する
* せっかくなので内部処理で使われる最大サイズの299x299に事前にリサイズする
*/
const png = await (await sharpBmp(source, mime))
.resize(299, 299, {
withoutEnlargement: false,
})
.rotate()
.flatten({ background: { r: 119, g: 119, b: 119 } }) // 透過部分を18%グレーで塗りつぶす
.png()
.toBuffer();
const result = await this.aiService.detectSensitive(png);
if (result) {
[sensitive, porn] = judgePrediction(result);
}
}
return [sensitive, porn];
+6 -6
View File
@@ -756,8 +756,8 @@ export class QueueService {
@bindThis
public async queueRetryJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
const job = await queue.getJob(jobId);
if (job != null) {
if (job.finishedOn != null) {
await job.retry();
} else {
@@ -769,8 +769,8 @@ export class QueueService {
@bindThis
public async queueRemoveJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
const job = await queue.getJob(jobId);
if (job != null) {
await job.remove();
}
}
@@ -803,8 +803,8 @@ export class QueueService {
@bindThis
public async queueGetJob(queueType: typeof QUEUE_TYPES[number], jobId: string) {
const queue = this.getQueue(queueType);
const job: Bull.Job | null = await queue.getJob(jobId);
if (job) {
const job = await queue.getJob(jobId);
if (job != null) {
return this.packJobData(job);
} else {
throw new Error(`Job not found: ${jobId}`);
+7 -5
View File
@@ -31,6 +31,7 @@ import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
import { NotificationService } from '@/core/NotificationService.js';
import type { OnApplicationShutdown, OnModuleInit } from '@nestjs/common';
// misskey-js の rolePolicies と同期すべし
export type RolePolicies = {
gtlAvailable: boolean;
ltlAvailable: boolean;
@@ -100,14 +101,15 @@ export const DEFAULT_POLICIES: RolePolicies = {
userEachUserListsLimit: 50,
rateLimitFactor: 1,
avatarDecorationLimit: 1,
canImportAntennas: true,
canImportBlocking: true,
canImportFollowing: true,
canImportMuting: true,
canImportUserLists: true,
canImportAntennas: false,
canImportBlocking: false,
canImportFollowing: false,
canImportMuting: false,
canImportUserLists: false,
chatAvailability: 'available',
uploadableFileTypes: [
'text/plain',
'text/csv',
'application/json',
'image/*',
'video/*',
@@ -244,7 +244,6 @@ export class WebhookTestService {
case 'reaction':
return;
default: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _exhaustiveAssertion: never = params.type;
return;
}
@@ -327,7 +326,6 @@ export class WebhookTestService {
break;
}
default: {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _exhaustiveAssertion: never = params.type;
return;
}
@@ -412,7 +410,7 @@ export class WebhookTestService {
name: user.name,
username: user.username,
host: user.host,
avatarUrl: user.avatarId == null ? null : user.avatarUrl,
avatarUrl: (user.avatarId == null ? null : user.avatarUrl) ?? '',
avatarBlurhash: user.avatarId == null ? null : user.avatarBlurhash,
avatarDecorations: user.avatarDecorations.map(it => ({
id: it.id,
@@ -54,12 +54,13 @@ export class ChatEntityService {
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
const reactions: { user: Packed<'UserLite'>; reaction: string; }[] = [];
// userは削除されている可能性があるのでnull許容
const reactions: { user: Packed<'UserLite'> | null; reaction: string; }[] = [];
for (const record of message.reactions) {
const [userId, reaction] = record.split('/');
reactions.push({
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId),
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId).catch(() => null),
reaction,
});
}
@@ -76,7 +77,7 @@ export class ChatEntityService {
toRoom: message.toRoomId ? (packedRooms?.get(message.toRoomId) ?? await this.packRoom(message.toRoom ?? message.toRoomId, me)) : undefined,
fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions,
reactions: reactions.filter((r): r is { user: Packed<'UserLite'>; reaction: string; } => r.user != null),
};
}
@@ -108,6 +109,7 @@ export class ChatEntityService {
}
}
// TODO: packedUsersに削除されたユーザーもnullとして含める
const [packedUsers, packedFiles, packedRooms] = await Promise.all([
this.userEntityService.packMany(users, me)
.then(users => new Map(users.map(u => [u.id, u]))),
@@ -183,12 +185,13 @@ export class ChatEntityService {
const message = typeof src === 'object' ? src : await this.chatMessagesRepository.findOneByOrFail({ id: src });
const reactions: { user: Packed<'UserLite'>; reaction: string; }[] = [];
// userは削除されている可能性があるのでnull許容
const reactions: { user: Packed<'UserLite'> | null; reaction: string; }[] = [];
for (const record of message.reactions) {
const [userId, reaction] = record.split('/');
reactions.push({
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId),
user: packedUsers?.get(userId) ?? await this.userEntityService.pack(userId).catch(() => null),
reaction,
});
}
@@ -202,7 +205,7 @@ export class ChatEntityService {
toRoomId: message.toRoomId!,
fileId: message.fileId,
file: message.fileId ? (packedFiles?.get(message.fileId) ?? await this.driveFileEntityService.pack(message.file ?? message.fileId)) : null,
reactions,
reactions: reactions.filter((r): r is { user: Packed<'UserLite'>; reaction: string; } => r.user != null),
};
}
@@ -117,6 +117,7 @@ export class MetaEntityService {
ratio: ad.ratio,
imageUrl: ad.imageUrl,
dayOfWeek: ad.dayOfWeek,
isSensitive: ad.isSensitive ? true : undefined,
})),
notesPerOneAd: instance.notesPerOneAd,
enableEmail: instance.enableEmail,
@@ -49,15 +49,12 @@ export class NoteReactionEntityService implements OnModuleInit {
public async pack(
src: MiNoteReaction['id'] | MiNoteReaction,
me?: { id: MiUser['id'] } | null | undefined,
options?: {
withNote: boolean;
},
options?: object,
hints?: {
packedUser?: Packed<'UserLite'>
},
): Promise<Packed<'NoteReaction'>> {
const opts = Object.assign({
withNote: false,
}, options);
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
@@ -67,9 +64,6 @@ export class NoteReactionEntityService implements OnModuleInit {
createdAt: this.idService.parse(reaction.id).date.toISOString(),
user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
type: this.reactionService.convertLegacyReaction(reaction.reaction),
...(opts.withNote ? {
note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
} : {}),
};
}
@@ -77,16 +71,50 @@ export class NoteReactionEntityService implements OnModuleInit {
public async packMany(
reactions: MiNoteReaction[],
me?: { id: MiUser['id'] } | null | undefined,
options?: {
withNote: boolean;
},
options?: object,
): Promise<Packed<'NoteReaction'>[]> {
const opts = Object.assign({
withNote: false,
}, options);
const _users = reactions.map(({ user, userId }) => user ?? userId);
const _userMap = await this.userEntityService.packMany(_users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(reactions.map(reaction => this.pack(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
}
@bindThis
public async packWithNote(
src: MiNoteReaction['id'] | MiNoteReaction,
me?: { id: MiUser['id'] } | null | undefined,
options?: object,
hints?: {
packedUser?: Packed<'UserLite'>
},
): Promise<Packed<'NoteReactionWithNote'>> {
const opts = Object.assign({
}, options);
const reaction = typeof src === 'object' ? src : await this.noteReactionsRepository.findOneByOrFail({ id: src });
return {
id: reaction.id,
createdAt: this.idService.parse(reaction.id).date.toISOString(),
user: hints?.packedUser ?? await this.userEntityService.pack(reaction.user ?? reaction.userId, me),
type: this.reactionService.convertLegacyReaction(reaction.reaction),
note: await this.noteEntityService.pack(reaction.note ?? reaction.noteId, me),
};
}
@bindThis
public async packManyWithNote(
reactions: MiNoteReaction[],
me?: { id: MiUser['id'] } | null | undefined,
options?: object,
): Promise<Packed<'NoteReactionWithNote'>[]> {
const opts = Object.assign({
}, options);
const _users = reactions.map(({ user, userId }) => user ?? userId);
const _userMap = await this.userEntityService.packMany(_users, me)
.then(users => new Map(users.map(u => [u.id, u])));
return Promise.all(reactions.map(reaction => this.packWithNote(reaction, me, opts, { packedUser: _userMap.get(reaction.userId) })));
}
}
@@ -471,8 +471,8 @@ export class UserEntityService implements OnModuleInit {
(profile.followersVisibility === 'followers') && (relation && relation.isFollowing) ? user.followersCount :
null;
const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : null;
const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : null;
const isModerator = isMe && isDetailed ? this.roleService.isModerator(user) : undefined;
const isAdmin = isMe && isDetailed ? this.roleService.isAdministrator(user) : undefined;
const unreadAnnouncements = isMe && isDetailed ?
(await this.announcementService.getUnreadAnnouncements(user)).map((announcement) => ({
createdAt: this.idService.parse(announcement.id).date.toISOString(),
@@ -481,6 +481,7 @@ export class UserEntityService implements OnModuleInit {
const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null;
// TODO: 例えば avatarUrl: true など間違った型を設定しても型エラーにならないのをどうにかする(ジェネリクス使わない方法で実装するしかなさそう?)
const packed = {
id: user.id,
name: user.name,
+4 -1
View File
@@ -22,7 +22,7 @@ import { packedFollowingSchema } from '@/models/json-schema/following.js';
import { packedMutingSchema } from '@/models/json-schema/muting.js';
import { packedRenoteMutingSchema } from '@/models/json-schema/renote-muting.js';
import { packedBlockingSchema } from '@/models/json-schema/blocking.js';
import { packedNoteReactionSchema } from '@/models/json-schema/note-reaction.js';
import { packedNoteReactionSchema, packedNoteReactionWithNoteSchema } from '@/models/json-schema/note-reaction.js';
import { packedHashtagSchema } from '@/models/json-schema/hashtag.js';
import { packedInviteCodeSchema } from '@/models/json-schema/invite-code.js';
import { packedPageBlockSchema, packedPageSchema } from '@/models/json-schema/page.js';
@@ -65,6 +65,7 @@ import {
packedMetaDetailedSchema,
packedMetaLiteSchema,
} from '@/models/json-schema/meta.js';
import { packedUserWebhookSchema } from '@/models/json-schema/user-webhook.js';
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js';
@@ -92,6 +93,7 @@ export const refs = {
Note: packedNoteSchema,
NoteDraft: packedNoteDraftSchema,
NoteReaction: packedNoteReactionSchema,
NoteReactionWithNote: packedNoteReactionWithNoteSchema,
NoteFavorite: packedNoteFavoriteSchema,
Notification: packedNotificationSchema,
DriveFile: packedDriveFileSchema,
@@ -133,6 +135,7 @@ export const refs = {
MetaLite: packedMetaLiteSchema,
MetaDetailedOnly: packedMetaDetailedOnlySchema,
MetaDetailed: packedMetaDetailedSchema,
UserWebhook: packedUserWebhookSchema,
SystemWebhook: packedSystemWebhookSchema,
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
ChatMessage: packedChatMessageSchema,
+7
View File
@@ -54,10 +54,17 @@ export class MiAd {
length: 8192, nullable: false,
})
public memo: string;
@Column('integer', {
default: 0, nullable: false,
})
public dayOfWeek: number;
@Column('boolean', {
default: false,
})
public isSensitive: boolean;
constructor(data: Partial<MiAd>) {
if (data == null) return;
@@ -10,6 +10,7 @@ import { MiAccessToken } from './AccessToken.js';
import { MiRole } from './Role.js';
import { MiDriveFile } from './DriveFile.js';
// misskey-js の notificationTypes と同期すべし
export type MiNotification = {
type: 'note';
id: string;
+1 -1
View File
@@ -69,7 +69,7 @@ export class MiPage {
public eyeCatchingImageId: MiDriveFile['id'] | null;
@ManyToOne(type => MiDriveFile, {
onDelete: 'CASCADE',
onDelete: 'SET NULL',
})
@JoinColumn()
public eyeCatchingImage: MiDriveFile | null;
@@ -60,5 +60,10 @@ export const packedAdSchema = {
optional: false,
nullable: false,
},
isSensitive: {
type: 'boolean',
optional: false,
nullable: false,
},
},
} as const;
@@ -195,6 +195,10 @@ export const packedMetaLiteSchema = {
type: 'integer',
optional: false, nullable: false,
},
isSensitive: {
type: 'boolean',
optional: true, nullable: false,
},
},
},
},
@@ -10,7 +10,6 @@ export const packedNoteReactionSchema = {
type: 'string',
optional: false, nullable: false,
format: 'id',
example: 'xxxxxxxxxx',
},
createdAt: {
type: 'string',
@@ -28,3 +27,33 @@ export const packedNoteReactionSchema = {
},
},
} as const;
export const packedNoteReactionWithNoteSchema = {
type: 'object',
properties: {
id: {
type: 'string',
optional: false, nullable: false,
format: 'id',
},
createdAt: {
type: 'string',
optional: false, nullable: false,
format: 'date-time',
},
user: {
type: 'object',
optional: false, nullable: false,
ref: 'UserLite',
},
type: {
type: 'string',
optional: false, nullable: false,
},
note: {
type: 'object',
optional: false, nullable: false,
ref: 'Note',
},
},
} as const;
@@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { webhookEventTypes } from '@/models/Webhook.js';
export const packedUserWebhookSchema = {
type: 'object',
properties: {
id: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
userId: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
on: {
type: 'array',
items: {
type: 'string',
optional: false, nullable: false,
enum: webhookEventTypes,
},
},
url: {
type: 'string',
optional: false, nullable: false,
},
secret: {
type: 'string',
optional: false, nullable: false,
},
active: {
type: 'boolean',
optional: false, nullable: false,
},
latestSentAt: {
type: 'string',
format: 'date-time',
optional: false, nullable: true,
},
latestStatus: {
type: 'integer',
optional: false, nullable: true,
},
},
} as const;
@@ -65,7 +65,7 @@ export const packedUserLiteSchema = {
avatarUrl: {
type: 'string',
format: 'url',
nullable: true, optional: false,
nullable: false, optional: false,
},
avatarBlurhash: {
type: 'string',
@@ -465,11 +465,11 @@ export const packedMeDetailedOnlySchema = {
},
isModerator: {
type: 'boolean',
nullable: true, optional: false,
nullable: false, optional: false,
},
isAdmin: {
type: 'boolean',
nullable: true, optional: false,
nullable: false, optional: false,
},
injectFeaturedNote: {
type: 'boolean',
@@ -591,7 +591,7 @@ export const packedMeDetailedOnlySchema = {
},
mutedInstances: {
type: 'array',
nullable: true, optional: false,
nullable: false, optional: false,
items: {
type: 'string',
nullable: false, optional: false,
@@ -238,30 +238,6 @@ export class ServerService implements OnApplicationShutdown {
}
});
fastify.get<{ Params: { code: string } }>('/verify-email/:code', async (request, reply) => {
const profile = await this.userProfilesRepository.findOneBy({
emailVerifyCode: request.params.code,
});
if (profile != null) {
await this.userProfilesRepository.update({ userId: profile.userId }, {
emailVerified: true,
emailVerifyCode: null,
});
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
schema: 'MeDetailed',
includeSecrets: true,
}));
reply.code(200).send('Verification succeeded! メールアドレスの認証に成功しました。');
return;
} else {
reply.code(404).send('Verification failed. Please try again. メールアドレスの認証に失敗しました。もう一度お試しください');
return;
}
});
fastify.register(this.clientServerService.createServer);
this.streamingApiServerService.attach(fastify.server);
@@ -176,6 +176,17 @@ export class ApiServerService {
}
});
fastify.all('/clear-browser-cache', (request, reply) => {
if (['GET', 'POST'].includes(request.method)) {
reply.header('Clear-Site-Data', '"cache", "prefetchCache", "prerenderCache", "executionContexts"');
reply.code(204);
reply.send();
} else {
reply.code(405);
reply.send();
}
});
// Make sure any unknown path under /api returns HTTP 404 Not Found,
// because otherwise ClientServerService will return the base client HTML
// page with HTTP 200.
@@ -412,6 +412,7 @@ export * as 'users/search' from './endpoints/users/search.js';
export * as 'users/search-by-username-and-host' from './endpoints/users/search-by-username-and-host.js';
export * as 'users/show' from './endpoints/users/show.js';
export * as 'users/update-memo' from './endpoints/users/update-memo.js';
export * as 'verify-email' from './endpoints/verify-email.js';
export * as 'chat/messages/create-to-user' from './endpoints/chat/messages/create-to-user.js';
export * as 'chat/messages/create-to-room' from './endpoints/chat/messages/create-to-room.js';
export * as 'chat/messages/delete' from './endpoints/chat/messages/delete.js';
@@ -34,13 +34,22 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
ref: 'MeDetailed',
properties: {
token: {
type: 'string',
optional: false, nullable: false,
allOf: [
{
type: 'object',
ref: 'MeDetailed',
},
},
{
type: 'object',
optional: false, nullable: false,
properties: {
token: {
type: 'string',
optional: false, nullable: false,
},
},
}
],
},
} as const;
@@ -36,6 +36,7 @@ export const paramDef = {
startsAt: { type: 'integer' },
imageUrl: { type: 'string', minLength: 1 },
dayOfWeek: { type: 'integer' },
isSensitive: { type: 'boolean' },
},
required: ['url', 'memo', 'place', 'priority', 'ratio', 'expiresAt', 'startsAt', 'imageUrl', 'dayOfWeek'],
} as const;
@@ -55,6 +56,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: new Date(ps.expiresAt),
startsAt: new Date(ps.startsAt),
dayOfWeek: ps.dayOfWeek,
isSensitive: ps.isSensitive,
url: ps.url,
imageUrl: ps.imageUrl,
priority: ps.priority,
@@ -73,6 +75,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: ad.expiresAt.toISOString(),
startsAt: ad.startsAt.toISOString(),
dayOfWeek: ad.dayOfWeek,
isSensitive: ad.isSensitive,
url: ad.url,
imageUrl: ad.imageUrl,
priority: ad.priority,
@@ -63,6 +63,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: ad.expiresAt.toISOString(),
startsAt: ad.startsAt.toISOString(),
dayOfWeek: ad.dayOfWeek,
isSensitive: ad.isSensitive,
url: ad.url,
imageUrl: ad.imageUrl,
memo: ad.memo,
@@ -39,6 +39,7 @@ export const paramDef = {
expiresAt: { type: 'integer' },
startsAt: { type: 'integer' },
dayOfWeek: { type: 'integer' },
isSensitive: { type: 'boolean' },
},
required: ['id'],
} as const;
@@ -66,6 +67,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
expiresAt: ps.expiresAt ? new Date(ps.expiresAt) : undefined,
startsAt: ps.startsAt ? new Date(ps.startsAt) : undefined,
dayOfWeek: ps.dayOfWeek,
isSensitive: ps.isSensitive,
});
const updatedAd = await this.adsRepository.findOneByOrFail({ id: ad.id });
@@ -49,6 +49,34 @@ export const meta = {
type: 'string',
optional: false, nullable: false,
},
icon: {
type: 'string',
optional: false, nullable: true,
},
display: {
type: 'string',
optional: false, nullable: false,
},
isActive: {
type: 'boolean',
optional: false, nullable: false,
},
forExistingUsers: {
type: 'boolean',
optional: false, nullable: false,
},
silence: {
type: 'boolean',
optional: false, nullable: false,
},
needConfirmationToRead: {
type: 'boolean',
optional: false, nullable: false,
},
userId: {
type: 'string',
optional: false, nullable: true,
},
imageUrl: {
type: 'string',
optional: false, nullable: true,
@@ -157,6 +157,22 @@ export const meta = {
type: 'boolean',
optional: false, nullable: false,
},
maybeSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
maybePorn: {
type: 'boolean',
optional: false, nullable: false,
},
requestIp: {
type: 'string',
optional: false, nullable: true,
},
requestHeaders: {
type: 'object',
optional: false, nullable: true,
},
},
},
} as const;
@@ -223,10 +223,12 @@ export const meta = {
sensitiveMediaDetection: {
type: 'string',
optional: false, nullable: false,
enum: ['none', 'all', 'local', 'remote'],
},
sensitiveMediaDetectionSensitivity: {
type: 'string',
optional: false, nullable: false,
enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'],
},
setSensitiveFlagAutomatically: {
type: 'boolean',
@@ -473,6 +475,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
feedbackUrl: {
type: 'string',
optional: false, nullable: true,
},
summalyProxy: {
type: 'string',
optional: false, nullable: true,
@@ -5,6 +5,7 @@
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import { QueryService } from '@/core/QueryService.js';
import type { ClipsRepository } from '@/models/_.js';
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
import { DI } from '@/di-symbols.js';
@@ -29,7 +30,13 @@ export const meta = {
export const paramDef = {
type: 'object',
properties: {},
properties: {
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
sinceId: { type: 'string', format: 'misskey:id' },
untilId: { type: 'string', format: 'misskey:id' },
sinceDate: { type: 'integer' },
untilDate: { type: 'integer' },
},
required: [],
} as const;
@@ -39,12 +46,14 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
@Inject(DI.clipsRepository)
private clipsRepository: ClipsRepository,
private queryService: QueryService,
private clipEntityService: ClipEntityService,
) {
super(meta, paramDef, async (ps, me) => {
const clips = await this.clipsRepository.findBy({
userId: me.id,
});
const query = this.queryService.makePaginationQuery(this.clipsRepository.createQueryBuilder('clip'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
.andWhere('clip.userId = :userId', { userId: me.id });
const clips = await query.limit(ps.limit).getMany();
return await this.clipEntityService.packMany(clips, me);
});
@@ -73,8 +73,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
updatedAt: new Date(),
...Object.fromEntries(
Object.entries(ps).filter(
([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key)
)
([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key),
),
),
});
});
@@ -46,6 +46,14 @@ export const meta = {
type: 'string',
},
},
iconUrl: {
type: 'string',
optional: true, nullable: true,
},
description: {
type: 'string',
optional: true, nullable: true,
},
},
},
},
@@ -88,6 +96,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
createdAt: this.idService.parse(token.id).date.toISOString(),
lastUsedAt: token.lastUsedAt?.toISOString(),
permission: token.app ? token.app.permission : token.permission,
iconUrl: token.iconUrl,
description: token.description ?? token.app?.description ?? null,
})));
});
}
@@ -21,29 +21,7 @@ export const meta = {
type: 'array',
items: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'misskey:id',
},
userId: {
type: 'string',
format: 'misskey:id',
},
name: { type: 'string' },
on: {
type: 'array',
items: {
type: 'string',
enum: webhookEventTypes,
},
},
url: { type: 'string' },
secret: { type: 'string' },
active: { type: 'boolean' },
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
latestStatus: { type: 'integer', nullable: true },
},
ref: 'UserWebhook',
},
},
} as const;
@@ -65,19 +43,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
userId: me.id,
});
return webhooks.map(webhook => (
{
id: webhook.id,
userId: webhook.userId,
name: webhook.name,
on: webhook.on,
url: webhook.url,
secret: webhook.secret,
active: webhook.active,
latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null,
latestStatus: webhook.latestStatus,
}
));
return webhooks.map(webhook => ({
id: webhook.id,
userId: webhook.userId,
name: webhook.name,
on: webhook.on,
url: webhook.url,
secret: webhook.secret,
active: webhook.active,
latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null,
latestStatus: webhook.latestStatus,
}));
});
}
}
@@ -28,29 +28,7 @@ export const meta = {
res: {
type: 'object',
properties: {
id: {
type: 'string',
format: 'misskey:id',
},
userId: {
type: 'string',
format: 'misskey:id',
},
name: { type: 'string' },
on: {
type: 'array',
items: {
type: 'string',
enum: webhookEventTypes,
},
},
url: { type: 'string' },
secret: { type: 'string' },
active: { type: 'boolean' },
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
latestStatus: { type: 'integer', nullable: true },
},
ref: 'UserWebhook',
},
} as const;
@@ -91,6 +91,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
qb.orWhere(new Brackets(qb => {
qb.where('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
}));
}));
}
@@ -66,7 +66,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
.orWhere(':meIdAsList <@ note.visibleUserIds');
}))
// Avoid scanning primary key index
.orderBy('CONCAT(note.id)', 'DESC')
.orderBy('CONCAT(note.id)', (ps.sinceDate || ps.sinceId) ? 'ASC' : 'DESC')
.innerJoinAndSelect('note.user', 'user')
.leftJoinAndSelect('note.reply', 'reply')
.leftJoinAndSelect('note.renote', 'renote')
@@ -29,10 +29,16 @@ export const meta = {
id: '24fcbfc6-2e37-42b6-8388-c29b3861a08d',
},
signinRequired: {
message: 'Signin required.',
code: 'SIGNIN_REQUIRED',
id: '8e75455b-738c-471d-9f80-62693f33372e',
contentRestrictedByUser: {
message: 'Content restricted by user. Please sign in to view.',
code: 'CONTENT_RESTRICTED_BY_USER',
id: 'fbcc002d-37d9-4944-a6b0-d9e29f2d33ab',
},
contentRestrictedByServer: {
message: 'Content restricted by server settings. Please sign in to view.',
code: 'CONTENT_RESTRICTED_BY_SERVER',
id: '145f88d2-b03d-4087-8143-a78928883c4b',
},
},
} as const;
@@ -61,15 +67,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
});
if (note.user!.requireSigninToViewContents && me == null) {
throw new ApiError(meta.errors.signinRequired);
throw new ApiError(meta.errors.contentRestrictedByUser);
}
if (this.serverSettings.ugcVisibilityForVisitor === 'none' && me == null) {
throw new ApiError(meta.errors.signinRequired);
throw new ApiError(meta.errors.contentRestrictedByServer);
}
if (this.serverSettings.ugcVisibilityForVisitor === 'local' && note.userHost != null && me == null) {
throw new ApiError(meta.errors.signinRequired);
throw new ApiError(meta.errors.contentRestrictedByServer);
}
return await this.noteEntityService.pack(note, me, {
@@ -242,6 +242,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
}));
}));
}
@@ -223,6 +223,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
qb.orWhere(new Brackets(qb => {
qb.orWhere('note.text IS NOT NULL');
qb.orWhere('note.fileIds != \'{}\'');
qb.orWhere('0 < (SELECT COUNT(*) FROM poll WHERE poll."noteId" = note.id)');
}));
}));
}
@@ -22,7 +22,26 @@ export const meta = {
res: {
type: 'object',
optional: false, nullable: false,
ref: 'UserList',
allOf: [
{
type: 'object',
ref: 'UserList',
},
{
type: 'object',
optional: false, nullable: false,
properties: {
likedCount: {
type: 'number',
optional: true, nullable: false,
},
isLiked: {
type: 'boolean',
optional: true, nullable: false,
},
},
},
],
},
errors: {
@@ -28,7 +28,7 @@ export const meta = {
items: {
type: 'object',
optional: false, nullable: false,
ref: 'NoteReaction',
ref: 'NoteReactionWithNote',
},
},
@@ -120,7 +120,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
return true;
});
return await this.noteReactionEntityService.packMany(reactions, me, { withNote: true });
return await this.noteReactionEntityService.packManyWithNote(reactions, me);
});
}
}
@@ -0,0 +1,66 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Inject, Injectable } from '@nestjs/common';
import { Endpoint } from '@/server/api/endpoint-base.js';
import type { UserProfilesRepository } from '@/models/_.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { DI } from '@/di-symbols.js';
import { GlobalEventService } from '@/core/GlobalEventService.js';
import { ApiError } from '../error.js';
export const meta = {
requireCredential: false,
tags: ['account'],
errors: {
noSuchCode: {
message: 'No such code.',
code: 'NO_SUCH_CODE',
id: '97c1f576-e4b8-4b8a-a6dc-9cb65e7f6f85',
},
},
} as const;
export const paramDef = {
type: 'object',
properties: {
code: { type: 'string' },
},
required: ['code'],
} as const;
@Injectable()
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
constructor(
@Inject(DI.userProfilesRepository)
private userProfilesRepository: UserProfilesRepository,
private userEntityService: UserEntityService,
private globalEventService: GlobalEventService,
) {
super(meta, paramDef, async (ps) => {
const profile = await this.userProfilesRepository.findOneBy({
emailVerifyCode: ps.code,
});
if (profile == null) {
throw new ApiError(meta.errors.noSuchCode);
}
await this.userProfilesRepository.update({ userId: profile.userId }, {
emailVerified: true,
emailVerifyCode: null,
});
this.globalEventService.publishMainStream(profile.userId, 'meUpdated', await this.userEntityService.pack(profile.userId, { id: profile.userId }, {
schema: 'MeDetailed',
includeSecrets: true,
}));
});
}
}
@@ -201,6 +201,8 @@ export class ClientServerService {
@bindThis
public createServer(fastify: FastifyInstance, options: FastifyPluginOptions, done: (err?: Error) => void) {
const configUrl = new URL(this.config.url);
fastify.register(fastifyView, {
root: _dirname + '/views',
engine: {
@@ -239,7 +241,6 @@ export class ClientServerService {
done();
});
} else {
const configUrl = new URL(this.config.url);
const urlOriginWithoutPort = configUrl.origin.replace(/:\d+$/, '');
const port = (process.env.VITE_PORT ?? '5173');
@@ -887,6 +888,22 @@ export class ClientServerService {
[, ...target.split('/').filter(x => x), ...source.split('/').filter(x => x).splice(depth)].join('/');
fastify.get('/flush', async (request, reply) => {
let sendHeader = true;
if (request.headers['origin']) {
const originURL = new URL(request.headers['origin']);
if (originURL.protocol !== 'https:') { // Clear-Site-Data only supports https
sendHeader = false;
}
if (originURL.host !== configUrl.host) {
sendHeader = false;
}
}
if (sendHeader) {
reply.header('Clear-Site-Data', '"*"');
}
reply.header('Set-Cookie', 'http-flush-failed=1; Path=/flush; Max-Age=60');
return await reply.view('flush');
});
+34 -30
View File
@@ -6,41 +6,45 @@ html
const msg = document.getElementById('msg');
const successText = `\nSuccess Flush! <a href="/">Back to Misskey</a>\n成功しました。<a href="/">Misskeyを開き直してください。</a>`;
message('Start flushing.');
if (!document.cookie) {
message('Your site data is fully cleared by your browser.');
message(successText);
} else {
message('Your browser does not support Clear-Site-Data header. Start opportunistic flushing.');
(async function() {
try {
localStorage.clear();
message('localStorage cleared.');
(async function() {
try {
localStorage.clear();
message('localStorage cleared.');
const idbPromises = ['MisskeyClient', 'keyval-store'].map((name, i, arr) => new Promise((res, rej) => {
const delidb = indexedDB.deleteDatabase(name);
delidb.onsuccess = () => res(message(`indexedDB "${name}" cleared. (${i + 1}/${arr.length})`));
delidb.onerror = e => rej(e)
}));
const idbPromises = ['MisskeyClient', 'keyval-store'].map((name, i, arr) => new Promise((res, rej) => {
const delidb = indexedDB.deleteDatabase(name);
delidb.onsuccess = () => res(message(`indexedDB "${name}" cleared. (${i + 1}/${arr.length})`));
delidb.onerror = e => rej(e)
}));
await Promise.all(idbPromises);
await Promise.all(idbPromises);
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage('clear');
await navigator.serviceWorker.getRegistrations()
.then(registrations => {
return Promise.all(registrations.map(registration => registration.unregister()));
})
.catch(e => { throw new Error(e) });
}
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage('clear');
await navigator.serviceWorker.getRegistrations()
.then(registrations => {
return Promise.all(registrations.map(registration => registration.unregister()));
})
.catch(e => { throw new Error(e) });
message(successText);
} catch (e) {
message(`\n${e}\n\nFlush Failed. <a href="/flush">Please retry.</a>\n失敗しました。<a href="/flush">もう一度試してみてください。</a>`);
message(`\nIf you retry more than 3 times, try manually clearing the browser cache or contact to instance admin.\n3回以上試しても失敗する場合、ブラウザのキャッシュを手動で消去し、それでもだめならインスタンス管理者に連絡してみてください。\n`)
console.error(e);
setTimeout(() => {
location = '/';
}, 10000)
}
message(successText);
} catch (e) {
message(`\n${e}\n\nFlush Failed. <a href="/flush">Please retry.</a>\n失敗しました。<a href="/flush">もう一度試してみてください。</a>`);
message(`\nIf you retry more than 3 times, clear the browser cache or contact to instance admin.\n3回以上試しても失敗する場合、ブラウザのキャッシュを消去し、それでもだめならインスタンス管理者に連絡してみてください。\n`)
console.error(e);
setTimeout(() => {
location = '/';
}, 10000)
}
})();
})();
}
function message(text) {
msg.insertAdjacentHTML('beforeend', `<p>[${(new Date()).toString()}] ${text.replace(/\n/g,'<br>')}</p>`)
@@ -68,7 +68,6 @@ async function createAdmin(host: Host): Promise<Misskey.entities.SignupResponse
return await client.request('admin/accounts/create', ADMIN_PARAMS).then(res => {
ADMIN_CACHE.set(host, {
id: res.id,
// @ts-expect-error FIXME: openapi-typescript generates incorrect response type for this endpoint, so ignore this
i: res.token,
});
return res as Misskey.entities.SignupResponse;
+3 -6
View File
@@ -363,14 +363,11 @@ describe('クリップ', () => {
const clipLimit = DEFAULT_POLICIES.clipLimit;
const clips = await createMany({}, clipLimit);
const res = await list({
parameters: { limit: 1 }, // FIXME: 無視されて11全部返ってくる
parameters: { limit: clips.length },
});
// 返ってくる配列には順序保障がないのでidでソートして厳密比較
assert.deepStrictEqual(
res.sort(compareBy(s => s.id)),
clips.sort(compareBy(s => s.id)),
);
// 作成responseの配列には順序保障がないのでidでソートして厳密比較
assert.deepStrictEqual(res.toReversed(), clips.sort(compareBy(s => s.id)));
});
test('の一覧が取得できる(空)', async () => {
+1 -1
View File
@@ -20,6 +20,6 @@
"dependencies": {
"estree-walker": "3.0.3",
"magic-string": "0.30.17",
"vite": "7.0.6"
"vite": "7.0.7"
}
}
+65 -3
View File
@@ -46,9 +46,71 @@ export default [
allowSingleExtends: true,
}],
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
// window の禁止理由: グローバルスコープと衝突し、予期せぬ結果を招くため
// e の禁止理由: error や event など、複数のキーワードの頭文字であり分かりにくいため
'id-denylist': ['error', 'window', 'e'],
// window ... グローバルスコープと衝突し、予期せぬ結果を招くため
// e ... error や event など、複数のキーワードの頭文字であり分かりにくいため
// close ... window.closeと衝突 or 紛らわしい
// open ... window.openと衝突 or 紛らわしい
// fetch ... window.fetchと衝突 or 紛らわしい
// location ... window.locationと衝突 or 紛らわしい
// document ... window.documentと衝突 or 紛らわしい
// history ... window.historyと衝突 or 紛らわしい
// scroll ... window.scrollと衝突 or 紛らわしい
// setTimeout ... window.setTimeoutと衝突 or 紛らわしい
// setInterval ... window.setIntervalと衝突 or 紛らわしい
// clearTimeout ... window.clearTimeoutと衝突 or 紛らわしい
// clearInterval ... window.clearIntervalと衝突 or 紛らわしい
'id-denylist': ['error', 'window', 'e', 'close', 'open', 'fetch', 'location', 'document', 'history', 'scroll', 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval'],
'no-restricted-globals': [
'error',
{
'name': 'open',
'message': 'Use `window.open`.',
},
{
'name': 'close',
'message': 'Use `window.close`.',
},
{
'name': 'fetch',
'message': 'Use `window.fetch`.',
},
{
'name': 'location',
'message': 'Use `window.location`.',
},
{
'name': 'document',
'message': 'Use `window.document`.',
},
{
'name': 'history',
'message': 'Use `window.history`.',
},
{
'name': 'scroll',
'message': 'Use `window.scroll`.',
},
{
'name': 'setTimeout',
'message': 'Use `window.setTimeout`.',
},
{
'name': 'setInterval',
'message': 'Use `window.setInterval`.',
},
{
'name': 'clearTimeout',
'message': 'Use `window.clearTimeout`.',
},
{
'name': 'clearInterval',
'message': 'Use `window.clearInterval`.',
},
{
'name': 'name',
'message': 'Use `window.name`. もしくは name という変数名を定義し忘れている',
},
],
'no-shadow': ['warn'],
'vue/attributes-order': ['error', {
alphabetical: false,
+16 -16
View File
@@ -13,10 +13,10 @@
"@discordapp/twemoji": "16.0.1",
"@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "6.0.2",
"@rollup/pluginutils": "5.2.0",
"@rollup/pluginutils": "5.3.0",
"@twemoji/parser": "16.0.0",
"@vitejs/plugin-vue": "6.0.1",
"@vue/compiler-sfc": "3.5.18",
"@vue/compiler-sfc": "3.5.21",
"astring": "1.9.0",
"buraha": "0.0.1",
"estree-walker": "3.0.3",
@@ -26,16 +26,16 @@
"mfm-js": "0.25.0",
"misskey-js": "workspace:*",
"punycode.js": "2.3.1",
"rollup": "4.46.2",
"sass": "1.89.2",
"shiki": "3.9.1",
"rollup": "4.50.1",
"sass": "1.92.1",
"shiki": "3.12.2",
"tinycolor2": "1.6.0",
"tsc-alias": "1.8.16",
"tsconfig-paths": "4.2.0",
"typescript": "5.9.2",
"uuid": "11.1.0",
"vite": "7.0.6",
"vue": "3.5.18"
"vite": "7.1.5",
"vue": "3.5.21"
},
"devDependencies": {
"@misskey-dev/summaly": "5.2.3",
@@ -43,14 +43,14 @@
"@testing-library/vue": "8.1.0",
"@types/estree": "1.0.8",
"@types/micromatch": "4.0.9",
"@types/node": "22.17.0",
"@types/node": "22.18.1",
"@types/punycode.js": "npm:@types/punycode@2.1.4",
"@types/tinycolor2": "1.4.6",
"@types/ws": "8.18.1",
"@typescript-eslint/eslint-plugin": "8.38.0",
"@typescript-eslint/parser": "8.38.0",
"@typescript-eslint/eslint-plugin": "8.42.0",
"@typescript-eslint/parser": "8.42.0",
"@vitest/coverage-v8": "3.2.4",
"@vue/runtime-core": "3.5.18",
"@vue/runtime-core": "3.5.21",
"acorn": "8.15.0",
"cross-env": "10.0.0",
"eslint-plugin-import": "2.32.0",
@@ -59,14 +59,14 @@
"happy-dom": "18.0.1",
"intersection-observer": "0.12.2",
"micromatch": "4.0.8",
"msw": "2.10.4",
"msw": "2.11.1",
"nodemon": "3.1.10",
"prettier": "3.6.2",
"start-server-and-test": "2.0.12",
"tsx": "4.20.3",
"start-server-and-test": "2.1.0",
"tsx": "4.20.5",
"vite-plugin-turbosnap": "1.0.3",
"vue-component-type-helpers": "3.0.5",
"vue-component-type-helpers": "3.0.6",
"vue-eslint-parser": "10.2.0",
"vue-tsc": "3.0.5"
"vue-tsc": "3.0.6"
}
}
+6 -6
View File
@@ -33,7 +33,7 @@ import type { Theme } from '@/theme.js';
console.log('Misskey Embed');
//#region Embedパラメータの取得・パース
const params = new URLSearchParams(location.search);
const params = new URLSearchParams(window.location.search);
const embedParams = parseEmbedParams(params);
if (_DEV_) console.log(embedParams);
//#endregion
@@ -81,7 +81,7 @@ storeBootloaderErrors({ ...i18n.ts._bootErrors, reload: i18n.ts.reload });
//#endregion
// サイズの制限
document.documentElement.style.maxWidth = '500px';
window.document.documentElement.style.maxWidth = '500px';
// iframeIdの設定
function setIframeIdHandler(event: MessageEvent) {
@@ -114,16 +114,16 @@ app.provide(DI.embedParams, embedParams);
const rootEl = ((): HTMLElement => {
const MISSKEY_MOUNT_DIV_ID = 'misskey_app';
const currentRoot = document.getElementById(MISSKEY_MOUNT_DIV_ID);
const currentRoot = window.document.getElementById(MISSKEY_MOUNT_DIV_ID);
if (currentRoot) {
console.warn('multiple import detected');
return currentRoot;
}
const root = document.createElement('div');
const root = window.document.createElement('div');
root.id = MISSKEY_MOUNT_DIV_ID;
document.body.appendChild(root);
window.document.body.appendChild(root);
return root;
})();
@@ -159,7 +159,7 @@ console.log(i18n.tsx._selfXssPrevention.description3({ link: 'https://misskey-hu
//#endregion
function removeSplash() {
const splash = document.getElementById('splash');
const splash = window.document.getElementById('splash');
if (splash) {
splash.style.opacity = '0';
splash.style.pointerEvents = 'none';
@@ -19,7 +19,7 @@ import { extractAvgColorFromBlurhash } from '@@/js/extract-avg-color-from-blurha
const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resolve => {
// テスト環境で Web Worker インスタンスは作成できない
if (import.meta.env.MODE === 'test') {
const canvas = document.createElement('canvas');
const canvas = window.document.createElement('canvas');
canvas.width = 64;
canvas.height = 64;
resolve(canvas);
@@ -34,7 +34,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
);
resolve(workers);
} else {
const canvas = document.createElement('canvas');
const canvas = window.document.createElement('canvas');
canvas.width = 64;
canvas.height = 64;
resolve(canvas);
@@ -29,7 +29,7 @@ const props = defineProps<{
// if no instance data is given, this is for the local instance
const instance = props.instance ?? {
name: serverMetadata.name,
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement)?.content,
themeColor: (window.document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement)?.content,
};
const faviconUrl = computed(() => props.instance ? mediaProxy.getProxiedImageUrlNullable(props.instance.faviconUrl, 'preview') : mediaProxy.getProxiedImageUrlNullable(serverMetadata.iconUrl, 'preview') ?? '/favicon.ico');
@@ -27,7 +27,7 @@ const canonical = props.host === localHost ? `@${props.username}` : `@${props.us
const url = `/${canonical}`;
const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--MI_THEME-mention'));
const bg = tinycolor(getComputedStyle(window.document.documentElement).getPropertyValue('--MI_THEME-mention'));
bg.setAlpha(0.1);
const bgCss = bg.toRgbString();
</script>
@@ -134,7 +134,7 @@ const isBackTop = ref(false);
const empty = computed(() => items.value.size === 0);
const error = ref(false);
const scrollableElement = computed(() => rootEl.value ? getScrollContainer(rootEl.value) : document.body);
const scrollableElement = computed(() => rootEl.value ? getScrollContainer(rootEl.value) : window.document.body);
const visibility = useDocumentVisibility();
@@ -353,7 +353,7 @@ watch(visibility, () => {
BACKGROUND_PAUSE_WAIT_SEC * 1000);
} else { // 'visible'
if (timerForSetPause) {
clearTimeout(timerForSetPause);
window.clearTimeout(timerForSetPause);
timerForSetPause = null;
} else {
isPausingUpdate = false;
@@ -447,11 +447,11 @@ onBeforeMount(() => {
init().then(() => {
if (props.pagination.reversed) {
nextTick(() => {
setTimeout(toBottom, 800);
window.setTimeout(toBottom, 800);
// scrollToBottomでmoreFetchingボタンが画面外まで出るまで
// more = trueを遅らせる
setTimeout(() => {
window.setTimeout(() => {
moreFetching.value = false;
}, 2000);
});
@@ -461,11 +461,11 @@ onBeforeMount(() => {
onBeforeUnmount(() => {
if (timerForSetPause) {
clearTimeout(timerForSetPause);
window.clearTimeout(timerForSetPause);
timerForSetPause = null;
}
if (preventAppearFetchMoreTimer.value) {
clearTimeout(preventAppearFetchMoreTimer.value);
window.clearTimeout(preventAppearFetchMoreTimer.value);
preventAppearFetchMoreTimer.value = null;
}
scrollObserver.value?.disconnect();
@@ -4,7 +4,7 @@
*/
import * as Misskey from 'misskey-js';
const providedContextEl = document.getElementById('misskey_embedCtx');
const providedContextEl = window.document.getElementById('misskey_embedCtx');
export type ServerContext = {
clip?: Misskey.entities.Clip;
@@ -6,7 +6,7 @@
import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/misskey-api.js';
const providedMetaEl = document.getElementById('misskey_meta');
const providedMetaEl = window.document.getElementById('misskey_meta');
const _serverMetadata: Misskey.entities.MetaDetailed | null = (providedMetaEl && providedMetaEl.textContent) ? JSON.parse(providedMetaEl.textContent) : null;
+7 -5
View File
@@ -3,6 +3,8 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
// TODO: (可能な部分を)sharedに抽出して frontend と共通化
import tinycolor from 'tinycolor2';
import lightTheme from '@@/themes/_light.json5';
import darkTheme from '@@/themes/_dark.json5';
@@ -33,15 +35,15 @@ export function assertIsTheme(theme: Record<string, unknown>): theme is Theme {
export function applyTheme(theme: Theme, persist = true) {
if (timeout) window.clearTimeout(timeout);
document.documentElement.classList.add('_themeChanging_');
window.document.documentElement.classList.add('_themeChanging_');
timeout = window.setTimeout(() => {
document.documentElement.classList.remove('_themeChanging_');
window.document.documentElement.classList.remove('_themeChanging_');
}, 1000);
const colorScheme = theme.base === 'dark' ? 'dark' : 'light';
document.documentElement.dataset.colorScheme = colorScheme;
window.document.documentElement.dataset.colorScheme = colorScheme;
// Deep copy
const _theme = JSON.parse(JSON.stringify(theme));
@@ -53,7 +55,7 @@ export function applyTheme(theme: Theme, persist = true) {
const props = compile(_theme);
for (const tag of document.head.children) {
for (const tag of window.document.head.children) {
if (tag.tagName === 'META' && tag.getAttribute('name') === 'theme-color') {
tag.setAttribute('content', props['htmlThemeColor']);
break;
@@ -61,7 +63,7 @@ export function applyTheme(theme: Theme, persist = true) {
}
for (const [k, v] of Object.entries(props)) {
document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
window.document.documentElement.style.setProperty(`--MI_THEME-${k}`, v.toString());
}
// iframeを正常に透過させるために、cssのcolor-schemeは `light dark;` 固定にしてある。style.scss参照

Some files were not shown because too many files have changed in this diff Show More