mirror of
https://activitypub.software/TransFem-org/Sharkey
synced 2024-11-22 05:55:12 +00:00
merge: Merge upstream changes from 23rd of Feburary (!439)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/439 Closes #431 Approved-by: dakkar <dakkar@thenautilus.net> Approved-by: Amelia Yukii <amelia.yukii@shourai.de>
This commit is contained in:
commit
d539dec8b1
94 changed files with 1719 additions and 1113 deletions
27
CHANGELOG.md
27
CHANGELOG.md
|
@ -14,26 +14,20 @@
|
||||||
## 202x.x.x (unreleased)
|
## 202x.x.x (unreleased)
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
- Enhance: サーバーごとにモデレーションノートを残せるように
|
||||||
|
|
||||||
|
### Client
|
||||||
|
- Enhance: ノート作成画面のファイル添付メニューの区切り線の位置を調整
|
||||||
- Fix: syuilo/misskeyの時代からあるインスタンスが改変されたバージョンであると誤認識される問題
|
- Fix: syuilo/misskeyの時代からあるインスタンスが改変されたバージョンであると誤認識される問題
|
||||||
|
- Fix: MFMのオートコンプリートが出るべき状況で出ないことがある問題を修正
|
||||||
### Client
|
- Fix: チャートのラベルが消えている問題を修正
|
||||||
|
- Fix: 画面表示後最初の音声再生が爆音になることがある問題を修正
|
||||||
### Server
|
- Fix: 絵文字サジェストの順位で、絵文字自体の名前が同じものよりもタグで一致しているものが優先されてしまう問題を修正
|
||||||
|
|
||||||
|
|
||||||
## 202x.x.x (unreleased)
|
|
||||||
|
|
||||||
### General
|
|
||||||
|
|
||||||
### Client
|
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正
|
- Fix: nodeinfoにenableMcaptchaとenableTurnstileが無いのを修正
|
||||||
|
- エンドポイント`flash/update`の`flashId`以外のパラメータは必須ではなくなりました
|
||||||
## 202x.x.x (unreleased)
|
- Fix: 禁止キーワードを含むノートがDelayed Queueに追加されて再処理される問題を修正
|
||||||
|
|
||||||
### Client
|
|
||||||
- Fix: MFMのオートコンプリートが出るべき状況で出ないことがある問題を修正
|
|
||||||
|
|
||||||
## 2024.2.0
|
## 2024.2.0
|
||||||
|
|
||||||
|
@ -106,6 +100,7 @@
|
||||||
- Fix: エラー画像URLを設定した後解除すると,デフォルトの画像が表示されない問題の修正
|
- Fix: エラー画像URLを設定した後解除すると,デフォルトの画像が表示されない問題の修正
|
||||||
- Fix: MkCodeEditorで行がずれていってしまう問題の修正
|
- Fix: MkCodeEditorで行がずれていってしまう問題の修正
|
||||||
- Fix: Summaly proxy利用時にプレイヤーが動作しないことがあるのを修正 #13196
|
- Fix: Summaly proxy利用時にプレイヤーが動作しないことがあるのを修正 #13196
|
||||||
|
- Fix: ユーザの情報のポップアップが消えなくなることがある問題を修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Enhance: 連合先のレートリミットを超過した際にリトライするようになりました
|
- Enhance: 連合先のレートリミットを超過した際にリトライするようになりました
|
||||||
|
|
68
locales/index.d.ts
vendored
68
locales/index.d.ts
vendored
|
@ -5053,6 +5053,14 @@ export interface Locale extends ILocale {
|
||||||
* リプレイ中
|
* リプレイ中
|
||||||
*/
|
*/
|
||||||
"replaying": string;
|
"replaying": string;
|
||||||
|
/**
|
||||||
|
* リプレイを終了
|
||||||
|
*/
|
||||||
|
"endReplay": string;
|
||||||
|
/**
|
||||||
|
* リプレイデータをコピー
|
||||||
|
*/
|
||||||
|
"copyReplayData": string;
|
||||||
/**
|
/**
|
||||||
* ランキング
|
* ランキング
|
||||||
*/
|
*/
|
||||||
|
@ -5081,11 +5089,57 @@ export interface Locale extends ILocale {
|
||||||
* スワイプしてタブを切り替える
|
* スワイプしてタブを切り替える
|
||||||
*/
|
*/
|
||||||
"enableHorizontalSwipe": string;
|
"enableHorizontalSwipe": string;
|
||||||
|
/**
|
||||||
|
* 読み込み中
|
||||||
|
*/
|
||||||
|
"loading": string;
|
||||||
|
/**
|
||||||
|
* やめる
|
||||||
|
*/
|
||||||
|
"surrender": string;
|
||||||
|
/**
|
||||||
|
* リトライ
|
||||||
|
*/
|
||||||
|
"gameRetry": string;
|
||||||
"_bubbleGame": {
|
"_bubbleGame": {
|
||||||
/**
|
/**
|
||||||
* 遊び方
|
* 遊び方
|
||||||
*/
|
*/
|
||||||
"howToPlay": string;
|
"howToPlay": string;
|
||||||
|
/**
|
||||||
|
* ホールド
|
||||||
|
*/
|
||||||
|
"hold": string;
|
||||||
|
"_score": {
|
||||||
|
/**
|
||||||
|
* スコア
|
||||||
|
*/
|
||||||
|
"score": string;
|
||||||
|
/**
|
||||||
|
* 稼いだ金額
|
||||||
|
*/
|
||||||
|
"scoreYen": string;
|
||||||
|
/**
|
||||||
|
* ハイスコア
|
||||||
|
*/
|
||||||
|
"highScore": string;
|
||||||
|
/**
|
||||||
|
* 最大チェーン数
|
||||||
|
*/
|
||||||
|
"maxChain": string;
|
||||||
|
/**
|
||||||
|
* {yen}円
|
||||||
|
*/
|
||||||
|
"yen": ParameterizedString<"yen">;
|
||||||
|
/**
|
||||||
|
* {qty}個分
|
||||||
|
*/
|
||||||
|
"estimatedQty": ParameterizedString<"qty">;
|
||||||
|
/**
|
||||||
|
* おにぎり {onigiriQtyWithUnit}
|
||||||
|
*/
|
||||||
|
"scoreSweets": ParameterizedString<"onigiriQtyWithUnit">;
|
||||||
|
};
|
||||||
"_howToPlay": {
|
"_howToPlay": {
|
||||||
/**
|
/**
|
||||||
* 位置を調整してハコにモノを落とします。
|
* 位置を調整してハコにモノを落とします。
|
||||||
|
@ -9433,7 +9487,7 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"updateServerSettings": string;
|
"updateServerSettings": string;
|
||||||
/**
|
/**
|
||||||
* モデレーションノート更新
|
* ユーザーのモデレーションノート更新
|
||||||
*/
|
*/
|
||||||
"updateUserNote": string;
|
"updateUserNote": string;
|
||||||
/**
|
/**
|
||||||
|
@ -9480,6 +9534,10 @@ export interface Locale extends ILocale {
|
||||||
* リモートサーバーを再開
|
* リモートサーバーを再開
|
||||||
*/
|
*/
|
||||||
"unsuspendRemoteInstance": string;
|
"unsuspendRemoteInstance": string;
|
||||||
|
/**
|
||||||
|
* リモートサーバーのモデレーションノート更新
|
||||||
|
*/
|
||||||
|
"updateRemoteInstanceNote": string;
|
||||||
/**
|
/**
|
||||||
* ファイルをセンシティブ付与
|
* ファイルをセンシティブ付与
|
||||||
*/
|
*/
|
||||||
|
@ -9954,6 +10012,14 @@ export interface Locale extends ILocale {
|
||||||
* 変則なし
|
* 変則なし
|
||||||
*/
|
*/
|
||||||
"disallowIrregularRules": string;
|
"disallowIrregularRules": string;
|
||||||
|
/**
|
||||||
|
* 盤面に行・列番号を表示
|
||||||
|
*/
|
||||||
|
"showBoardLabels": string;
|
||||||
|
/**
|
||||||
|
* 石をアイコンにする
|
||||||
|
*/
|
||||||
|
"useAvatarAsStone": string;
|
||||||
};
|
};
|
||||||
"_offlineScreen": {
|
"_offlineScreen": {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1259,6 +1259,8 @@ soundWillBePlayed: "サウンドが再生されます"
|
||||||
showReplay: "リプレイを見る"
|
showReplay: "リプレイを見る"
|
||||||
replay: "リプレイ"
|
replay: "リプレイ"
|
||||||
replaying: "リプレイ中"
|
replaying: "リプレイ中"
|
||||||
|
endReplay: "リプレイを終了"
|
||||||
|
copyReplayData: "リプレイデータをコピー"
|
||||||
ranking: "ランキング"
|
ranking: "ランキング"
|
||||||
lastNDays: "直近{n}日"
|
lastNDays: "直近{n}日"
|
||||||
backToTitle: "タイトルへ"
|
backToTitle: "タイトルへ"
|
||||||
|
@ -1266,9 +1268,21 @@ hemisphere: "お住まいの地域"
|
||||||
withSensitive: "センシティブなファイルを含むノートを表示"
|
withSensitive: "センシティブなファイルを含むノートを表示"
|
||||||
userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿"
|
userSaysSomethingSensitive: "{name}のセンシティブなファイルを含む投稿"
|
||||||
enableHorizontalSwipe: "スワイプしてタブを切り替える"
|
enableHorizontalSwipe: "スワイプしてタブを切り替える"
|
||||||
|
loading: "読み込み中"
|
||||||
|
surrender: "やめる"
|
||||||
|
gameRetry: "リトライ"
|
||||||
|
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "遊び方"
|
howToPlay: "遊び方"
|
||||||
|
hold: "ホールド"
|
||||||
|
_score:
|
||||||
|
score: "スコア"
|
||||||
|
scoreYen: "稼いだ金額"
|
||||||
|
highScore: "ハイスコア"
|
||||||
|
maxChain: "最大チェーン数"
|
||||||
|
yen: "{yen}円"
|
||||||
|
estimatedQty: "{qty}個分"
|
||||||
|
scoreSweets: "おにぎり {onigiriQtyWithUnit}"
|
||||||
_howToPlay:
|
_howToPlay:
|
||||||
section1: "位置を調整してハコにモノを落とします。"
|
section1: "位置を調整してハコにモノを落とします。"
|
||||||
section2: "同じ種類のモノがくっつくと別のモノに変化して、スコアが得られます。"
|
section2: "同じ種類のモノがくっつくと別のモノに変化して、スコアが得られます。"
|
||||||
|
@ -2499,7 +2513,7 @@ _moderationLogTypes:
|
||||||
updateCustomEmoji: "カスタム絵文字更新"
|
updateCustomEmoji: "カスタム絵文字更新"
|
||||||
deleteCustomEmoji: "カスタム絵文字削除"
|
deleteCustomEmoji: "カスタム絵文字削除"
|
||||||
updateServerSettings: "サーバー設定更新"
|
updateServerSettings: "サーバー設定更新"
|
||||||
updateUserNote: "モデレーションノート更新"
|
updateUserNote: "ユーザーのモデレーションノート更新"
|
||||||
deleteDriveFile: "ファイルを削除"
|
deleteDriveFile: "ファイルを削除"
|
||||||
deleteNote: "ノートを削除"
|
deleteNote: "ノートを削除"
|
||||||
createGlobalAnnouncement: "全体のお知らせを作成"
|
createGlobalAnnouncement: "全体のお知らせを作成"
|
||||||
|
@ -2511,6 +2525,7 @@ _moderationLogTypes:
|
||||||
resetPassword: "パスワードをリセット"
|
resetPassword: "パスワードをリセット"
|
||||||
suspendRemoteInstance: "リモートサーバーを停止"
|
suspendRemoteInstance: "リモートサーバーを停止"
|
||||||
unsuspendRemoteInstance: "リモートサーバーを再開"
|
unsuspendRemoteInstance: "リモートサーバーを再開"
|
||||||
|
updateRemoteInstanceNote: "リモートサーバーのモデレーションノート更新"
|
||||||
markSensitiveDriveFile: "ファイルをセンシティブ付与"
|
markSensitiveDriveFile: "ファイルをセンシティブ付与"
|
||||||
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
|
unmarkSensitiveDriveFile: "ファイルをセンシティブ解除"
|
||||||
resolveAbuseReport: "通報を解決"
|
resolveAbuseReport: "通報を解決"
|
||||||
|
@ -2649,6 +2664,8 @@ _reversi:
|
||||||
opponentHasSettingsChanged: "相手が設定を変更しました"
|
opponentHasSettingsChanged: "相手が設定を変更しました"
|
||||||
allowIrregularRules: "変則許可 (完全フリー)"
|
allowIrregularRules: "変則許可 (完全フリー)"
|
||||||
disallowIrregularRules: "変則なし"
|
disallowIrregularRules: "変則なし"
|
||||||
|
showBoardLabels: "盤面に行・列番号を表示"
|
||||||
|
useAvatarAsStone: "石をアイコンにする"
|
||||||
|
|
||||||
_offlineScreen:
|
_offlineScreen:
|
||||||
title: "オフライン - サーバーに接続できません"
|
title: "オフライン - サーバーに接続できません"
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class PerInstanceModNote1708399372194 {
|
||||||
|
name = 'PerInstanceModNote1708399372194'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" ADD "moderationNote" character varying(16384) NOT NULL DEFAULT ''`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "moderationNote"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -77,7 +77,7 @@
|
||||||
"@fastify/multipart": "8.1.0",
|
"@fastify/multipart": "8.1.0",
|
||||||
"@fastify/static": "6.12.0",
|
"@fastify/static": "6.12.0",
|
||||||
"@fastify/view": "8.2.0",
|
"@fastify/view": "8.2.0",
|
||||||
"@misskey-dev/sharp-read-bmp": "^1.1.1",
|
"@misskey-dev/sharp-read-bmp": "^1.2.0",
|
||||||
"@misskey-dev/summaly": "^5.0.3",
|
"@misskey-dev/summaly": "^5.0.3",
|
||||||
"@nestjs/common": "10.2.10",
|
"@nestjs/common": "10.2.10",
|
||||||
"@nestjs/core": "10.2.10",
|
"@nestjs/core": "10.2.10",
|
||||||
|
@ -120,6 +120,7 @@
|
||||||
"got": "14.1.0",
|
"got": "14.1.0",
|
||||||
"happy-dom": "10.0.3",
|
"happy-dom": "10.0.3",
|
||||||
"hpagent": "1.2.0",
|
"hpagent": "1.2.0",
|
||||||
|
"htmlescape": "^1.1.1",
|
||||||
"http-link-header": "1.1.1",
|
"http-link-header": "1.1.1",
|
||||||
"ioredis": "5.3.2",
|
"ioredis": "5.3.2",
|
||||||
"ip-cidr": "3.1.0",
|
"ip-cidr": "3.1.0",
|
||||||
|
@ -165,7 +166,7 @@
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "7.8.1",
|
||||||
"sanitize-html": "2.11.0",
|
"sanitize-html": "2.11.0",
|
||||||
"secure-json-parse": "2.7.0",
|
"secure-json-parse": "2.7.0",
|
||||||
"sharp": "0.32.6",
|
"sharp": "0.33.2",
|
||||||
"slacc": "0.0.10",
|
"slacc": "0.0.10",
|
||||||
"strict-event-emitter-types": "2.0.0",
|
"strict-event-emitter-types": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
|
@ -196,6 +197,7 @@
|
||||||
"@types/color-convert": "2.0.3",
|
"@types/color-convert": "2.0.3",
|
||||||
"@types/content-disposition": "0.5.8",
|
"@types/content-disposition": "0.5.8",
|
||||||
"@types/fluent-ffmpeg": "2.1.24",
|
"@types/fluent-ffmpeg": "2.1.24",
|
||||||
|
"@types/htmlescape": "^1.1.3",
|
||||||
"@types/http-link-header": "1.0.5",
|
"@types/http-link-header": "1.0.5",
|
||||||
"@types/jest": "29.5.11",
|
"@types/jest": "29.5.11",
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
|
|
|
@ -128,6 +128,7 @@ export class CacheService implements OnApplicationShutdown {
|
||||||
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
|
const { type, body } = obj.message as GlobalEvents['internal']['payload'];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'userChangeSuspendedState':
|
case 'userChangeSuspendedState':
|
||||||
|
case 'userChangeDeletedState':
|
||||||
case 'remoteUserUpdated': {
|
case 'remoteUserUpdated': {
|
||||||
const user = await this.usersRepository.findOneBy({ id: body.id });
|
const user = await this.usersRepository.findOneBy({ id: body.id });
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
|
|
@ -116,6 +116,7 @@ import { FlashEntityService } from './entities/FlashEntityService.js';
|
||||||
import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
|
import { FlashLikeEntityService } from './entities/FlashLikeEntityService.js';
|
||||||
import { RoleEntityService } from './entities/RoleEntityService.js';
|
import { RoleEntityService } from './entities/RoleEntityService.js';
|
||||||
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
|
import { ReversiGameEntityService } from './entities/ReversiGameEntityService.js';
|
||||||
|
import { MetaEntityService } from './entities/MetaEntityService.js';
|
||||||
|
|
||||||
import { ApAudienceService } from './activitypub/ApAudienceService.js';
|
import { ApAudienceService } from './activitypub/ApAudienceService.js';
|
||||||
import { ApDbResolverService } from './activitypub/ApDbResolverService.js';
|
import { ApDbResolverService } from './activitypub/ApDbResolverService.js';
|
||||||
|
@ -254,6 +255,7 @@ const $FlashEntityService: Provider = { provide: 'FlashEntityService', useExisti
|
||||||
const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
|
const $FlashLikeEntityService: Provider = { provide: 'FlashLikeEntityService', useExisting: FlashLikeEntityService };
|
||||||
const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService };
|
const $RoleEntityService: Provider = { provide: 'RoleEntityService', useExisting: RoleEntityService };
|
||||||
const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService };
|
const $ReversiGameEntityService: Provider = { provide: 'ReversiGameEntityService', useExisting: ReversiGameEntityService };
|
||||||
|
const $MetaEntityService: Provider = { provide: 'MetaEntityService', useExisting: MetaEntityService };
|
||||||
|
|
||||||
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
|
const $ApAudienceService: Provider = { provide: 'ApAudienceService', useExisting: ApAudienceService };
|
||||||
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
|
const $ApDbResolverService: Provider = { provide: 'ApDbResolverService', useExisting: ApDbResolverService };
|
||||||
|
@ -393,6 +395,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
FlashLikeEntityService,
|
FlashLikeEntityService,
|
||||||
RoleEntityService,
|
RoleEntityService,
|
||||||
ReversiGameEntityService,
|
ReversiGameEntityService,
|
||||||
|
MetaEntityService,
|
||||||
|
|
||||||
ApAudienceService,
|
ApAudienceService,
|
||||||
ApDbResolverService,
|
ApDbResolverService,
|
||||||
|
@ -528,6 +531,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$FlashLikeEntityService,
|
$FlashLikeEntityService,
|
||||||
$RoleEntityService,
|
$RoleEntityService,
|
||||||
$ReversiGameEntityService,
|
$ReversiGameEntityService,
|
||||||
|
$MetaEntityService,
|
||||||
|
|
||||||
$ApAudienceService,
|
$ApAudienceService,
|
||||||
$ApDbResolverService,
|
$ApDbResolverService,
|
||||||
|
@ -663,6 +667,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
FlashLikeEntityService,
|
FlashLikeEntityService,
|
||||||
RoleEntityService,
|
RoleEntityService,
|
||||||
ReversiGameEntityService,
|
ReversiGameEntityService,
|
||||||
|
MetaEntityService,
|
||||||
|
|
||||||
ApAudienceService,
|
ApAudienceService,
|
||||||
ApDbResolverService,
|
ApDbResolverService,
|
||||||
|
@ -797,6 +802,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$FlashLikeEntityService,
|
$FlashLikeEntityService,
|
||||||
$RoleEntityService,
|
$RoleEntityService,
|
||||||
$ReversiGameEntityService,
|
$ReversiGameEntityService,
|
||||||
|
$MetaEntityService,
|
||||||
|
|
||||||
$ApAudienceService,
|
$ApAudienceService,
|
||||||
$ApDbResolverService,
|
$ApDbResolverService,
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import { UserSuspendService } from '@/core/UserSuspendService.js';
|
import { UserSuspendService } from '@/core/UserSuspendService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DeleteAccountService {
|
export class DeleteAccountService {
|
||||||
|
@ -18,6 +19,7 @@ export class DeleteAccountService {
|
||||||
|
|
||||||
private userSuspendService: UserSuspendService,
|
private userSuspendService: UserSuspendService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
|
private globalEventService: GlobalEventService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,5 +41,7 @@ export class DeleteAccountService {
|
||||||
await this.usersRepository.update(user.id, {
|
await this.usersRepository.update(user.id, {
|
||||||
isDeleted: true,
|
isDeleted: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.globalEventService.publishInternalEvent('userChangeDeletedState', { id: user.id, isDeleted: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import * as fileType from 'file-type';
|
||||||
import isSvg from 'is-svg';
|
import isSvg from 'is-svg';
|
||||||
import probeImageSize from 'probe-image-size';
|
import probeImageSize from 'probe-image-size';
|
||||||
import sharp from 'sharp';
|
import sharp from 'sharp';
|
||||||
|
import { sharpBmp } from '@misskey-dev/sharp-read-bmp';
|
||||||
import { encode } from 'blurhash';
|
import { encode } from 'blurhash';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
|
||||||
|
@ -110,7 +111,7 @@ export class FileInfoService {
|
||||||
'image/avif',
|
'image/avif',
|
||||||
'image/svg+xml',
|
'image/svg+xml',
|
||||||
].includes(type.mime)) {
|
].includes(type.mime)) {
|
||||||
blurhash = await this.getBlurhash(path).catch(e => {
|
blurhash = await this.getBlurhash(path, type.mime).catch(e => {
|
||||||
warnings.push(`getBlurhash failed: ${e}`);
|
warnings.push(`getBlurhash failed: ${e}`);
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
@ -237,9 +238,9 @@ export class FileInfoService {
|
||||||
* Calculate average color of image
|
* Calculate average color of image
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
private getBlurhash(path: string): Promise<string> {
|
private getBlurhash(path: string, type: string): Promise<string> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
sharp(path)
|
(await sharpBmp(path, type))
|
||||||
.raw()
|
.raw()
|
||||||
.ensureAlpha()
|
.ensureAlpha()
|
||||||
.resize(64, 64, { fit: 'inside' })
|
.resize(64, 64, { fit: 'inside' })
|
||||||
|
|
|
@ -213,6 +213,7 @@ type SerializedAll<T> = {
|
||||||
|
|
||||||
export interface InternalEventTypes {
|
export interface InternalEventTypes {
|
||||||
userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
|
userChangeSuspendedState: { id: MiUser['id']; isSuspended: MiUser['isSuspended']; };
|
||||||
|
userChangeDeletedState: { id: MiUser['id']; isDeleted: MiUser['isDeleted']; };
|
||||||
userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; };
|
userTokenRegenerated: { id: MiUser['id']; oldToken: string; newToken: string; };
|
||||||
remoteUserUpdated: { id: MiUser['id']; };
|
remoteUserUpdated: { id: MiUser['id']; };
|
||||||
follow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
|
follow: { followerId: MiUser['id']; followeeId: MiUser['id']; };
|
||||||
|
|
|
@ -61,6 +61,8 @@ import { CacheService } from '@/core/CacheService.js';
|
||||||
import { isReply } from '@/misc/is-reply.js';
|
import { isReply } from '@/misc/is-reply.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
|
||||||
|
@ -153,8 +155,6 @@ type Option = {
|
||||||
export class NoteCreateService implements OnApplicationShutdown {
|
export class NoteCreateService implements OnApplicationShutdown {
|
||||||
#shutdownController = new AbortController();
|
#shutdownController = new AbortController();
|
||||||
|
|
||||||
public static ContainsProhibitedWordsError = class extends Error {};
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
private config: Config,
|
private config: Config,
|
||||||
|
@ -439,7 +439,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
|
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
|
||||||
throw new NoteCreateService.ContainsProhibitedWordsError();
|
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
|
||||||
}
|
}
|
||||||
|
|
||||||
const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
|
const inSilencedInstance = this.utilityService.isSilencedHost(meta.silencedHosts, user.host);
|
||||||
|
@ -1141,7 +1141,7 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
const mentions = extractMentions(tokens);
|
const mentions = extractMentions(tokens);
|
||||||
let mentionedUsers = (await Promise.all(mentions.map(m =>
|
let mentionedUsers = (await Promise.all(mentions.map(m =>
|
||||||
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
|
this.remoteUserResolveService.resolveUser(m.username, m.host ?? user.host).catch(() => null),
|
||||||
))).filter(x => x != null) as MiUser[];
|
))).filter(isNotNull);
|
||||||
|
|
||||||
// Drop duplicate users
|
// Drop duplicate users
|
||||||
mentionedUsers = mentionedUsers.filter((u, i, self) =>
|
mentionedUsers = mentionedUsers.filter((u, i, self) =>
|
||||||
|
|
|
@ -51,6 +51,7 @@ import { CacheService } from '@/core/CacheService.js';
|
||||||
import { isReply } from '@/misc/is-reply.js';
|
import { isReply } from '@/misc/is-reply.js';
|
||||||
import { trackPromise } from '@/misc/promise-tracker.js';
|
import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
import { isUserRelated } from '@/misc/is-user-related.js';
|
import { isUserRelated } from '@/misc/is-user-related.js';
|
||||||
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention' | 'edited';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention' | 'edited';
|
||||||
|
|
||||||
|
@ -244,8 +245,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
// we never want to change the replyId, so fetch the original "parent"
|
// we never want to change the replyId, so fetch the original "parent"
|
||||||
if (oldnote.replyId) {
|
if (oldnote.replyId) {
|
||||||
data.reply = await this.notesRepository.findOneBy({ id: oldnote.replyId });
|
data.reply = await this.notesRepository.findOneBy({ id: oldnote.replyId });
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
data.reply = undefined;
|
data.reply = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +284,7 @@ export class NoteEditService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
|
if (this.utilityService.isKeyWordIncluded(data.cw ?? data.text ?? '', meta.prohibitedWords)) {
|
||||||
throw new NoteEditService.ContainsProhibitedWordsError();
|
throw new IdentifiableError('689ee33f-f97c-479a-ac49-1b9f8140af99', 'Note contains prohibited words');
|
||||||
}
|
}
|
||||||
|
|
||||||
const inSilencedInstance = this.utilityService.isSilencedHost((meta).silencedHosts, user.host);
|
const inSilencedInstance = this.utilityService.isSilencedHost((meta).silencedHosts, user.host);
|
||||||
|
|
|
@ -92,46 +92,47 @@ export class NoteReadService implements OnApplicationShutdown {
|
||||||
userId: MiUser['id'],
|
userId: MiUser['id'],
|
||||||
notes: (MiNote | Packed<'Note'>)[],
|
notes: (MiNote | Packed<'Note'>)[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const readMentions: (MiNote | Packed<'Note'>)[] = [];
|
if (notes.length === 0) return;
|
||||||
const readSpecifiedNotes: (MiNote | Packed<'Note'>)[] = [];
|
|
||||||
|
const noteIds = new Set<MiNote['id']>();
|
||||||
|
|
||||||
for (const note of notes) {
|
for (const note of notes) {
|
||||||
if (note.mentions && note.mentions.includes(userId)) {
|
if (note.mentions && note.mentions.includes(userId)) {
|
||||||
readMentions.push(note);
|
noteIds.add(note.id);
|
||||||
} else if (note.visibleUserIds && note.visibleUserIds.includes(userId)) {
|
} else if (note.visibleUserIds && note.visibleUserIds.includes(userId)) {
|
||||||
readSpecifiedNotes.push(note);
|
noteIds.add(note.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((readMentions.length > 0) || (readSpecifiedNotes.length > 0)) {
|
if (noteIds.size === 0) return;
|
||||||
// Remove the record
|
|
||||||
await this.noteUnreadsRepository.delete({
|
|
||||||
userId: userId,
|
|
||||||
noteId: In([...readMentions.map(n => n.id), ...readSpecifiedNotes.map(n => n.id)]),
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: ↓まとめてクエリしたい
|
// Remove the record
|
||||||
|
await this.noteUnreadsRepository.delete({
|
||||||
|
userId: userId,
|
||||||
|
noteId: In(Array.from(noteIds)),
|
||||||
|
});
|
||||||
|
|
||||||
trackPromise(this.noteUnreadsRepository.countBy({
|
// TODO: ↓まとめてクエリしたい
|
||||||
userId: userId,
|
|
||||||
isMentioned: true,
|
|
||||||
}).then(mentionsCount => {
|
|
||||||
if (mentionsCount === 0) {
|
|
||||||
// 全て既読になったイベントを発行
|
|
||||||
this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions');
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
trackPromise(this.noteUnreadsRepository.countBy({
|
trackPromise(this.noteUnreadsRepository.countBy({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
isSpecified: true,
|
isMentioned: true,
|
||||||
}).then(specifiedCount => {
|
}).then(mentionsCount => {
|
||||||
if (specifiedCount === 0) {
|
if (mentionsCount === 0) {
|
||||||
// 全て既読になったイベントを発行
|
// 全て既読になったイベントを発行
|
||||||
this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
|
this.globalEventService.publishMainStream(userId, 'readAllUnreadMentions');
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
|
||||||
|
trackPromise(this.noteUnreadsRepository.countBy({
|
||||||
|
userId: userId,
|
||||||
|
isSpecified: true,
|
||||||
|
}).then(specifiedCount => {
|
||||||
|
if (specifiedCount === 0) {
|
||||||
|
// 全て既読になったイベントを発行
|
||||||
|
this.globalEventService.publishMainStream(userId, 'readAllUnreadSpecifiedNotes');
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -115,12 +115,19 @@ export class PushNotificationService implements OnApplicationShutdown {
|
||||||
endpoint: subscription.endpoint,
|
endpoint: subscription.endpoint,
|
||||||
auth: subscription.auth,
|
auth: subscription.auth,
|
||||||
publickey: subscription.publickey,
|
publickey: subscription.publickey,
|
||||||
|
}).then(() => {
|
||||||
|
this.refreshCache(userId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public refreshCache(userId: string): void {
|
||||||
|
this.subscriptionsCache.refresh(userId);
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public dispose(): void {
|
public dispose(): void {
|
||||||
this.subscriptionsCache.dispose();
|
this.subscriptionsCache.dispose();
|
||||||
|
|
|
@ -334,35 +334,36 @@ export class ReactionService {
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文字列タイプのレガシーな形式のリアクションを現在の形式に変換しつつ、
|
||||||
|
* データベース上には存在する「0個のリアクションがついている」という情報を削除する。
|
||||||
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public convertLegacyReactions(reactions: Record<string, number>) {
|
public convertLegacyReactions(reactions: MiNote['reactions']): MiNote['reactions'] {
|
||||||
const _reactions = {} as Record<string, number>;
|
return Object.entries(reactions)
|
||||||
|
.filter(([, count]) => {
|
||||||
|
// `ReactionService.prototype.delete`ではリアクション削除時に、
|
||||||
|
// `MiNote['reactions']`のエントリの値をデクリメントしているが、
|
||||||
|
// デクリメントしているだけなのでエントリ自体は0を値として持つ形で残り続ける。
|
||||||
|
// そのため、この処理がなければ、「0個のリアクションがついている」ということになってしまう。
|
||||||
|
return count > 0;
|
||||||
|
})
|
||||||
|
.map(([reaction, count]) => {
|
||||||
|
// unchecked indexed access
|
||||||
|
const convertedReaction = legacies[reaction] as string | undefined;
|
||||||
|
|
||||||
for (const reaction of Object.keys(reactions)) {
|
const key = this.decodeReaction(convertedReaction ?? reaction).reaction;
|
||||||
if (reactions[reaction] <= 0) continue;
|
|
||||||
|
|
||||||
if (Object.keys(legacies).includes(reaction)) {
|
return [key, count] as const;
|
||||||
if (_reactions[legacies[reaction]]) {
|
})
|
||||||
_reactions[legacies[reaction]] += reactions[reaction];
|
.reduce<MiNote['reactions']>((acc, [key, count]) => {
|
||||||
} else {
|
// unchecked indexed access
|
||||||
_reactions[legacies[reaction]] = reactions[reaction];
|
const prevCount = acc[key] as number | undefined;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (_reactions[reaction]) {
|
|
||||||
_reactions[reaction] += reactions[reaction];
|
|
||||||
} else {
|
|
||||||
_reactions[reaction] = reactions[reaction];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _reactions2 = {} as Record<string, number>;
|
acc[key] = (prevCount ?? 0) + count;
|
||||||
|
|
||||||
for (const reaction of Object.keys(_reactions)) {
|
return acc;
|
||||||
_reactions2[this.decodeReaction(reaction).reaction] = _reactions[reaction];
|
}, {});
|
||||||
}
|
|
||||||
|
|
||||||
return _reactions2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -30,6 +30,7 @@ import type { Config } from '@/config.js';
|
||||||
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
import { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
import { FanoutTimelineService } from '@/core/FanoutTimelineService.js';
|
||||||
|
import type { ThinUser } from '@/queue/types.js';
|
||||||
import Logger from '../logger.js';
|
import Logger from '../logger.js';
|
||||||
|
|
||||||
const logger = new Logger('following/create');
|
const logger = new Logger('following/create');
|
||||||
|
@ -94,20 +95,43 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
this.userBlockingService = this.moduleRef.get('UserBlockingService');
|
this.userBlockingService = this.moduleRef.get('UserBlockingService');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async deliverAccept(follower: MiRemoteUser, followee: MiPartialLocalUser, requestId?: string) {
|
||||||
|
const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
|
||||||
|
this.queueService.deliver(followee, content, follower.inbox, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ThinUserでなくともユーザーの情報が最新でない場合はこちらを使うべき
|
||||||
|
*/
|
||||||
|
@bindThis
|
||||||
|
public async followByThinUser(
|
||||||
|
_follower: ThinUser,
|
||||||
|
_followee: ThinUser,
|
||||||
|
options: Parameters<typeof this.follow>[2] = {},
|
||||||
|
) {
|
||||||
|
const [follower, followee] = await Promise.all([
|
||||||
|
this.usersRepository.findOneByOrFail({ id: _follower.id }),
|
||||||
|
this.usersRepository.findOneByOrFail({ id: _followee.id }),
|
||||||
|
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
|
||||||
|
|
||||||
|
await this.follow(follower, followee, options);
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async follow(
|
public async follow(
|
||||||
_follower: { id: MiUser['id'] },
|
follower: MiLocalUser | MiRemoteUser,
|
||||||
_followee: { id: MiUser['id'] },
|
followee: MiLocalUser | MiRemoteUser,
|
||||||
{ requestId, silent = false, withReplies }: {
|
{ requestId, silent = false, withReplies }: {
|
||||||
requestId?: string,
|
requestId?: string,
|
||||||
silent?: boolean,
|
silent?: boolean,
|
||||||
withReplies?: boolean,
|
withReplies?: boolean,
|
||||||
} = {},
|
} = {},
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const [follower, followee] = await Promise.all([
|
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isRemoteUser(followee)) {
|
||||||
this.usersRepository.findOneByOrFail({ id: _follower.id }),
|
// What?
|
||||||
this.usersRepository.findOneByOrFail({ id: _followee.id }),
|
throw new Error('Remote user cannot follow remote user.');
|
||||||
]) as [MiLocalUser | MiRemoteUser, MiLocalUser | MiRemoteUser];
|
}
|
||||||
|
|
||||||
// check blocking
|
// check blocking
|
||||||
const [blocking, blocked] = await Promise.all([
|
const [blocking, blocked] = await Promise.all([
|
||||||
|
@ -129,6 +153,24 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked');
|
if (blocked) throw new IdentifiableError('3338392a-f764-498d-8855-db939dcf8c48', 'blocked');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (await this.followingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
followerId: follower.id,
|
||||||
|
followeeId: followee.id,
|
||||||
|
},
|
||||||
|
})) {
|
||||||
|
// すでにフォロー関係が存在している場合
|
||||||
|
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||||
|
// リモート → ローカル: acceptを送り返しておしまい
|
||||||
|
this.deliverAccept(follower, followee, requestId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.userEntityService.isLocalUser(follower)) {
|
||||||
|
// ローカル → リモート/ローカル: 例外
|
||||||
|
throw new IdentifiableError('ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced', 'already following');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
const followeeProfile = await this.userProfilesRepository.findOneByOrFail({ userId: followee.id });
|
||||||
// フォロー対象が鍵アカウントである or
|
// フォロー対象が鍵アカウントである or
|
||||||
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
// フォロワーがBotであり、フォロー対象がBotからのフォローに慎重である or
|
||||||
|
@ -189,8 +231,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
await this.insertFollowingDoc(followee, follower, silent, withReplies);
|
await this.insertFollowingDoc(followee, follower, silent, withReplies);
|
||||||
|
|
||||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||||
const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee, requestId), followee));
|
this.deliverAccept(follower, followee, requestId);
|
||||||
this.queueService.deliver(followee, content, follower.inbox, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,8 +612,7 @@ export class UserFollowingService implements OnModuleInit {
|
||||||
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
|
await this.insertFollowingDoc(followee, follower, false, request.withReplies);
|
||||||
|
|
||||||
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
if (this.userEntityService.isRemoteUser(follower) && this.userEntityService.isLocalUser(followee)) {
|
||||||
const content = this.apRendererService.addContext(this.apRendererService.renderAccept(this.apRendererService.renderFollow(follower, followee as MiPartialLocalUser, request.requestId!), followee));
|
this.deliverAccept(follower, followee as MiPartialLocalUser, request.requestId ?? undefined);
|
||||||
this.queueService.deliver(followee, content, follower.inbox, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.userEntityService.pack(followee.id, followee, {
|
this.userEntityService.pack(followee.id, followee, {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit';
|
||||||
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
import type { MiRemoteUser, MiUser } from '@/models/User.js';
|
||||||
import { concat, unique } from '@/misc/prelude/array.js';
|
import { concat, unique } from '@/misc/prelude/array.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { getApIds } from './type.js';
|
import { getApIds } from './type.js';
|
||||||
import { ApPersonService } from './models/ApPersonService.js';
|
import { ApPersonService } from './models/ApPersonService.js';
|
||||||
import type { ApObject } from './type.js';
|
import type { ApObject } from './type.js';
|
||||||
|
@ -40,7 +41,7 @@ export class ApAudienceService {
|
||||||
const limit = promiseLimit<MiUser | null>(2);
|
const limit = promiseLimit<MiUser | null>(2);
|
||||||
const mentionedUsers = (await Promise.all(
|
const mentionedUsers = (await Promise.all(
|
||||||
others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
|
others.map(id => limit(() => this.apPersonService.resolvePerson(id, resolver).catch(() => null))),
|
||||||
)).filter((x): x is MiUser => x != null);
|
)).filter(isNotNull);
|
||||||
|
|
||||||
if (toGroups.public.length > 0) {
|
if (toGroups.public.length > 0) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -27,6 +27,7 @@ import { QueueService } from '@/core/QueueService.js';
|
||||||
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js';
|
import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserReportsRepository, FollowRequestsRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { MiRemoteUser } from '@/models/User.js';
|
import type { MiRemoteUser } from '@/models/User.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||||
import { ApNoteService } from './models/ApNoteService.js';
|
import { ApNoteService } from './models/ApNoteService.js';
|
||||||
import { ApLoggerService } from './ApLoggerService.js';
|
import { ApLoggerService } from './ApLoggerService.js';
|
||||||
|
@ -84,7 +85,6 @@ export class ApInboxService {
|
||||||
private apPersonService: ApPersonService,
|
private apPersonService: ApPersonService,
|
||||||
private apQuestionService: ApQuestionService,
|
private apQuestionService: ApQuestionService,
|
||||||
private queueService: QueueService,
|
private queueService: QueueService,
|
||||||
private cacheService: CacheService,
|
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
) {
|
) {
|
||||||
this.logger = this.apLoggerService.logger;
|
this.logger = this.apLoggerService.logger;
|
||||||
|
@ -521,7 +521,7 @@ export class ApInboxService {
|
||||||
const userIds = uris
|
const userIds = uris
|
||||||
.filter(uri => uri.startsWith(this.config.url + '/users/'))
|
.filter(uri => uri.startsWith(this.config.url + '/users/'))
|
||||||
.map(uri => uri.split('/').at(-1))
|
.map(uri => uri.split('/').at(-1))
|
||||||
.filter((userId): userId is string => userId !== undefined);
|
.filter(isNotNull);
|
||||||
const users = await this.usersRepository.findBy({
|
const users = await this.usersRepository.findBy({
|
||||||
id: In(userIds),
|
id: In(userIds),
|
||||||
});
|
});
|
||||||
|
|
|
@ -335,7 +335,7 @@ export class ApRendererService {
|
||||||
const getPromisedFiles = async (ids: string[]): Promise<MiDriveFile[]> => {
|
const getPromisedFiles = async (ids: string[]): Promise<MiDriveFile[]> => {
|
||||||
if (ids.length === 0) return [];
|
if (ids.length === 0) return [];
|
||||||
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
|
const items = await this.driveFilesRepository.findBy({ id: In(ids) });
|
||||||
return ids.map(id => items.find(item => item.id === id)).filter((item): item is MiDriveFile => item != null);
|
return ids.map(id => items.find(item => item.id === id)).filter(isNotNull);
|
||||||
};
|
};
|
||||||
|
|
||||||
let inReplyTo;
|
let inReplyTo;
|
||||||
|
|
|
@ -8,6 +8,7 @@ import promiseLimit from 'promise-limit';
|
||||||
import type { MiUser } from '@/models/_.js';
|
import type { MiUser } from '@/models/_.js';
|
||||||
import { toArray, unique } from '@/misc/prelude/array.js';
|
import { toArray, unique } from '@/misc/prelude/array.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { isMention } from '../type.js';
|
import { isMention } from '../type.js';
|
||||||
import { Resolver } from '../ApResolverService.js';
|
import { Resolver } from '../ApResolverService.js';
|
||||||
import { ApPersonService } from './ApPersonService.js';
|
import { ApPersonService } from './ApPersonService.js';
|
||||||
|
@ -27,7 +28,7 @@ export class ApMentionService {
|
||||||
const limit = promiseLimit<MiUser | null>(2);
|
const limit = promiseLimit<MiUser | null>(2);
|
||||||
const mentionedUsers = (await Promise.all(
|
const mentionedUsers = (await Promise.all(
|
||||||
hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))),
|
hrefs.map(x => limit(() => this.apPersonService.resolvePerson(x, resolver).catch(() => null))),
|
||||||
)).filter((x): x is MiUser => x != null);
|
)).filter(isNotNull);
|
||||||
|
|
||||||
return mentionedUsers;
|
return mentionedUsers;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import { ApQuestionService } from './ApQuestionService.js';
|
||||||
import { ApImageService } from './ApImageService.js';
|
import { ApImageService } from './ApImageService.js';
|
||||||
import type { Resolver } from '../ApResolverService.js';
|
import type { Resolver } from '../ApResolverService.js';
|
||||||
import type { IObject, IPost } from '../type.js';
|
import type { IObject, IPost } from '../type.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApNoteService {
|
export class ApNoteService {
|
||||||
|
@ -226,7 +227,7 @@ export class ApNoteService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const uris = unique([note._misskey_quote, note.quoteUrl, note.quoteUri].filter((x): x is string => typeof x === 'string'));
|
const uris = unique([note._misskey_quote, note.quoteUrl, note.quoteUri].filter(isNotNull));
|
||||||
const results = await Promise.all(uris.map(tryResolveNote));
|
const results = await Promise.all(uris.map(tryResolveNote));
|
||||||
|
|
||||||
quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0);
|
quote = results.filter((x): x is { status: 'ok', res: MiNote } => x.status === 'ok').map(x => x.res).at(0);
|
||||||
|
|
|
@ -38,6 +38,7 @@ import { MetaService } from '@/core/MetaService.js';
|
||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
|
||||||
import type { AccountMoveService } from '@/core/AccountMoveService.js';
|
import type { AccountMoveService } from '@/core/AccountMoveService.js';
|
||||||
import { checkHttps } from '@/misc/check-https.js';
|
import { checkHttps } from '@/misc/check-https.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
|
import { getApId, getApType, getOneApHrefNullable, isActor, isCollection, isCollectionOrOrderedCollection, isPropertyValue } from '../type.js';
|
||||||
import { extractApHashtags } from './tag.js';
|
import { extractApHashtags } from './tag.js';
|
||||||
import type { OnModuleInit } from '@nestjs/common';
|
import type { OnModuleInit } from '@nestjs/common';
|
||||||
|
@ -659,7 +660,7 @@ export class ApPersonService implements OnModuleInit {
|
||||||
|
|
||||||
// とりあえずidを別の時間で生成して順番を維持
|
// とりあえずidを別の時間で生成して順番を維持
|
||||||
let td = 0;
|
let td = 0;
|
||||||
for (const note of featuredNotes.filter((note): note is MiNote => note != null)) {
|
for (const note of featuredNotes.filter(isNotNull)) {
|
||||||
td -= 1000;
|
td -= 1000;
|
||||||
transactionalEntityManager.insert(MiUserNotePining, {
|
transactionalEntityManager.insert(MiUserNotePining, {
|
||||||
id: this.idService.gen(Date.now() + td),
|
id: this.idService.gen(Date.now() + td),
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { Config } from '@/config.js';
|
||||||
import type { IPoll } from '@/models/Poll.js';
|
import type { IPoll } from '@/models/Poll.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { isQuestion } from '../type.js';
|
import { isQuestion } from '../type.js';
|
||||||
import { ApLoggerService } from '../ApLoggerService.js';
|
import { ApLoggerService } from '../ApLoggerService.js';
|
||||||
import { ApResolverService } from '../ApResolverService.js';
|
import { ApResolverService } from '../ApResolverService.js';
|
||||||
|
@ -51,7 +52,7 @@ export class ApQuestionService {
|
||||||
|
|
||||||
const choices = question[multiple ? 'anyOf' : 'oneOf']
|
const choices = question[multiple ? 'anyOf' : 'oneOf']
|
||||||
?.map((x) => x.name)
|
?.map((x) => x.name)
|
||||||
.filter((x): x is string => typeof x === 'string')
|
.filter(isNotNull)
|
||||||
?? [];
|
?? [];
|
||||||
|
|
||||||
const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0);
|
const votes = question[multiple ? 'anyOf' : 'oneOf']?.map((x) => x.replies?.totalItems ?? x._misskey_votes ?? 0);
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { toArray } from '@/misc/prelude/array.js';
|
import { toArray } from '@/misc/prelude/array.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { isHashtag } from '../type.js';
|
import { isHashtag } from '../type.js';
|
||||||
import type { IObject, IApHashtag } from '../type.js';
|
import type { IObject, IApHashtag } from '../type.js';
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ export function extractApHashtags(tags: IObject | IObject[] | null | undefined):
|
||||||
return hashtags.map(tag => {
|
return hashtags.map(tag => {
|
||||||
const m = tag.name.match(/^#(.+)/);
|
const m = tag.name.match(/^#(.+)/);
|
||||||
return m ? m[1] : null;
|
return m ? m[1] : null;
|
||||||
}).filter((x): x is string => x != null);
|
}).filter(isNotNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] {
|
export function extractApHashtagObjects(tags: IObject | IObject[] | null | undefined): IApHashtag[] {
|
||||||
|
|
|
@ -259,7 +259,7 @@ export class DriveFileEntityService {
|
||||||
options?: PackOptions,
|
options?: PackOptions,
|
||||||
): Promise<Packed<'DriveFile'>[]> {
|
): Promise<Packed<'DriveFile'>[]> {
|
||||||
const items = await Promise.all(files.map(f => this.packNullable(f, options)));
|
const items = await Promise.all(files.map(f => this.packNullable(f, options)));
|
||||||
return items.filter((x): x is Packed<'DriveFile'> => x != null);
|
return items.filter(isNotNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -8,12 +8,15 @@ import type { Packed } from '@/misc/json-schema.js';
|
||||||
import type { MiInstance } from '@/models/Instance.js';
|
import type { MiInstance } from '@/models/Instance.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { UtilityService } from '../UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
import { MiUser } from '@/models/User.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class InstanceEntityService {
|
export class InstanceEntityService {
|
||||||
constructor(
|
constructor(
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
|
private roleService: RoleService,
|
||||||
|
|
||||||
private utilityService: UtilityService,
|
private utilityService: UtilityService,
|
||||||
) {
|
) {
|
||||||
|
@ -22,8 +25,11 @@ export class InstanceEntityService {
|
||||||
@bindThis
|
@bindThis
|
||||||
public async pack(
|
public async pack(
|
||||||
instance: MiInstance,
|
instance: MiInstance,
|
||||||
|
me?: { id: MiUser['id']; } | null | undefined,
|
||||||
): Promise<Packed<'FederationInstance'>> {
|
): Promise<Packed<'FederationInstance'>> {
|
||||||
const meta = await this.metaService.fetch();
|
const meta = await this.metaService.fetch();
|
||||||
|
const iAmModerator = me ? await this.roleService.isModerator(me as MiUser) : false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: instance.id,
|
id: instance.id,
|
||||||
firstRetrievedAt: instance.firstRetrievedAt.toISOString(),
|
firstRetrievedAt: instance.firstRetrievedAt.toISOString(),
|
||||||
|
@ -49,6 +55,7 @@ export class InstanceEntityService {
|
||||||
infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null,
|
infoUpdatedAt: instance.infoUpdatedAt ? instance.infoUpdatedAt.toISOString() : null,
|
||||||
latestRequestReceivedAt: instance.latestRequestReceivedAt ? instance.latestRequestReceivedAt.toISOString() : null,
|
latestRequestReceivedAt: instance.latestRequestReceivedAt ? instance.latestRequestReceivedAt.toISOString() : null,
|
||||||
isNSFW: instance.isNSFW,
|
isNSFW: instance.isNSFW,
|
||||||
|
moderationNote: iAmModerator ? instance.moderationNote : null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
157
packages/backend/src/core/entities/MetaEntityService.ts
Normal file
157
packages/backend/src/core/entities/MetaEntityService.ts
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Brackets } from 'typeorm';
|
||||||
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import JSON5 from 'json5';
|
||||||
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
|
import type { MiMeta } from '@/models/Meta.js';
|
||||||
|
import type { AdsRepository } from '@/models/_.js';
|
||||||
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
|
import { InstanceActorService } from '@/core/InstanceActorService.js';
|
||||||
|
import type { Config } from '@/config.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MetaEntityService {
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
|
@Inject(DI.adsRepository)
|
||||||
|
private adsRepository: AdsRepository,
|
||||||
|
|
||||||
|
private userEntityService: UserEntityService,
|
||||||
|
private metaService: MetaService,
|
||||||
|
private instanceActorService: InstanceActorService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async pack(meta?: MiMeta): Promise<Packed<'MetaLite'>> {
|
||||||
|
let instance = meta;
|
||||||
|
|
||||||
|
if (!instance) {
|
||||||
|
instance = await this.metaService.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ads = await this.adsRepository.createQueryBuilder('ads')
|
||||||
|
.where('ads.expiresAt > :now', { now: new Date() })
|
||||||
|
.andWhere('ads.startsAt <= :now', { now: new Date() })
|
||||||
|
.andWhere(new Brackets(qb => {
|
||||||
|
// 曜日のビットフラグを確認する
|
||||||
|
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
|
||||||
|
.orWhere('ads.dayOfWeek = 0');
|
||||||
|
}))
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
const packed: Packed<'MetaLite'> = {
|
||||||
|
maintainerName: instance.maintainerName,
|
||||||
|
maintainerEmail: instance.maintainerEmail,
|
||||||
|
|
||||||
|
version: this.config.version,
|
||||||
|
providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl,
|
||||||
|
|
||||||
|
name: instance.name,
|
||||||
|
shortName: instance.shortName,
|
||||||
|
uri: this.config.url,
|
||||||
|
description: instance.description,
|
||||||
|
langs: instance.langs,
|
||||||
|
tosUrl: instance.termsOfServiceUrl,
|
||||||
|
repositoryUrl: instance.repositoryUrl,
|
||||||
|
feedbackUrl: instance.feedbackUrl,
|
||||||
|
impressumUrl: instance.impressumUrl,
|
||||||
|
donationUrl: instance.donationUrl,
|
||||||
|
privacyPolicyUrl: instance.privacyPolicyUrl,
|
||||||
|
disableRegistration: instance.disableRegistration,
|
||||||
|
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||||
|
approvalRequiredForSignup: instance.approvalRequiredForSignup,
|
||||||
|
enableHcaptcha: instance.enableHcaptcha,
|
||||||
|
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
||||||
|
enableMcaptcha: instance.enableMcaptcha,
|
||||||
|
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
||||||
|
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
||||||
|
enableRecaptcha: instance.enableRecaptcha,
|
||||||
|
enableAchievements: instance.enableAchievements,
|
||||||
|
recaptchaSiteKey: instance.recaptchaSiteKey,
|
||||||
|
enableTurnstile: instance.enableTurnstile,
|
||||||
|
turnstileSiteKey: instance.turnstileSiteKey,
|
||||||
|
swPublickey: instance.swPublicKey,
|
||||||
|
themeColor: instance.themeColor,
|
||||||
|
mascotImageUrl: instance.mascotImageUrl ?? '/assets/ai.png',
|
||||||
|
bannerUrl: instance.bannerUrl,
|
||||||
|
infoImageUrl: instance.infoImageUrl,
|
||||||
|
serverErrorImageUrl: instance.serverErrorImageUrl,
|
||||||
|
notFoundImageUrl: instance.notFoundImageUrl,
|
||||||
|
iconUrl: instance.iconUrl,
|
||||||
|
backgroundImageUrl: instance.backgroundImageUrl,
|
||||||
|
logoImageUrl: instance.logoImageUrl,
|
||||||
|
maxNoteTextLength: this.config.maxNoteLength,
|
||||||
|
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
||||||
|
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
|
||||||
|
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
|
||||||
|
defaultLike: instance.defaultLike,
|
||||||
|
ads: ads.map(ad => ({
|
||||||
|
id: ad.id,
|
||||||
|
url: ad.url,
|
||||||
|
place: ad.place,
|
||||||
|
ratio: ad.ratio,
|
||||||
|
imageUrl: ad.imageUrl,
|
||||||
|
dayOfWeek: ad.dayOfWeek,
|
||||||
|
})),
|
||||||
|
notesPerOneAd: instance.notesPerOneAd,
|
||||||
|
enableEmail: instance.enableEmail,
|
||||||
|
enableServiceWorker: instance.enableServiceWorker,
|
||||||
|
|
||||||
|
translatorAvailable: instance.deeplAuthKey != null || instance.deeplFreeMode && instance.deeplFreeInstance != null,
|
||||||
|
|
||||||
|
serverRules: instance.serverRules,
|
||||||
|
|
||||||
|
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||||
|
|
||||||
|
mediaProxy: this.config.mediaProxy,
|
||||||
|
};
|
||||||
|
|
||||||
|
return packed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async packDetailed(meta?: MiMeta): Promise<Packed<'MetaDetailed'>> {
|
||||||
|
let instance = meta;
|
||||||
|
|
||||||
|
if (!instance) {
|
||||||
|
instance = await this.metaService.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
const packed = await this.pack(instance);
|
||||||
|
|
||||||
|
const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null;
|
||||||
|
|
||||||
|
const packDetailed: Packed<'MetaDetailed'> = {
|
||||||
|
...packed,
|
||||||
|
cacheRemoteFiles: instance.cacheRemoteFiles,
|
||||||
|
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
||||||
|
requireSetup: !await this.instanceActorService.realLocalUsersPresent(),
|
||||||
|
proxyAccountName: proxyAccount ? proxyAccount.username : null,
|
||||||
|
features: {
|
||||||
|
localTimeline: instance.policies.ltlAvailable,
|
||||||
|
globalTimeline: instance.policies.gtlAvailable,
|
||||||
|
registration: !instance.disableRegistration,
|
||||||
|
emailRequiredForSignup: instance.emailRequiredForSignup,
|
||||||
|
hcaptcha: instance.enableHcaptcha,
|
||||||
|
recaptcha: instance.enableRecaptcha,
|
||||||
|
turnstile: instance.enableTurnstile,
|
||||||
|
objectStorage: instance.useObjectStorage,
|
||||||
|
serviceWorker: instance.enableServiceWorker,
|
||||||
|
miauth: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return packDetailed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import type { MiPage } from '@/models/Page.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import { UserEntityService } from './UserEntityService.js';
|
import { UserEntityService } from './UserEntityService.js';
|
||||||
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
import { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||||
|
|
||||||
|
@ -102,7 +103,7 @@ export class PageEntityService {
|
||||||
script: page.script,
|
script: page.script,
|
||||||
eyeCatchingImageId: page.eyeCatchingImageId,
|
eyeCatchingImageId: page.eyeCatchingImageId,
|
||||||
eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null,
|
eyeCatchingImage: page.eyeCatchingImageId ? await this.driveFileEntityService.pack(page.eyeCatchingImageId) : null,
|
||||||
attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter((x): x is MiDriveFile => x != null)),
|
attachedFiles: this.driveFileEntityService.packMany((await Promise.all(attachedFiles)).filter(isNotNull)),
|
||||||
likedCount: page.likedCount,
|
likedCount: page.likedCount,
|
||||||
isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined,
|
isLiked: meId ? await this.pageLikesRepository.exists({ where: { pageId: page.id, userId: meId } }) : undefined,
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { IdService } from '@/core/IdService.js';
|
||||||
import type { AnnouncementService } from '@/core/AnnouncementService.js';
|
import type { AnnouncementService } from '@/core/AnnouncementService.js';
|
||||||
import type { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
import type { CustomEmojiService } from '@/core/CustomEmojiService.js';
|
||||||
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
import { AvatarDecorationService } from '@/core/AvatarDecorationService.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
import type { OnModuleInit } from '@nestjs/common';
|
import type { OnModuleInit } from '@nestjs/common';
|
||||||
import type { NoteEntityService } from './NoteEntityService.js';
|
import type { NoteEntityService } from './NoteEntityService.js';
|
||||||
import type { DriveFileEntityService } from './DriveFileEntityService.js';
|
import type { DriveFileEntityService } from './DriveFileEntityService.js';
|
||||||
|
@ -423,7 +424,7 @@ export class UserEntityService implements OnModuleInit {
|
||||||
movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null,
|
movedTo: user.movedToUri ? this.apPersonService.resolvePerson(user.movedToUri).then(user => user.id).catch(() => null) : null,
|
||||||
alsoKnownAs: user.alsoKnownAs
|
alsoKnownAs: user.alsoKnownAs
|
||||||
? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null)))
|
? Promise.all(user.alsoKnownAs.map(uri => this.apPersonService.fetchPerson(uri).then(user => user?.id).catch(() => null)))
|
||||||
.then(xs => xs.length === 0 ? null : xs.filter(x => x != null) as string[])
|
.then(xs => xs.length === 0 ? null : xs.filter(isNotNull))
|
||||||
: null,
|
: null,
|
||||||
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
|
updatedAt: user.updatedAt ? user.updatedAt.toISOString() : null,
|
||||||
lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
|
lastFetchedAt: user.lastFetchedAt ? user.lastFetchedAt.toISOString() : null,
|
||||||
|
|
|
@ -3,8 +3,6 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// we are using {} as "any non-nullish value" as expected
|
export function isNotNull<T extends NonNullable<unknown>>(input: T | undefined | null): input is T {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
||||||
export function isNotNull<T extends {}>(input: T | undefined | null): input is T {
|
|
||||||
return input != null;
|
return input != null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,11 @@ import {
|
||||||
} from '@/models/json-schema/role.js';
|
} from '@/models/json-schema/role.js';
|
||||||
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
import { packedAdSchema } from '@/models/json-schema/ad.js';
|
||||||
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
import { packedReversiGameLiteSchema, packedReversiGameDetailedSchema } from '@/models/json-schema/reversi-game.js';
|
||||||
|
import {
|
||||||
|
packedMetaLiteSchema,
|
||||||
|
packedMetaDetailedOnlySchema,
|
||||||
|
packedMetaDetailedSchema,
|
||||||
|
} from '@/models/json-schema/meta.js';
|
||||||
|
|
||||||
export const refs = {
|
export const refs = {
|
||||||
UserLite: packedUserLiteSchema,
|
UserLite: packedUserLiteSchema,
|
||||||
|
@ -99,6 +104,9 @@ export const refs = {
|
||||||
RolePolicies: packedRolePoliciesSchema,
|
RolePolicies: packedRolePoliciesSchema,
|
||||||
ReversiGameLite: packedReversiGameLiteSchema,
|
ReversiGameLite: packedReversiGameLiteSchema,
|
||||||
ReversiGameDetailed: packedReversiGameDetailedSchema,
|
ReversiGameDetailed: packedReversiGameDetailedSchema,
|
||||||
|
MetaLite: packedMetaLiteSchema,
|
||||||
|
MetaDetailedOnly: packedMetaDetailedOnlySchema,
|
||||||
|
MetaDetailed: packedMetaDetailedSchema,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
|
export type Packed<x extends keyof typeof refs> = SchemaType<typeof refs[x]>;
|
||||||
|
|
|
@ -149,4 +149,9 @@ export class MiInstance {
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
public isNSFW: boolean;
|
public isNSFW: boolean;
|
||||||
|
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 16384, default: '',
|
||||||
|
})
|
||||||
|
public moderationNote: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,5 +112,9 @@ export const packedFederationInstanceSchema = {
|
||||||
optional: false,
|
optional: false,
|
||||||
nullable: false,
|
nullable: false,
|
||||||
},
|
},
|
||||||
|
moderationNote: {
|
||||||
|
type: 'string',
|
||||||
|
optional: true, nullable: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
344
packages/backend/src/models/json-schema/meta.ts
Normal file
344
packages/backend/src/models/json-schema/meta.ts
Normal file
|
@ -0,0 +1,344 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const packedMetaLiteSchema = {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
maintainerName: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
maintainerEmail: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
providesTarball: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
shortName: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
uri: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'url',
|
||||||
|
example: 'https://misskey.example.com',
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
langs: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
tosUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
repositoryUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
default: 'https://github.com/misskey-dev/misskey',
|
||||||
|
},
|
||||||
|
feedbackUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
||||||
|
},
|
||||||
|
donationUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
defaultDarkTheme: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
defaultLightTheme: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
defaultLike: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
disableRegistration: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
emailRequiredForSignup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
approvalRequiredForSignup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
enableHcaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
hcaptchaSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableMcaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
mcaptchaSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
mcaptchaInstanceUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableRecaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
recaptchaSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableTurnstile: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
turnstileSiteKey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
enableAchievements: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
swPublickey: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
mascotImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
default: '/assets/ai.png',
|
||||||
|
},
|
||||||
|
bannerUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
serverErrorImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
infoImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
notFoundImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
iconUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
maxNoteTextLength: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
ads: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
id: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'url',
|
||||||
|
},
|
||||||
|
place: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
ratio: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
imageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
format: 'url',
|
||||||
|
},
|
||||||
|
dayOfWeek: {
|
||||||
|
type: 'integer',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
notesPerOneAd: {
|
||||||
|
type: 'number',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
enableEmail: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
enableServiceWorker: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
translatorAvailable: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
mediaProxy: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
backgroundImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
impressumUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
logoImageUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
privacyPolicyUrl: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
serverRules: {
|
||||||
|
type: 'array',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
items: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
themeColor: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
policies: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'RolePolicies',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const packedMetaDetailedOnlySchema = {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
properties: {
|
||||||
|
features: {
|
||||||
|
type: 'object',
|
||||||
|
optional: true, nullable: false,
|
||||||
|
properties: {
|
||||||
|
registration: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
emailRequiredForSignup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
localTimeline: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
globalTimeline: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
hcaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
turnstile: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
recaptcha: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
objectStorage: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
serviceWorker: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
miauth: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: true, nullable: false,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
proxyAccountName: {
|
||||||
|
type: 'string',
|
||||||
|
optional: false, nullable: true,
|
||||||
|
},
|
||||||
|
requireSetup: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
example: false,
|
||||||
|
},
|
||||||
|
cacheRemoteFiles: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
cacheRemoteSensitiveFiles: {
|
||||||
|
type: 'boolean',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const packedMetaDetailedSchema = {
|
||||||
|
type: 'object',
|
||||||
|
allOf: [
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
ref: 'MetaLite',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
ref: 'MetaDetailedOnly',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as const;
|
|
@ -24,6 +24,7 @@ import { ApPersonService } from '@/core/activitypub/models/ApPersonService.js';
|
||||||
import { LdSignatureService } from '@/core/activitypub/LdSignatureService.js';
|
import { LdSignatureService } from '@/core/activitypub/LdSignatureService.js';
|
||||||
import { ApInboxService } from '@/core/activitypub/ApInboxService.js';
|
import { ApInboxService } from '@/core/activitypub/ApInboxService.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
import { QueueLoggerService } from '../QueueLoggerService.js';
|
||||||
import type { InboxJobData } from '../types.js';
|
import type { InboxJobData } from '../types.js';
|
||||||
|
|
||||||
|
@ -191,7 +192,14 @@ export class InboxProcessorService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// アクティビティを処理
|
// アクティビティを処理
|
||||||
await this.apInboxService.performActivity(authUser.user, activity);
|
try {
|
||||||
|
await this.apInboxService.performActivity(authUser.user, activity);
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof IdentifiableError) {
|
||||||
|
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') return 'blocked notes with prohibited words';
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
return 'ok';
|
return 'ok';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ export class RelationshipProcessorService {
|
||||||
@bindThis
|
@bindThis
|
||||||
public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> {
|
public async processFollow(job: Bull.Job<RelationshipJobData>): Promise<string> {
|
||||||
this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? "with replies" : "without replies"}`);
|
this.logger.info(`${job.data.from.id} is trying to follow ${job.data.to.id} ${job.data.withReplies ? "with replies" : "without replies"}`);
|
||||||
await this.userFollowingService.follow(job.data.from, job.data.to, {
|
await this.userFollowingService.followByThinUser(job.data.from, job.data.to, {
|
||||||
requestId: job.data.requestId,
|
requestId: job.data.requestId,
|
||||||
silent: job.data.silent,
|
silent: job.data.silent,
|
||||||
withReplies: job.data.withReplies,
|
withReplies: job.data.withReplies,
|
||||||
|
|
|
@ -25,6 +25,7 @@ export const paramDef = {
|
||||||
host: { type: 'string' },
|
host: { type: 'string' },
|
||||||
isSuspended: { type: 'boolean' },
|
isSuspended: { type: 'boolean' },
|
||||||
isNSFW: { type: 'boolean' },
|
isNSFW: { type: 'boolean' },
|
||||||
|
moderationNote: { type: 'string' },
|
||||||
},
|
},
|
||||||
required: ['host'],
|
required: ['host'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -46,29 +47,32 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new Error('instance not found');
|
throw new Error('instance not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.isSuspended != null) {
|
await this.federatedInstanceService.update(instance.id, {
|
||||||
await this.federatedInstanceService.update(instance.id, {
|
isSuspended: ps.isSuspended,
|
||||||
isSuspended: ps.isSuspended,
|
isNSFW: ps.isNSFW,
|
||||||
});
|
moderationNote: ps.moderationNote,
|
||||||
|
});
|
||||||
|
|
||||||
if (instance.isSuspended !== ps.isSuspended) {
|
if (ps.isSuspended != null && instance.isSuspended !== ps.isSuspended) {
|
||||||
if (ps.isSuspended) {
|
if (ps.isSuspended) {
|
||||||
this.moderationLogService.log(me, 'suspendRemoteInstance', {
|
this.moderationLogService.log(me, 'suspendRemoteInstance', {
|
||||||
id: instance.id,
|
id: instance.id,
|
||||||
host: instance.host,
|
host: instance.host,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.moderationLogService.log(me, 'unsuspendRemoteInstance', {
|
this.moderationLogService.log(me, 'unsuspendRemoteInstance', {
|
||||||
id: instance.id,
|
id: instance.id,
|
||||||
host: instance.host,
|
host: instance.host,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ps.isNSFW != null) {
|
if (ps.moderationNote != null && instance.moderationNote !== ps.moderationNote) {
|
||||||
await this.federatedInstanceService.update(instance.id, {
|
this.moderationLogService.log(me, 'updateRemoteInstanceNote', {
|
||||||
isNSFW: ps.isNSFW,
|
id: instance.id,
|
||||||
|
host: instance.host,
|
||||||
|
before: instance.moderationNote,
|
||||||
|
after: ps.moderationNote,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -124,9 +124,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
notes.sort((a, b) => a.id > b.id ? -1 : 1);
|
notes.sort((a, b) => a.id > b.id ? -1 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notes.length > 0) {
|
this.noteReadService.read(me.id, notes);
|
||||||
this.noteReadService.read(me.id, notes);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.noteEntityService.packMany(notes, me);
|
return await this.noteEntityService.packMany(notes, me);
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const instance = await this.instancesRepository
|
const instance = await this.instancesRepository
|
||||||
.findOneBy({ host: this.utilityService.toPuny(ps.host) });
|
.findOneBy({ host: this.utilityService.toPuny(ps.host) });
|
||||||
|
|
||||||
return instance ? await this.instanceEntityService.pack(instance) : null;
|
return instance ? await this.instanceEntityService.pack(instance, me) : null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ export const paramDef = {
|
||||||
} },
|
} },
|
||||||
visibility: { type: 'string', enum: ['public', 'private'] },
|
visibility: { type: 'string', enum: ['public', 'private'] },
|
||||||
},
|
},
|
||||||
required: ['flashId', 'title', 'summary', 'script', 'permissions'],
|
required: ['flashId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -71,11 +71,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
await this.flashsRepository.update(flash.id, {
|
await this.flashsRepository.update(flash.id, {
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
title: ps.title,
|
...Object.fromEntries(
|
||||||
summary: ps.summary,
|
Object.entries(ps).filter(
|
||||||
script: ps.script,
|
([key, val]) => (key !== 'flashId') && Object.hasOwn(paramDef.properties, key)
|
||||||
permissions: ps.permissions,
|
)
|
||||||
visibility: ps.visibility,
|
),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,22 +100,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if already following
|
|
||||||
const exist = await this.followingsRepository.exists({
|
|
||||||
where: {
|
|
||||||
followerId: follower.id,
|
|
||||||
followeeId: followee.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (exist) {
|
|
||||||
throw new ApiError(meta.errors.alreadyFollowing);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
|
await this.userFollowingService.follow(follower, followee, { withReplies: ps.withReplies });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof IdentifiableError) {
|
if (e instanceof IdentifiableError) {
|
||||||
|
if (e.id === 'ec3f65c0-a9d1-47d9-8791-b2e7b9dcdced') throw new ApiError(meta.errors.alreadyFollowing);
|
||||||
if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking);
|
if (e.id === '710e8fb0-b8c3-4922-be49-d5d93d8e6a6e') throw new ApiError(meta.errors.blocking);
|
||||||
if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked);
|
if (e.id === '3338392a-f764-498d-8855-db939dcf8c48') throw new ApiError(meta.errors.blocked);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['gallery'],
|
tags: ['gallery'],
|
||||||
|
@ -69,7 +70,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
id: fileId,
|
id: fileId,
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
}),
|
}),
|
||||||
))).filter((file): file is MiDriveFile => file != null);
|
))).filter(isNotNull);
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
|
|
|
@ -10,6 +10,7 @@ import type { DriveFilesRepository, GalleryPostsRepository } from '@/models/_.js
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['gallery'],
|
tags: ['gallery'],
|
||||||
|
@ -67,7 +68,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
id: fileId,
|
id: fileId,
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
}),
|
}),
|
||||||
))).filter((file): file is MiDriveFile => file != null);
|
))).filter(isNotNull);
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
|
|
|
@ -43,7 +43,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const hashtags = await this.hashtagsRepository.createQueryBuilder('tag')
|
const hashtags = await this.hashtagsRepository.createQueryBuilder('tag')
|
||||||
.where('tag.name like :q', { q: sqlLikeEscape(ps.query.toLowerCase()) + '%' })
|
.where('tag.name like :q', { q: sqlLikeEscape(ps.query.toLowerCase()) + '%' })
|
||||||
.orderBy('tag.count', 'DESC')
|
.orderBy('tag.mentionedLocalUsersCount', 'DESC')
|
||||||
.groupBy('tag.id')
|
.groupBy('tag.id')
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
.offset(ps.offset)
|
.offset(ps.offset)
|
||||||
|
|
|
@ -3,17 +3,9 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { IsNull, LessThanOrEqual, MoreThan, Brackets } from 'typeorm';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import JSON5 from 'json5';
|
|
||||||
import type { AdsRepository } from '@/models/_.js';
|
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { MetaEntityService } from '@/core/entities/MetaEntityService.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
|
||||||
import { InstanceActorService } from '@/core/InstanceActorService.js';
|
|
||||||
import type { Config } from '@/config.js';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import { DEFAULT_POLICIES } from '@/core/RoleService.js';
|
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
@ -22,309 +14,10 @@ export const meta = {
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: false,
|
oneOf: [
|
||||||
properties: {
|
{ type: 'object', ref: 'MetaLite' },
|
||||||
maintainerName: {
|
{ type: 'object', ref: 'MetaDetailed' },
|
||||||
type: 'string',
|
],
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
maintainerEmail: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
version: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
providesTarball: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
shortName: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
uri: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'url',
|
|
||||||
example: 'https://misskey.example.com',
|
|
||||||
},
|
|
||||||
description: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
langs: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tosUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
repositoryUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
default: 'https://github.com/misskey-dev/misskey',
|
|
||||||
},
|
|
||||||
feedbackUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
default: 'https://github.com/misskey-dev/misskey/issues/new',
|
|
||||||
},
|
|
||||||
defaultDarkTheme: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
defaultLightTheme: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
defaultLike: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
disableRegistration: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
cacheRemoteFiles: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
cacheRemoteSensitiveFiles: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
emailRequiredForSignup: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
approvalRequiredForSignup: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
enableHcaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
hcaptchaSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
enableMcaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
mcaptchaSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
mcaptchaInstanceUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
enableRecaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
recaptchaSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
enableTurnstile: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
turnstileSiteKey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
swPublickey: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
mascotImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
default: '/assets/ai.png',
|
|
||||||
},
|
|
||||||
bannerUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
serverErrorImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
infoImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
notFoundImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
iconUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
maxNoteTextLength: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
ads: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
properties: {
|
|
||||||
id: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'id',
|
|
||||||
example: 'xxxxxxxxxx',
|
|
||||||
},
|
|
||||||
url: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'url',
|
|
||||||
},
|
|
||||||
place: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
ratio: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
imageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
format: 'url',
|
|
||||||
},
|
|
||||||
dayOfWeek: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
notesPerOneAd: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
requireSetup: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
example: false,
|
|
||||||
},
|
|
||||||
enableEmail: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
enableServiceWorker: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
translatorAvailable: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
proxyAccountName: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
mediaProxy: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
features: {
|
|
||||||
type: 'object',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
properties: {
|
|
||||||
registration: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
localTimeline: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
globalTimeline: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
hcaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
recaptcha: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
objectStorage: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
serviceWorker: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
miauth: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: true, nullable: false,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
backgroundImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
impressumUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
donationUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
logoImageUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
privacyPolicyUrl: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
serverRules: {
|
|
||||||
type: 'array',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
items: {
|
|
||||||
type: 'string',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
themeColor: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
policies: {
|
|
||||||
type: 'object',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
ref: 'RolePolicies',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -339,119 +32,10 @@ export const paramDef = {
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
private metaEntityService: MetaEntityService,
|
||||||
private config: Config,
|
|
||||||
|
|
||||||
@Inject(DI.adsRepository)
|
|
||||||
private adsRepository: AdsRepository,
|
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
|
||||||
private metaService: MetaService,
|
|
||||||
private instanceActorService: InstanceActorService,
|
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const instance = await this.metaService.fetch(true);
|
return ps.detail ? await this.metaEntityService.packDetailed() : await this.metaEntityService.pack();
|
||||||
|
|
||||||
const ads = await this.adsRepository.createQueryBuilder('ads')
|
|
||||||
.where('ads.expiresAt > :now', { now: new Date() })
|
|
||||||
.andWhere('ads.startsAt <= :now', { now: new Date() })
|
|
||||||
.andWhere(new Brackets(qb => {
|
|
||||||
// 曜日のビットフラグを確認する
|
|
||||||
qb.where('ads.dayOfWeek & :dayOfWeek > 0', { dayOfWeek: 1 << new Date().getDay() })
|
|
||||||
.orWhere('ads.dayOfWeek = 0');
|
|
||||||
}))
|
|
||||||
.getMany();
|
|
||||||
|
|
||||||
const response: any = {
|
|
||||||
maintainerName: instance.maintainerName,
|
|
||||||
maintainerEmail: instance.maintainerEmail,
|
|
||||||
|
|
||||||
version: this.config.version,
|
|
||||||
providesTarball: this.config.publishTarballInsteadOfProvideRepositoryUrl,
|
|
||||||
|
|
||||||
name: instance.name,
|
|
||||||
shortName: instance.shortName,
|
|
||||||
uri: this.config.url,
|
|
||||||
description: instance.description,
|
|
||||||
langs: instance.langs,
|
|
||||||
tosUrl: instance.termsOfServiceUrl,
|
|
||||||
repositoryUrl: instance.repositoryUrl,
|
|
||||||
feedbackUrl: instance.feedbackUrl,
|
|
||||||
impressumUrl: instance.impressumUrl,
|
|
||||||
donationUrl: instance.donationUrl,
|
|
||||||
privacyPolicyUrl: instance.privacyPolicyUrl,
|
|
||||||
disableRegistration: instance.disableRegistration,
|
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
|
||||||
approvalRequiredForSignup: instance.approvalRequiredForSignup,
|
|
||||||
enableHcaptcha: instance.enableHcaptcha,
|
|
||||||
hcaptchaSiteKey: instance.hcaptchaSiteKey,
|
|
||||||
enableMcaptcha: instance.enableMcaptcha,
|
|
||||||
mcaptchaSiteKey: instance.mcaptchaSitekey,
|
|
||||||
mcaptchaInstanceUrl: instance.mcaptchaInstanceUrl,
|
|
||||||
enableRecaptcha: instance.enableRecaptcha,
|
|
||||||
enableAchievements: instance.enableAchievements,
|
|
||||||
recaptchaSiteKey: instance.recaptchaSiteKey,
|
|
||||||
enableTurnstile: instance.enableTurnstile,
|
|
||||||
turnstileSiteKey: instance.turnstileSiteKey,
|
|
||||||
swPublickey: instance.swPublicKey,
|
|
||||||
themeColor: instance.themeColor,
|
|
||||||
mascotImageUrl: instance.mascotImageUrl,
|
|
||||||
bannerUrl: instance.bannerUrl,
|
|
||||||
infoImageUrl: instance.infoImageUrl,
|
|
||||||
serverErrorImageUrl: instance.serverErrorImageUrl,
|
|
||||||
notFoundImageUrl: instance.notFoundImageUrl,
|
|
||||||
iconUrl: instance.iconUrl,
|
|
||||||
backgroundImageUrl: instance.backgroundImageUrl,
|
|
||||||
logoImageUrl: instance.logoImageUrl,
|
|
||||||
maxNoteTextLength: this.config.maxNoteLength,
|
|
||||||
// クライアントの手間を減らすためあらかじめJSONに変換しておく
|
|
||||||
defaultLightTheme: instance.defaultLightTheme ? JSON.stringify(JSON5.parse(instance.defaultLightTheme)) : null,
|
|
||||||
defaultDarkTheme: instance.defaultDarkTheme ? JSON.stringify(JSON5.parse(instance.defaultDarkTheme)) : null,
|
|
||||||
defaultLike: instance.defaultLike,
|
|
||||||
ads: ads.map(ad => ({
|
|
||||||
id: ad.id,
|
|
||||||
url: ad.url,
|
|
||||||
place: ad.place,
|
|
||||||
ratio: ad.ratio,
|
|
||||||
imageUrl: ad.imageUrl,
|
|
||||||
dayOfWeek: ad.dayOfWeek,
|
|
||||||
})),
|
|
||||||
notesPerOneAd: instance.notesPerOneAd,
|
|
||||||
enableEmail: instance.enableEmail,
|
|
||||||
enableServiceWorker: instance.enableServiceWorker,
|
|
||||||
|
|
||||||
translatorAvailable: instance.deeplAuthKey != null || instance.deeplFreeMode && instance.deeplFreeInstance,
|
|
||||||
|
|
||||||
serverRules: instance.serverRules,
|
|
||||||
|
|
||||||
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
|
||||||
|
|
||||||
mediaProxy: this.config.mediaProxy,
|
|
||||||
|
|
||||||
...(ps.detail ? {
|
|
||||||
cacheRemoteFiles: instance.cacheRemoteFiles,
|
|
||||||
cacheRemoteSensitiveFiles: instance.cacheRemoteSensitiveFiles,
|
|
||||||
requireSetup: !await this.instanceActorService.realLocalUsersPresent(),
|
|
||||||
} : {}),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (ps.detail) {
|
|
||||||
const proxyAccount = instance.proxyAccountId ? await this.userEntityService.pack(instance.proxyAccountId).catch(() => null) : null;
|
|
||||||
|
|
||||||
response.proxyAccountName = proxyAccount ? proxyAccount.username : null;
|
|
||||||
response.features = {
|
|
||||||
registration: !instance.disableRegistration,
|
|
||||||
emailRequiredForSignup: instance.emailRequiredForSignup,
|
|
||||||
hcaptcha: instance.enableHcaptcha,
|
|
||||||
recaptcha: instance.enableRecaptcha,
|
|
||||||
turnstile: instance.enableTurnstile,
|
|
||||||
objectStorage: instance.useObjectStorage,
|
|
||||||
serviceWorker: instance.enableServiceWorker,
|
|
||||||
miauth: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return response;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import { DI } from '@/di-symbols.js';
|
||||||
import { isPureRenote } from '@/misc/is-pure-renote.js';
|
import { isPureRenote } from '@/misc/is-pure-renote.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { UtilityService } from '@/core/UtilityService.js';
|
import { UtilityService } from '@/core/UtilityService.js';
|
||||||
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -387,8 +388,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
};
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// TODO: 他のErrorもここでキャッチしてエラーメッセージを当てるようにしたい
|
// TODO: 他のErrorもここでキャッチしてエラーメッセージを当てるようにしたい
|
||||||
if (e instanceof NoteCreateService.ContainsProhibitedWordsError) {
|
if (e instanceof IdentifiableError) {
|
||||||
throw new ApiError(meta.errors.containsProhibitedWords);
|
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') throw new ApiError(meta.errors.containsProhibitedWords);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { NoteEditService } from '@/core/NoteEditService.js';
|
import { NoteEditService } from '@/core/NoteEditService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -141,6 +142,12 @@ export const meta = {
|
||||||
code: 'MAX_LENGTH',
|
code: 'MAX_LENGTH',
|
||||||
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce16',
|
id: '3ac74a84-8fd5-4bb0-870f-01804f82ce16',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
containsProhibitedWords: {
|
||||||
|
message: 'Cannot post because it contains prohibited words.',
|
||||||
|
code: 'CONTAINS_PROHIBITED_WORDS',
|
||||||
|
id: 'aa6e01d3-a85c-669d-758a-76aab43af334',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
@ -379,32 +386,40 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.noSuchChannel);
|
throw new ApiError(meta.errors.noSuchChannel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
// 投稿を作成
|
||||||
|
const note = await this.noteEditService.edit(me, ps.editId!, {
|
||||||
|
files: files,
|
||||||
|
poll: ps.poll ? {
|
||||||
|
choices: ps.poll.choices,
|
||||||
|
multiple: ps.poll.multiple ?? false,
|
||||||
|
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
||||||
|
} : undefined,
|
||||||
|
text: ps.text ?? undefined,
|
||||||
|
reply,
|
||||||
|
renote,
|
||||||
|
cw: ps.cw,
|
||||||
|
localOnly: ps.localOnly,
|
||||||
|
reactionAcceptance: ps.reactionAcceptance,
|
||||||
|
visibility: ps.visibility,
|
||||||
|
visibleUsers,
|
||||||
|
channel,
|
||||||
|
apMentions: ps.noExtractMentions ? [] : undefined,
|
||||||
|
apHashtags: ps.noExtractHashtags ? [] : undefined,
|
||||||
|
apEmojis: ps.noExtractEmojis ? [] : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
// 投稿を作成
|
return {
|
||||||
const note = await this.noteEditService.edit(me, ps.editId!, {
|
createdNote: await this.noteEntityService.pack(note, me),
|
||||||
files: files,
|
};
|
||||||
poll: ps.poll ? {
|
} catch (e) {
|
||||||
choices: ps.poll.choices,
|
// TODO: 他のErrorもここでキャッチしてエラーメッセージを当てるようにしたい
|
||||||
multiple: ps.poll.multiple ?? false,
|
if (e instanceof IdentifiableError) {
|
||||||
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') throw new ApiError(meta.errors.containsProhibitedWords);
|
||||||
} : undefined,
|
}
|
||||||
text: ps.text ?? undefined,
|
|
||||||
reply,
|
|
||||||
renote,
|
|
||||||
cw: ps.cw,
|
|
||||||
localOnly: ps.localOnly,
|
|
||||||
reactionAcceptance: ps.reactionAcceptance,
|
|
||||||
visibility: ps.visibility,
|
|
||||||
visibleUsers,
|
|
||||||
channel,
|
|
||||||
apMentions: ps.noExtractMentions ? [] : undefined,
|
|
||||||
apHashtags: ps.noExtractHashtags ? [] : undefined,
|
|
||||||
apEmojis: ps.noExtractEmojis ? [] : undefined,
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
throw e;
|
||||||
createdNote: await this.noteEntityService.pack(note, me),
|
}
|
||||||
};
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['users'],
|
tags: ['users'],
|
||||||
|
@ -52,7 +53,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
host: acct.host ?? IsNull(),
|
host: acct.host ?? IsNull(),
|
||||||
})));
|
})));
|
||||||
|
|
||||||
return await this.userEntityService.packMany(users.filter(x => x !== null) as MiUser[], me, { schema: 'UserDetailed' });
|
return await this.userEntityService.packMany(users.filter(isNotNull), me, { schema: 'UserDetailed' });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import type { SwSubscriptionsRepository } from '@/models/_.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { MetaService } from '@/core/MetaService.js';
|
import { MetaService } from '@/core/MetaService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['account'],
|
tags: ['account'],
|
||||||
|
@ -66,6 +67,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private metaService: MetaService,
|
private metaService: MetaService,
|
||||||
|
private pushNotificationService: PushNotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
// if already subscribed
|
// if already subscribed
|
||||||
|
@ -97,6 +99,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
sendReadMessage: ps.sendReadMessage,
|
sendReadMessage: ps.sendReadMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.pushNotificationService.refreshCache(me.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
state: 'subscribed' as const,
|
state: 'subscribed' as const,
|
||||||
key: instance.swPublicKey,
|
key: instance.swPublicKey,
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { SwSubscriptionsRepository } from '@/models/_.js';
|
import type { SwSubscriptionsRepository } from '@/models/_.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['account'],
|
tags: ['account'],
|
||||||
|
@ -29,12 +30,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.swSubscriptionsRepository)
|
@Inject(DI.swSubscriptionsRepository)
|
||||||
private swSubscriptionsRepository: SwSubscriptionsRepository,
|
private swSubscriptionsRepository: SwSubscriptionsRepository,
|
||||||
|
|
||||||
|
private pushNotificationService: PushNotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
await this.swSubscriptionsRepository.delete({
|
await this.swSubscriptionsRepository.delete({
|
||||||
...(me ? { userId: me.id } : {}),
|
...(me ? { userId: me.id } : {}),
|
||||||
endpoint: ps.endpoint,
|
endpoint: ps.endpoint,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (me) {
|
||||||
|
this.pushNotificationService.refreshCache(me.id);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import type { SwSubscriptionsRepository } from '@/models/_.js';
|
import type { SwSubscriptionsRepository } from '@/models/_.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { PushNotificationService } from '@/core/PushNotificationService.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
|
@ -58,6 +59,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.swSubscriptionsRepository)
|
@Inject(DI.swSubscriptionsRepository)
|
||||||
private swSubscriptionsRepository: SwSubscriptionsRepository,
|
private swSubscriptionsRepository: SwSubscriptionsRepository,
|
||||||
|
|
||||||
|
private pushNotificationService: PushNotificationService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const swSubscription = await this.swSubscriptionsRepository.findOneBy({
|
const swSubscription = await this.swSubscriptionsRepository.findOneBy({
|
||||||
|
@ -77,6 +80,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
sendReadMessage: swSubscription.sendReadMessage,
|
sendReadMessage: swSubscription.sendReadMessage,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.pushNotificationService.refreshCache(me.id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
userId: swSubscription.userId,
|
userId: swSubscription.userId,
|
||||||
endpoint: swSubscription.endpoint,
|
endpoint: swSubscription.endpoint,
|
||||||
|
|
|
@ -19,6 +19,7 @@ import fastifyView from '@fastify/view';
|
||||||
import fastifyCookie from '@fastify/cookie';
|
import fastifyCookie from '@fastify/cookie';
|
||||||
import fastifyProxy from '@fastify/http-proxy';
|
import fastifyProxy from '@fastify/http-proxy';
|
||||||
import vary from 'vary';
|
import vary from 'vary';
|
||||||
|
import htmlSafeJsonStringify from 'htmlescape';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import { getNoteSummary } from '@/misc/get-note-summary.js';
|
import { getNoteSummary } from '@/misc/get-note-summary.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
|
@ -28,12 +29,12 @@ import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, Obj
|
||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
||||||
|
import { MetaEntityService } from '@/core/entities/MetaEntityService.js';
|
||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
||||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||||
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
import type { ChannelsRepository, ClipsRepository, FlashsRepository, GalleryPostsRepository, MiMeta, NotesRepository, PagesRepository, ReversiGamesRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { deepClone } from '@/misc/clone.js';
|
|
||||||
import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js';
|
import { handleRequestRedirectToOmitSearch } from '@/misc/fastify-hook-handlers.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
|
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
|
||||||
|
@ -93,6 +94,7 @@ export class ClientServerService {
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private pageEntityService: PageEntityService,
|
private pageEntityService: PageEntityService,
|
||||||
|
private metaEntityService: MetaEntityService,
|
||||||
private galleryPostEntityService: GalleryPostEntityService,
|
private galleryPostEntityService: GalleryPostEntityService,
|
||||||
private clipEntityService: ClipEntityService,
|
private clipEntityService: ClipEntityService,
|
||||||
private channelEntityService: ChannelEntityService,
|
private channelEntityService: ChannelEntityService,
|
||||||
|
@ -175,7 +177,7 @@ export class ClientServerService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private generateCommonPugData(meta: MiMeta) {
|
private async generateCommonPugData(meta: MiMeta) {
|
||||||
return {
|
return {
|
||||||
instanceName: meta.name ?? 'Sharkey',
|
instanceName: meta.name ?? 'Sharkey',
|
||||||
icon: meta.iconUrl,
|
icon: meta.iconUrl,
|
||||||
|
@ -186,6 +188,8 @@ export class ClientServerService {
|
||||||
notFoundImageUrl: meta.notFoundImageUrl ?? 'https://launcher.moe/missingpage.webp',
|
notFoundImageUrl: meta.notFoundImageUrl ?? 'https://launcher.moe/missingpage.webp',
|
||||||
instanceUrl: this.config.url,
|
instanceUrl: this.config.url,
|
||||||
randomMOTD: this.config.customMOTD ? this.config.customMOTD[Math.floor(Math.random() * this.config.customMOTD.length)] : undefined,
|
randomMOTD: this.config.customMOTD ? this.config.customMOTD[Math.floor(Math.random() * this.config.customMOTD.length)] : undefined,
|
||||||
|
metaJson: htmlSafeJsonStringify(await this.metaEntityService.packDetailed(meta)),
|
||||||
|
now: Date.now(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +455,7 @@ export class ClientServerService {
|
||||||
url: this.config.url,
|
url: this.config.url,
|
||||||
title: meta.name ?? 'Misskey',
|
title: meta.name ?? 'Misskey',
|
||||||
desc: meta.description,
|
desc: meta.description,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -538,7 +542,7 @@ export class ClientServerService {
|
||||||
user, profile, me,
|
user, profile, me,
|
||||||
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
avatarUrl: user.avatarUrl ?? this.userEntityService.getIdenticonUrl(user),
|
||||||
sub: request.params.sub,
|
sub: request.params.sub,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// リモートユーザーなので
|
// リモートユーザーなので
|
||||||
|
@ -588,7 +592,7 @@ export class ClientServerService {
|
||||||
avatarUrl: _note.user.avatarUrl,
|
avatarUrl: _note.user.avatarUrl,
|
||||||
// TODO: Let locale changeable by instance setting
|
// TODO: Let locale changeable by instance setting
|
||||||
summary: getNoteSummary(_note),
|
summary: getNoteSummary(_note),
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -627,7 +631,7 @@ export class ClientServerService {
|
||||||
page: _page,
|
page: _page,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _page.user.avatarUrl,
|
avatarUrl: _page.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -653,7 +657,7 @@ export class ClientServerService {
|
||||||
flash: _flash,
|
flash: _flash,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _flash.user.avatarUrl,
|
avatarUrl: _flash.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -679,7 +683,7 @@ export class ClientServerService {
|
||||||
clip: _clip,
|
clip: _clip,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _clip.user.avatarUrl,
|
avatarUrl: _clip.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -703,7 +707,7 @@ export class ClientServerService {
|
||||||
post: _post,
|
post: _post,
|
||||||
profile,
|
profile,
|
||||||
avatarUrl: _post.user.avatarUrl,
|
avatarUrl: _post.user.avatarUrl,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -722,7 +726,7 @@ export class ClientServerService {
|
||||||
reply.header('Cache-Control', 'public, max-age=15');
|
reply.header('Cache-Control', 'public, max-age=15');
|
||||||
return await reply.view('channel', {
|
return await reply.view('channel', {
|
||||||
channel: _channel,
|
channel: _channel,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
@ -741,7 +745,7 @@ export class ClientServerService {
|
||||||
reply.header('Cache-Control', 'public, max-age=3600');
|
reply.header('Cache-Control', 'public, max-age=3600');
|
||||||
return await reply.view('reversi-game', {
|
return await reply.view('reversi-game', {
|
||||||
game: _game,
|
game: _game,
|
||||||
...this.generateCommonPugData(meta),
|
...await this.generateCommonPugData(meta),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return await renderBase(reply);
|
return await renderBase(reply);
|
||||||
|
|
|
@ -75,6 +75,9 @@ html
|
||||||
var CLIENT_ENTRY = "#{clientEntry.file}";
|
var CLIENT_ENTRY = "#{clientEntry.file}";
|
||||||
window.libopenmpt = window.Module;
|
window.libopenmpt = window.Module;
|
||||||
|
|
||||||
|
script(type='application/json' id='misskey_meta' data-generated-at=now)
|
||||||
|
!= metaJson
|
||||||
|
|
||||||
script
|
script
|
||||||
include ../boot.js
|
include ../boot.js
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ export const moderationLogTypes = [
|
||||||
'resetPassword',
|
'resetPassword',
|
||||||
'suspendRemoteInstance',
|
'suspendRemoteInstance',
|
||||||
'unsuspendRemoteInstance',
|
'unsuspendRemoteInstance',
|
||||||
|
'updateRemoteInstanceNote',
|
||||||
'markSensitiveDriveFile',
|
'markSensitiveDriveFile',
|
||||||
'unmarkSensitiveDriveFile',
|
'unmarkSensitiveDriveFile',
|
||||||
'resolveAbuseReport',
|
'resolveAbuseReport',
|
||||||
|
@ -215,6 +216,12 @@ export type ModerationLogPayloads = {
|
||||||
id: string;
|
id: string;
|
||||||
host: string;
|
host: string;
|
||||||
};
|
};
|
||||||
|
updateRemoteInstanceNote: {
|
||||||
|
id: string;
|
||||||
|
host: string;
|
||||||
|
before: string | null;
|
||||||
|
after: string | null;
|
||||||
|
};
|
||||||
markSensitiveDriveFile: {
|
markSensitiveDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
|
|
@ -90,4 +90,45 @@ describe('ReactionService', () => {
|
||||||
assert.strictEqual(await reactionService.normalize('unknown'), '❤');
|
assert.strictEqual(await reactionService.normalize('unknown'), '❤');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('convertLegacyReactions', () => {
|
||||||
|
test('空の入力に対しては何もしない', () => {
|
||||||
|
const input = {};
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), input);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Unicode絵文字リアクションを変換してしまわない', () => {
|
||||||
|
const input = { '👍': 1, '🍮': 2 };
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), input);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('カスタム絵文字リアクションを変換してしまわない', () => {
|
||||||
|
const input = { ':like@.:': 1, ':pudding@example.tld:': 2 };
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), input);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('文字列によるレガシーなリアクションを変換する', () => {
|
||||||
|
const input = { 'like': 1, 'pudding': 2 };
|
||||||
|
const output = { '👍': 1, '🍮': 2 };
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('host部分が省略されたレガシーなカスタム絵文字リアクションを変換する', () => {
|
||||||
|
const input = { ':custom_emoji:': 1 };
|
||||||
|
const output = { ':custom_emoji@.:': 1 };
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('「0個のリアクション」情報を削除する', () => {
|
||||||
|
const input = { 'angry': 0 };
|
||||||
|
const output = {};
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('host部分の有無によりデコードすると同じ表記になるカスタム絵文字リアクションの個数情報を正しく足し合わせる', () => {
|
||||||
|
const input = { ':custom_emoji:': 1, ':custom_emoji@.:': 2 };
|
||||||
|
const output = { ':custom_emoji@.:': 3 };
|
||||||
|
assert.deepStrictEqual(reactionService.convertLegacyReactions(input), output);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { alert, confirm, popup, post, toast } from '@/os.js';
|
||||||
import { useStream } from '@/stream.js';
|
import { useStream } from '@/stream.js';
|
||||||
import * as sound from '@/scripts/sound.js';
|
import * as sound from '@/scripts/sound.js';
|
||||||
import { $i, signout, updateAccount } from '@/account.js';
|
import { $i, signout, updateAccount } from '@/account.js';
|
||||||
import { fetchInstance, instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
import { ColdDeviceStorage, defaultStore } from '@/store.js';
|
||||||
import { makeHotkey } from '@/scripts/hotkey.js';
|
import { makeHotkey } from '@/scripts/hotkey.js';
|
||||||
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
import { reactionPicker } from '@/scripts/reaction-picker.js';
|
||||||
|
@ -233,12 +233,10 @@ export async function mainBoot() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchInstance().then(() => {
|
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
||||||
const modifiedVersionMustProminentlyOfferInAgplV3Section13Read = miLocalStorage.getItem('modifiedVersionMustProminentlyOfferInAgplV3Section13Read');
|
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://activitypub.software/TransFem-org/Sharkey/') {
|
||||||
if (modifiedVersionMustProminentlyOfferInAgplV3Section13Read !== 'true' && instance.repositoryUrl !== 'https://activitypub.software/TransFem-org/Sharkey/') {
|
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkSourceCodeAvailablePopup.vue')), {}, {}, 'closed');
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if ('Notification' in window) {
|
if ('Notification' in window) {
|
||||||
// 許可を得ていなかったらリクエスト
|
// 許可を得ていなかったらリクエスト
|
||||||
|
|
|
@ -57,18 +57,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { customEmojis } from '@/custom-emojis.js';
|
import { customEmojis } from '@/custom-emojis.js';
|
||||||
import { MFM_TAGS, MFM_PARAMS } from '@/const.js';
|
import { MFM_TAGS, MFM_PARAMS } from '@/const.js';
|
||||||
|
import { searchEmoji, EmojiDef } from '@/scripts/search-emoji.js';
|
||||||
type EmojiDef = {
|
|
||||||
emoji: string;
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
aliasOf?: string;
|
|
||||||
} | {
|
|
||||||
emoji: string;
|
|
||||||
name: string;
|
|
||||||
aliasOf?: string;
|
|
||||||
isCustomEmoji?: true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const lib = emojilist.filter(x => x.category !== 'flags');
|
const lib = emojilist.filter(x => x.category !== 'flags');
|
||||||
|
|
||||||
|
@ -249,7 +238,7 @@ function exec() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emojis.value = emojiAutoComplete(props.q.toLowerCase(), emojiDb.value);
|
emojis.value = searchEmoji(props.q.toLowerCase(), emojiDb.value);
|
||||||
} else if (props.type === 'mfmTag') {
|
} else if (props.type === 'mfmTag') {
|
||||||
if (!props.q || props.q === '') {
|
if (!props.q || props.q === '') {
|
||||||
mfmTags.value = MFM_TAGS;
|
mfmTags.value = MFM_TAGS;
|
||||||
|
@ -267,87 +256,6 @@ function exec() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EmojiScore = { emoji: EmojiDef, score: number };
|
|
||||||
|
|
||||||
function emojiAutoComplete(query: string | null, emojiDb: EmojiDef[], max = 30): EmojiDef[] {
|
|
||||||
if (!query) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const matched = new Map<string, EmojiScore>();
|
|
||||||
// 完全一致(エイリアス込み)
|
|
||||||
emojiDb.some(x => {
|
|
||||||
if (x.name.toLowerCase() === query && !matched.has(x.aliasOf ?? x.name)) {
|
|
||||||
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length + 2 });
|
|
||||||
}
|
|
||||||
return matched.size === max;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 前方一致(エイリアスなし)
|
|
||||||
if (matched.size < max) {
|
|
||||||
emojiDb.some(x => {
|
|
||||||
if (x.name.startsWith(query) && !x.aliasOf) {
|
|
||||||
matched.set(x.name, { emoji: x, score: query.length + 1 });
|
|
||||||
}
|
|
||||||
return matched.size === max;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 前方一致(エイリアス込み)
|
|
||||||
if (matched.size < max) {
|
|
||||||
emojiDb.some(x => {
|
|
||||||
if (x.name.toLowerCase().startsWith(query) && !matched.has(x.aliasOf ?? x.name)) {
|
|
||||||
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length });
|
|
||||||
}
|
|
||||||
return matched.size === max;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 部分一致(エイリアス込み)
|
|
||||||
if (matched.size < max) {
|
|
||||||
emojiDb.some(x => {
|
|
||||||
if (x.name.toLowerCase().includes(query) && !matched.has(x.aliasOf ?? x.name)) {
|
|
||||||
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length - 1 });
|
|
||||||
}
|
|
||||||
return matched.size === max;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 簡易あいまい検索(3文字以上)
|
|
||||||
if (matched.size < max && query.length > 3) {
|
|
||||||
const queryChars = [...query];
|
|
||||||
const hitEmojis = new Map<string, EmojiScore>();
|
|
||||||
|
|
||||||
for (const x of emojiDb) {
|
|
||||||
// 文字列の位置を進めながら、クエリの文字を順番に探す
|
|
||||||
|
|
||||||
let pos = 0;
|
|
||||||
let hit = 0;
|
|
||||||
for (const c of queryChars) {
|
|
||||||
pos = x.name.toLowerCase().indexOf(c, pos);
|
|
||||||
if (pos <= -1) break;
|
|
||||||
hit++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 半分以上の文字が含まれていればヒットとする
|
|
||||||
if (hit > Math.ceil(queryChars.length / 2) && hit - 2 > (matched.get(x.aliasOf ?? x.name)?.score ?? 0)) {
|
|
||||||
hitEmojis.set(x.aliasOf ?? x.name, { emoji: x, score: hit - 2 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ヒットしたものを全部追加すると雑多になるので、先頭の6件程度だけにしておく(6件=オートコンプリートのポップアップのサイズ分)
|
|
||||||
[...hitEmojis.values()]
|
|
||||||
.sort((x, y) => y.score - x.score)
|
|
||||||
.slice(0, 6)
|
|
||||||
.forEach(it => matched.set(it.emoji.name, it));
|
|
||||||
}
|
|
||||||
|
|
||||||
return [...matched.values()]
|
|
||||||
.sort((x, y) => y.score - x.score)
|
|
||||||
.slice(0, max)
|
|
||||||
.map(it => it.emoji);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onMousedown(event: Event) {
|
function onMousedown(event: Event) {
|
||||||
if (!contains(rootEl.value, event.target) && (rootEl.value !== event.target)) props.close();
|
if (!contains(rootEl.value, event.target) && (rootEl.value !== event.target)) props.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -240,7 +240,7 @@ const render = () => {
|
||||||
},
|
},
|
||||||
external: externalTooltipHandler,
|
external: externalTooltipHandler,
|
||||||
callbacks: {
|
callbacks: {
|
||||||
label: (item) => chartData?.bytes ? bytes(item.parsed.y * 1000, 1) : item.parsed.y.toString(),
|
label: (item) => `${item.dataset.label}: ${chartData?.bytes ? bytes(item.parsed.y * 1000, 1) : item.parsed.y.toString()}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
zoom: props.detailed ? {
|
zoom: props.detailed ? {
|
||||||
|
|
|
@ -52,7 +52,7 @@ async function fetchLanguage(to: string): Promise<void> {
|
||||||
return bundle.id === language || bundle.aliases?.includes(language);
|
return bundle.id === language || bundle.aliases?.includes(language);
|
||||||
});
|
});
|
||||||
if (bundles.length > 0) {
|
if (bundles.length > 0) {
|
||||||
console.log(`Loading language: ${language}`);
|
if (_DEV_) console.log(`Loading language: ${language}`);
|
||||||
await highlighter.loadLanguage(bundles[0].import);
|
await highlighter.loadLanguage(bundles[0].import);
|
||||||
codeLang.value = language;
|
codeLang.value = language;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -152,11 +152,11 @@ function showFileMenu(file: Misskey.entities.DriveFile, ev: MouseEvent): void {
|
||||||
icon: 'ph-crop ph-bold ph-lg',
|
icon: 'ph-crop ph-bold ph-lg',
|
||||||
action: () : void => { crop(file); },
|
action: () : void => { crop(file); },
|
||||||
}] : [], {
|
}] : [], {
|
||||||
|
type: 'divider',
|
||||||
|
}, {
|
||||||
text: i18n.ts.attachCancel,
|
text: i18n.ts.attachCancel,
|
||||||
icon: 'ph-x-circle ph-bold ph-lg',
|
icon: 'ph-x-circle ph-bold ph-lg',
|
||||||
action: () => { detachMedia(file.id); },
|
action: () => { detachMedia(file.id); },
|
||||||
}, {
|
|
||||||
type: 'divider',
|
|
||||||
}, {
|
}, {
|
||||||
text: i18n.ts.deleteFile,
|
text: i18n.ts.deleteFile,
|
||||||
icon: 'ph-trash ph-bold ph-lg',
|
icon: 'ph-trash ph-bold ph-lg',
|
||||||
|
|
|
@ -35,7 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton @click="close">{{ i18n.ts.gotIt }}</MkButton>
|
<MkButton @click="close">{{ i18n.ts.gotIt }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="_button" :class="$style.close" @click="close"><i class="ti ti-x"></i></button>
|
<button class="_button" :class="$style.close" @click="close"><i class="ph-x ph-bold ph-lg"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import MkTime from './MkTime.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { dateTimeFormat } from '@/scripts/intl-const.js';
|
import { dateTimeFormat } from '@/scripts/intl-const.js';
|
||||||
const now = new Date('2023-04-01T00:00:00.000Z');
|
const now = new Date('2023-04-01T00:00:00.000Z');
|
||||||
const future = new Date(8640000000000000);
|
const future = new Date('3000-04-01T00:00:00.000Z');
|
||||||
const oneHourAgo = new Date(now.getTime() - 3600000);
|
const oneHourAgo = new Date(now.getTime() - 3600000);
|
||||||
const oneDayAgo = new Date(now.getTime() - 86400000);
|
const oneDayAgo = new Date(now.getTime() - 86400000);
|
||||||
const oneWeekAgo = new Date(now.getTime() - 604800000);
|
const oneWeekAgo = new Date(now.getTime() - 604800000);
|
||||||
|
@ -49,11 +49,12 @@ export const Empty = {
|
||||||
export const RelativeFuture = {
|
export const RelativeFuture = {
|
||||||
...Empty,
|
...Empty,
|
||||||
async play({ canvasElement }) {
|
async play({ canvasElement }) {
|
||||||
await expect(canvasElement).toHaveTextContent(i18n.ts._ago.future);
|
await expect(canvasElement).toHaveTextContent(i18n.tsx._timeIn.years({ n: 977 }));
|
||||||
},
|
},
|
||||||
args: {
|
args: {
|
||||||
...Empty.args,
|
...Empty.args,
|
||||||
time: future,
|
time: future,
|
||||||
|
origin: now,
|
||||||
},
|
},
|
||||||
} satisfies StoryObj<typeof MkTime>;
|
} satisfies StoryObj<typeof MkTime>;
|
||||||
export const AbsoluteFuture = {
|
export const AbsoluteFuture = {
|
||||||
|
|
|
@ -99,7 +99,6 @@ export class UserPreview {
|
||||||
this.el.removeEventListener('mouseover', this.onMouseover);
|
this.el.removeEventListener('mouseover', this.onMouseover);
|
||||||
this.el.removeEventListener('mouseleave', this.onMouseleave);
|
this.el.removeEventListener('mouseleave', this.onMouseleave);
|
||||||
this.el.removeEventListener('click', this.onClick);
|
this.el.removeEventListener('click', this.onClick);
|
||||||
window.clearInterval(this.checkTimer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,13 +11,24 @@ import { DEFAULT_INFO_IMAGE_URL, DEFAULT_NOT_FOUND_IMAGE_URL, DEFAULT_SERVER_ERR
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
const cached = miLocalStorage.getItem('instance');
|
//#region loader
|
||||||
|
const providedMetaEl = document.getElementById('misskey_meta');
|
||||||
|
|
||||||
|
let cachedMeta = miLocalStorage.getItem('instance') ? JSON.parse(miLocalStorage.getItem('instance')!) : null;
|
||||||
|
let cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
|
||||||
|
const providedMeta = providedMetaEl && providedMetaEl.textContent ? JSON.parse(providedMetaEl.textContent) : null;
|
||||||
|
const providedAt = providedMetaEl && providedMetaEl.dataset.generatedAt ? parseInt(providedMetaEl.dataset.generatedAt) : 0;
|
||||||
|
if (providedAt > cachedAt) {
|
||||||
|
miLocalStorage.setItem('instance', JSON.stringify(providedMeta));
|
||||||
|
miLocalStorage.setItem('instanceCachedAt', providedAt.toString());
|
||||||
|
cachedMeta = providedMeta;
|
||||||
|
cachedAt = providedAt;
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
// TODO: instanceをリアクティブにするかは再考の余地あり
|
// TODO: instanceをリアクティブにするかは再考の余地あり
|
||||||
|
|
||||||
export const instance: Misskey.entities.MetaResponse = reactive(cached ? JSON.parse(cached) : {
|
export const instance: Misskey.entities.MetaResponse = reactive(cachedMeta ?? {});
|
||||||
// TODO: set default values
|
|
||||||
});
|
|
||||||
|
|
||||||
export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
|
export const serverErrorImageUrl = computed(() => instance.serverErrorImageUrl ?? DEFAULT_SERVER_ERROR_IMAGE_URL);
|
||||||
|
|
||||||
|
@ -25,7 +36,15 @@ export const infoImageUrl = computed(() => instance.infoImageUrl ?? DEFAULT_INFO
|
||||||
|
|
||||||
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
export const notFoundImageUrl = computed(() => instance.notFoundImageUrl ?? DEFAULT_NOT_FOUND_IMAGE_URL);
|
||||||
|
|
||||||
export async function fetchInstance() {
|
export async function fetchInstance(force = false): Promise<void> {
|
||||||
|
if (!force) {
|
||||||
|
const cachedAt = miLocalStorage.getItem('instanceCachedAt') ? parseInt(miLocalStorage.getItem('instanceCachedAt')!) : 0;
|
||||||
|
|
||||||
|
if (Date.now() - cachedAt < 1000 * 60 * 60) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const meta = await misskeyApi('meta', {
|
const meta = await misskeyApi('meta', {
|
||||||
detail: false,
|
detail: false,
|
||||||
});
|
});
|
||||||
|
@ -35,4 +54,5 @@ export async function fetchInstance() {
|
||||||
}
|
}
|
||||||
|
|
||||||
miLocalStorage.setItem('instance', JSON.stringify(instance));
|
miLocalStorage.setItem('instance', JSON.stringify(instance));
|
||||||
|
miLocalStorage.setItem('instanceCachedAt', Date.now().toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ type Keys =
|
||||||
'v' |
|
'v' |
|
||||||
'lastVersion' |
|
'lastVersion' |
|
||||||
'instance' |
|
'instance' |
|
||||||
|
'instanceCachedAt' |
|
||||||
'account' |
|
'account' |
|
||||||
'accounts' |
|
'accounts' |
|
||||||
'latestDonationInfoShownAt' |
|
'latestDonationInfoShownAt' |
|
||||||
|
|
|
@ -142,7 +142,7 @@ function save() {
|
||||||
turnstileSiteKey: turnstileSiteKey.value,
|
turnstileSiteKey: turnstileSiteKey.value,
|
||||||
turnstileSecretKey: turnstileSecretKey.value,
|
turnstileSecretKey: turnstileSecretKey.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -179,7 +179,7 @@ function save() {
|
||||||
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
|
feedbackUrl: feedbackUrl.value === '' ? null : feedbackUrl.value,
|
||||||
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
manifestJsonOverride: manifestJsonOverride.value === '' ? '{}' : JSON.stringify(JSON5.parse(manifestJsonOverride.value)),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,7 +124,7 @@ function save() {
|
||||||
smtpUser: smtpUser.value,
|
smtpUser: smtpUser.value,
|
||||||
smtpPass: smtpPass.value,
|
smtpPass: smtpPass.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ function save() {
|
||||||
deeplFreeMode: deeplFreeMode.value,
|
deeplFreeMode: deeplFreeMode.value,
|
||||||
deeplFreeInstance: deeplFreeInstance.value,
|
deeplFreeInstance: deeplFreeInstance.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ function save() {
|
||||||
silencedHosts: silencedHosts.value.split('\n') || [],
|
silencedHosts: silencedHosts.value.split('\n') || [],
|
||||||
|
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ function save() {
|
||||||
preservedUsernames: preservedUsernames.value.split('\n'),
|
preservedUsernames: preservedUsernames.value.split('\n'),
|
||||||
bubbleInstances: bubbleTimeline.value.split('\n'),
|
bubbleInstances: bubbleTimeline.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
|
<CodeDiff :context="5" :hideHeader="true" :oldString="JSON5.stringify(log.info.before, null, '\t')" :newString="JSON5.stringify(log.info.after, null, '\t')" language="javascript" maxHeight="300px"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-else-if="log.type === 'updateRemoteInstanceNote'">
|
||||||
|
<div>{{ i18n.ts.user }}: {{ log.info.userId }}</div>
|
||||||
|
<div :class="$style.diff">
|
||||||
|
<CodeDiff :context="5" :hideHeader="true" :oldString="log.info.before ?? ''" :newString="log.info.after ?? ''" maxHeight="300px"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary>raw</summary>
|
<summary>raw</summary>
|
||||||
|
|
|
@ -143,7 +143,7 @@ function save() {
|
||||||
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
objectStorageSetPublicRead: objectStorageSetPublicRead.value,
|
||||||
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
objectStorageS3ForcePathStyle: objectStorageS3ForcePathStyle.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ function save() {
|
||||||
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
enableChartsForRemoteUser: enableChartsForRemoteUser.value,
|
||||||
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
enableChartsForFederatedInstances: enableChartsForFederatedInstances.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ function save() {
|
||||||
os.apiWithDialog('admin/update-meta', {
|
os.apiWithDialog('admin/update-meta', {
|
||||||
proxyAccountId: proxyAccountId.value,
|
proxyAccountId: proxyAccountId.value,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ async function init() {
|
||||||
enableTruemailApi.value = meta.enableTruemailApi;
|
enableTruemailApi.value = meta.enableTruemailApi;
|
||||||
truemailInstance.value = meta.truemailInstance;
|
truemailInstance.value = meta.truemailInstance;
|
||||||
truemailAuthKey.value = meta.truemailAuthKey;
|
truemailAuthKey.value = meta.truemailAuthKey;
|
||||||
bannedEmailDomains.value = meta.bannedEmailDomains?.join('\n') || "";
|
bannedEmailDomains.value = meta.bannedEmailDomains?.join('\n') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
|
@ -155,7 +155,7 @@ function save() {
|
||||||
truemailAuthKey: truemailAuthKey.value,
|
truemailAuthKey: truemailAuthKey.value,
|
||||||
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
bannedEmailDomains: bannedEmailDomains.value.split('\n'),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ const save = async () => {
|
||||||
await os.apiWithDialog('admin/update-meta', {
|
await os.apiWithDialog('admin/update-meta', {
|
||||||
serverRules: serverRules.value,
|
serverRules: serverRules.value,
|
||||||
});
|
});
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const remove = (index: number): void => {
|
const remove = (index: number): void => {
|
||||||
|
|
|
@ -251,7 +251,7 @@ async function save(): void {
|
||||||
notesPerOneAd: notesPerOneAd.value,
|
notesPerOneAd: notesPerOneAd.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
fetchInstance();
|
fetchInstance(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
|
@ -7,9 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSpacer :contentMax="800">
|
<MkSpacer :contentMax="800">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div v-if="!gameLoaded" :class="$style.loadingScreen">
|
<div v-if="!gameLoaded" :class="$style.loadingScreen">
|
||||||
<div>
|
<div>{{ i18n.ts.loading }}<MkEllipsis/></div>
|
||||||
Loading...
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<!-- ↓に対してTransitionコンポーネントを使うと何故かkeyを指定していてもキャッシュが効かず様々なコンポーネントが都度再評価されてパフォーマンスが低下する -->
|
<!-- ↓に対してTransitionコンポーネントを使うと何故かkeyを指定していてもキャッシュが効かず様々なコンポーネントが都度再評価されてパフォーマンスが低下する -->
|
||||||
<div v-show="gameLoaded" class="_gaps_s">
|
<div v-show="gameLoaded" class="_gaps_s">
|
||||||
|
@ -32,18 +30,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|
||||||
<div :class="$style.header">
|
<div :class="$style.header">
|
||||||
<div :class="[$style.frame, $style.headerTitle]">
|
<div class="_woodenFrame" :class="[$style.headerTitle]">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<b>BUBBLE GAME</b>
|
<b>{{ i18n.ts.bubbleGame }}</b>
|
||||||
<div>- {{ gameMode }} -</div>
|
<div>- {{ gameMode.toUpperCase() }} -</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="[$style.frame, $style.frameH]">
|
<div class="_woodenFrame _woodenFrameH">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<MkButton inline small @click="hold">HOLD</MkButton>
|
<MkButton inline small @click="hold">{{ i18n.ts._bubbleGame.hold }}</MkButton>
|
||||||
<img v-if="holdingStock" :src="getTextureImageUrl(holdingStock.mono)" style="width: 32px; margin-left: 8px; vertical-align: bottom;"/>
|
<img v-if="holdingStock" :src="getTextureImageUrl(holdingStock.mono)" style="width: 32px; margin-left: 8px; vertical-align: bottom;"/>
|
||||||
</div>
|
</div>
|
||||||
<div :class="[$style.frameInner, $style.stock]" style="text-align: center;">
|
<div class="_woodenFrameInner" :class="$style.stock" style="text-align: center;">
|
||||||
<TransitionGroup
|
<TransitionGroup
|
||||||
:enterActiveClass="$style.transition_stock_enterActive"
|
:enterActiveClass="$style.transition_stock_enterActive"
|
||||||
:leaveActiveClass="$style.transition_stock_leaveActive"
|
:leaveActiveClass="$style.transition_stock_leaveActive"
|
||||||
|
@ -90,58 +88,74 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-if="isGameOver && !replaying" :class="$style.gameOverLabel">
|
<div v-if="isGameOver && !replaying" :class="$style.gameOverLabel">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
<img src="/client-assets/drop-and-fusion/gameover.png" style="width: 200px; max-width: 100%; display: block; margin: auto; margin-bottom: -5px;"/>
|
<img src="/client-assets/drop-and-fusion/gameover.png" style="width: 200px; max-width: 100%; display: block; margin: auto; margin-bottom: -5px;"/>
|
||||||
<div>SCORE: <MkNumber :value="score"/>{{ getScoreUnit(gameMode) }}</div>
|
<div>{{ i18n.ts._bubbleGame._score.score }}: <MkNumber :value="score"/>{{ getScoreUnit(gameMode) }}</div>
|
||||||
<div>MAX CHAIN: <MkNumber :value="maxCombo"/></div>
|
<div>{{ i18n.ts._bubbleGame._score.maxChain }}: <MkNumber :value="maxCombo"/></div>
|
||||||
<div v-if="gameMode === 'yen'">TOTAL EARNINGS: <b><MkNumber :value="yenTotal ?? score"/>円</b></div>
|
<div v-if="gameMode === 'yen'">
|
||||||
<div v-if="gameMode === 'sweets'"><b>おにぎり<MkNumber :value="score / 130"/>個分</b></div>
|
{{ i18n.ts._bubbleGame._score.scoreYen }}:
|
||||||
|
<I18n :src="i18n.ts._bubbleGame._score.yen" tag="b">
|
||||||
|
<template #yen><MkNumber :value="yenTotal ?? score"/></template>
|
||||||
|
</I18n>
|
||||||
|
</div>
|
||||||
|
<I18n v-if="gameMode === 'sweets'" :src="i18n.ts._bubbleGame._score.scoreSweets" tag="div">
|
||||||
|
<template #onigiriQtyWithUnit>
|
||||||
|
<I18n :src="i18n.ts._bubbleGame._score.estimatedQty" tag="b">
|
||||||
|
<template #qty><MkNumber :value="score / 130"/></template>
|
||||||
|
</I18n>
|
||||||
|
</template>
|
||||||
|
</I18n>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="replaying" :class="$style.replayIndicator"><span :class="$style.replayIndicatorText"><i class="ph-play ph-bold ph-lg"></i> {{ i18n.ts.replaying }}</span></div>
|
<div v-if="replaying" :class="$style.replayIndicator"><span :class="$style.replayIndicatorText"><i class="ph-play ph-bold ph-lg"></i> {{ i18n.ts.replaying }}</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="replaying" :class="$style.frame">
|
<div v-if="replaying" class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div style="background: #0004;">
|
<div style="background: #0004;">
|
||||||
<div style="height: 10px; background: var(--accent); will-change: width;" :style="{ width: `${(currentFrame / endedAtFrame) * 100}%` }"></div>
|
<div style="height: 10px; background: var(--accent); will-change: width;" :style="{ width: `${(currentFrame / endedAtFrame) * 100}%` }"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_buttonsCenter">
|
<div class="_buttonsCenter">
|
||||||
<MkButton @click="endReplay"><i class="ph-stop ph-bold ph-lg"></i> END</MkButton>
|
<MkButton @click="endReplay"><i class="ph-stop ph-bold ph-lg"></i> {{ i18n.ts.endReplay }}</MkButton>
|
||||||
<MkButton :primary="replayPlaybackRate === 4" @click="replayPlaybackRate = replayPlaybackRate === 4 ? 1 : 4"><i class="ph-skip-forward ph-bold ph-lg"></i> x4</MkButton>
|
<MkButton :primary="replayPlaybackRate === 4" @click="replayPlaybackRate = replayPlaybackRate === 4 ? 1 : 4"><i class="ph-skip-forward ph-bold ph-lg"></i> x4</MkButton>
|
||||||
<MkButton :primary="replayPlaybackRate === 16" @click="replayPlaybackRate = replayPlaybackRate === 16 ? 1 : 16"><i class="ph-skip-forward ph-bold ph-lg"></i> x16</MkButton>
|
<MkButton :primary="replayPlaybackRate === 16" @click="replayPlaybackRate = replayPlaybackRate === 16 ? 1 : 16"><i class="ph-skip-forward ph-bold ph-lg"></i> x16</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isGameOver" :class="$style.frame">
|
<div v-if="isGameOver" class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_buttonsCenter">
|
<div class="_buttonsCenter">
|
||||||
<MkButton primary rounded @click="backToTitle">{{ i18n.ts.backToTitle }}</MkButton>
|
<MkButton primary rounded @click="backToTitle">{{ i18n.ts.backToTitle }}</MkButton>
|
||||||
<MkButton primary rounded @click="replay">{{ i18n.ts.showReplay }}</MkButton>
|
<MkButton primary rounded @click="replay">{{ i18n.ts.showReplay }}</MkButton>
|
||||||
<MkButton primary rounded @click="share">{{ i18n.ts.share }}</MkButton>
|
<MkButton primary rounded @click="share">{{ i18n.ts.share }}</MkButton>
|
||||||
<MkButton rounded @click="exportLog">Copy replay data</MkButton>
|
<MkButton rounded @click="exportLog">{{ i18n.ts.copyReplayData }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="display: flex;">
|
<div style="display: flex;">
|
||||||
<div :class="$style.frame" style="flex: 1; margin-right: 10px;">
|
<div class="_woodenFrame" style="flex: 1; margin-right: 10px;">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div>SCORE: <b><MkNumber :value="score"/>{{ getScoreUnit(gameMode) }}</b></div>
|
<div>{{ i18n.ts._bubbleGame._score.score }}: <MkNumber :value="score"/>{{ getScoreUnit(gameMode) }}</div>
|
||||||
<div>HIGH SCORE: <b v-if="highScore"><MkNumber :value="highScore"/>{{ getScoreUnit(gameMode) }}</b><b v-else>-</b></div>
|
<div>{{ i18n.ts._bubbleGame._score.highScore }}: <b v-if="highScore"><MkNumber :value="highScore"/>{{ getScoreUnit(gameMode) }}</b><b v-else>-</b></div>
|
||||||
<div v-if="gameMode === 'yen'">TOTAL EARNINGS: <b v-if="yenTotal"><MkNumber :value="yenTotal"/>円</b><b v-else>-</b></div>
|
<div v-if="gameMode === 'yen'">
|
||||||
|
{{ i18n.ts._bubbleGame._score.scoreYen }}:
|
||||||
|
<I18n :src="i18n.ts._bubbleGame._score.yen" tag="b">
|
||||||
|
<template #yen><MkNumber :value="yenTotal ?? score"/></template>
|
||||||
|
</I18n>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="[$style.frame]" style="margin-left: auto;">
|
<div class="_woodenFrame" style="margin-left: auto;">
|
||||||
<div :class="$style.frameInner" style="text-align: center;">
|
<div class="_woodenFrameInner" style="text-align: center;">
|
||||||
<div @click="showConfig = !showConfig"><i class="ph-gear ph-bold ph-lg"></i></div>
|
<div @click="showConfig = !showConfig"><i class="ph-gear ph-bold ph-lg"></i></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="showConfig" :class="$style.frame">
|
<div v-if="showConfig" class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<MkRange v-model="bgmVolume" :min="0" :max="1" :step="0.01" :textConverter="(v) => `${Math.floor(v * 100)}%`" :continuousUpdate="true" @dragEnded="(v) => updateSettings('bgmVolume', v)">
|
<MkRange v-model="bgmVolume" :min="0" :max="1" :step="0.01" :textConverter="(v) => `${Math.floor(v * 100)}%`" :continuousUpdate="true" @dragEnded="(v) => updateSettings('bgmVolume', v)">
|
||||||
<template #label>BGM {{ i18n.ts.volume }}</template>
|
<template #label>BGM {{ i18n.ts.volume }}</template>
|
||||||
|
@ -153,8 +167,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="$style.frame">
|
<div class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div>FUSION RECIPE</div>
|
<div>FUSION RECIPE</div>
|
||||||
<div>
|
<div>
|
||||||
<div v-for="(mono, i) in game.monoDefinitions.sort((a, b) => a.level - b.level)" :key="mono.id" style="display: inline-block;">
|
<div v-for="(mono, i) in game.monoDefinitions.sort((a, b) => a.level - b.level)" :key="mono.id" style="display: inline-block;">
|
||||||
|
@ -165,10 +179,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="$style.frame">
|
<div class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<MkButton v-if="!isGameOver && !replaying" full danger @click="surrender">Surrender</MkButton>
|
<MkButton v-if="!isGameOver && !replaying" full danger @click="surrender">{{ i18n.ts.surrender }}</MkButton>
|
||||||
<MkButton v-else full @click="restart">Retry</MkButton>
|
<MkButton v-else full @click="restart">{{ i18n.ts.gameRetry }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1313,38 +1327,6 @@ definePageMetadata(() => ({
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.frame {
|
|
||||||
padding: 7px;
|
|
||||||
background: #8C4F26;
|
|
||||||
box-shadow: 0 6px 16px #0007, 0 0 1px 1px #693410, inset 0 0 2px 1px #ce8a5c;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.frameH {
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.frameInner {
|
|
||||||
padding: 8px;
|
|
||||||
margin-top: 8px;
|
|
||||||
background: #F1E8DC;
|
|
||||||
box-shadow: 0 0 2px 1px #ce8a5c, inset 0 0 1px 1px #693410;
|
|
||||||
border-radius: 6px;
|
|
||||||
color: #693410;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.frameDivider {
|
|
||||||
height: 0;
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid #693410;
|
|
||||||
border-bottom: 1px solid #ce8a5c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
|
|
|
@ -15,13 +15,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSpacer v-if="!gameStarted" :contentMax="800">
|
<MkSpacer v-if="!gameStarted" :contentMax="800">
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div class="_gaps">
|
<div class="_gaps">
|
||||||
<div :class="$style.frame" style="text-align: center;">
|
<div class="_woodenFrame" style="text-align: center;">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<img src="/client-assets/drop-and-fusion/logo.png" style="display: block; max-width: 100%; max-height: 200px; margin: auto;"/>
|
<img src="/client-assets/drop-and-fusion/logo.png" style="display: block; max-width: 100%; max-height: 200px; margin: auto;"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.frame" style="text-align: center;">
|
<div class="_woodenFrame" style="text-align: center;">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_gaps" style="padding: 16px;">
|
<div class="_gaps" style="padding: 16px;">
|
||||||
<MkSelect v-model="gameMode">
|
<MkSelect v-model="gameMode">
|
||||||
<option value="normal">NORMAL</option>
|
<option value="normal">NORMAL</option>
|
||||||
|
@ -33,19 +33,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton primary gradate large rounded inline @click="start">{{ i18n.ts.start }}</MkButton>
|
<MkButton primary gradate large rounded inline @click="start">{{ i18n.ts.start }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_gaps" style="padding: 16px;">
|
<div class="_gaps" style="padding: 16px;">
|
||||||
<div style="font-size: 90%;"><i class="ti ti-music"></i> {{ i18n.ts.soundWillBePlayed }}</div>
|
<div style="font-size: 90%;"><i class="ph-music-notes ph-bold ph-lg"></i> {{ i18n.ts.soundWillBePlayed }}</div>
|
||||||
<MkSwitch v-model="mute">
|
<MkSwitch v-model="mute">
|
||||||
<template #label>{{ i18n.ts.mute }}</template>
|
<template #label>{{ i18n.ts.mute }}</template>
|
||||||
</MkSwitch>
|
</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.frame">
|
<div class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_gaps_s" style="padding: 16px;">
|
<div class="_gaps_s" style="padding: 16px;">
|
||||||
<div><b>{{ i18n.tsx.lastNDays({ n: 7 }) }} {{ i18n.ts.ranking }}</b> ({{ gameMode }})</div>
|
<div><b>{{ i18n.tsx.lastNDays({ n: 7 }) }} {{ i18n.ts.ranking }}</b> ({{ gameMode.toUpperCase() }})</div>
|
||||||
<div v-if="ranking" class="_gaps_s">
|
<div v-if="ranking" class="_gaps_s">
|
||||||
<div v-for="r in ranking" :key="r.id" :class="$style.rankingRecord">
|
<div v-for="r in ranking" :key="r.id" :class="$style.rankingRecord">
|
||||||
<MkAvatar :link="true" style="width: 24px; height: 24px; margin-right: 4px;" :user="r.user"/>
|
<MkAvatar :link="true" style="width: 24px; height: 24px; margin-right: 4px;" :user="r.user"/>
|
||||||
|
@ -57,8 +57,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.frame">
|
<div class="_woodenFrame">
|
||||||
<div :class="$style.frameInner" style="padding: 16px;">
|
<div class="_woodenFrameInner" style="padding: 16px;">
|
||||||
<div style="font-weight: bold;">{{ i18n.ts._bubbleGame.howToPlay }}</div>
|
<div style="font-weight: bold;">{{ i18n.ts._bubbleGame.howToPlay }}</div>
|
||||||
<ol>
|
<ol>
|
||||||
<li>{{ i18n.ts._bubbleGame._howToPlay.section1 }}</li>
|
<li>{{ i18n.ts._bubbleGame._howToPlay.section1 }}</li>
|
||||||
|
@ -67,8 +67,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.frame">
|
<div class="_woodenFrame">
|
||||||
<div :class="$style.frameInner">
|
<div class="_woodenFrameInner">
|
||||||
<div class="_gaps_s" style="padding: 16px;">
|
<div class="_gaps_s" style="padding: 16px;">
|
||||||
<div><b>Credit</b></div>
|
<div><b>Credit</b></div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -123,7 +123,7 @@ function onGameEnd() {
|
||||||
|
|
||||||
definePageMetadata(() => ({
|
definePageMetadata(() => ({
|
||||||
title: i18n.ts.bubbleGame,
|
title: i18n.ts.bubbleGame,
|
||||||
icon: 'ti ti-device-gamepad',
|
icon: 'ph-game-controller ph-bold ph-lg',
|
||||||
}));
|
}));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -149,38 +149,6 @@ definePageMetadata(() => ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.frame {
|
|
||||||
padding: 7px;
|
|
||||||
background: #8C4F26;
|
|
||||||
box-shadow: 0 6px 16px #0007, 0 0 1px 1px #693410, inset 0 0 2px 1px #ce8a5c;
|
|
||||||
border-radius: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.frameH {
|
|
||||||
display: flex;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.frameInner {
|
|
||||||
padding: 8px;
|
|
||||||
margin-top: 8px;
|
|
||||||
background: #F1E8DC;
|
|
||||||
box-shadow: 0 0 2px 1px #ce8a5c, inset 0 0 1px 1px #693410;
|
|
||||||
border-radius: 6px;
|
|
||||||
color: #693410;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.frameDivider {
|
|
||||||
height: 0;
|
|
||||||
border: none;
|
|
||||||
border-top: 1px solid #693410;
|
|
||||||
border-bottom: 1px solid #ce8a5c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.rankingRecord {
|
.rankingRecord {
|
||||||
display: flex;
|
display: flex;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
|
|
|
@ -40,6 +40,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSwitch v-model="isSilenced" :disabled="!meta || !instance" @update:modelValue="toggleSilenced">{{ i18n.ts.silenceThisInstance }}</MkSwitch>
|
<MkSwitch v-model="isSilenced" :disabled="!meta || !instance" @update:modelValue="toggleSilenced">{{ i18n.ts.silenceThisInstance }}</MkSwitch>
|
||||||
<MkSwitch v-model="isNSFW" :disabled="!instance" @update:modelValue="toggleNSFW">Mark as NSFW</MkSwitch>
|
<MkSwitch v-model="isNSFW" :disabled="!instance" @update:modelValue="toggleNSFW">Mark as NSFW</MkSwitch>
|
||||||
<MkButton @click="refreshMetadata"><i class="ph-arrows-clockwise ph-bold ph-lg"></i> Refresh metadata</MkButton>
|
<MkButton @click="refreshMetadata"><i class="ph-arrows-clockwise ph-bold ph-lg"></i> Refresh metadata</MkButton>
|
||||||
|
<MkTextarea v-model="moderationNote" manualSave>
|
||||||
|
<template #label>{{ i18n.ts.moderationNote }}</template>
|
||||||
|
</MkTextarea>
|
||||||
</div>
|
</div>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
|
|
||||||
|
@ -120,7 +123,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed, watch } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import MkChart from '@/components/MkChart.vue';
|
import MkChart from '@/components/MkChart.vue';
|
||||||
import MkObjectView from '@/components/MkObjectView.vue';
|
import MkObjectView from '@/components/MkObjectView.vue';
|
||||||
|
@ -142,6 +145,7 @@ import MkPagination from '@/components/MkPagination.vue';
|
||||||
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
import MkHorizontalSwipe from '@/components/MkHorizontalSwipe.vue';
|
||||||
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
|
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js';
|
||||||
import { dateString } from '@/filters/date.js';
|
import { dateString } from '@/filters/date.js';
|
||||||
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
host: string;
|
host: string;
|
||||||
|
@ -157,6 +161,7 @@ const isBlocked = ref(false);
|
||||||
const isSilenced = ref(false);
|
const isSilenced = ref(false);
|
||||||
const isNSFW = ref(false);
|
const isNSFW = ref(false);
|
||||||
const faviconUrl = ref<string | null>(null);
|
const faviconUrl = ref<string | null>(null);
|
||||||
|
const moderationNote = ref('');
|
||||||
|
|
||||||
const usersPagination = {
|
const usersPagination = {
|
||||||
endpoint: iAmModerator ? 'admin/show-users' : 'users' as const,
|
endpoint: iAmModerator ? 'admin/show-users' : 'users' as const,
|
||||||
|
@ -169,6 +174,10 @@ const usersPagination = {
|
||||||
offsetMode: true,
|
offsetMode: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(moderationNote, async () => {
|
||||||
|
await misskeyApi('admin/federation/update-instance', { host: instance.value.host, moderationNote: moderationNote.value });
|
||||||
|
});
|
||||||
|
|
||||||
async function fetch(): Promise<void> {
|
async function fetch(): Promise<void> {
|
||||||
if (iAmAdmin) {
|
if (iAmAdmin) {
|
||||||
meta.value = await misskeyApi('admin/meta');
|
meta.value = await misskeyApi('admin/meta');
|
||||||
|
@ -181,6 +190,7 @@ async function fetch(): Promise<void> {
|
||||||
isSilenced.value = instance.value?.isSilenced ?? false;
|
isSilenced.value = instance.value?.isSilenced ?? false;
|
||||||
isNSFW.value = instance.value?.isNSFW ?? false;
|
isNSFW.value = instance.value?.isNSFW ?? false;
|
||||||
faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
|
faviconUrl.value = getProxiedImageUrlNullable(instance.value?.faviconUrl, 'preview') ?? getProxiedImageUrlNullable(instance.value?.iconUrl, 'preview');
|
||||||
|
moderationNote.value = instance.value?.moderationNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleBlock(): Promise<void> {
|
async function toggleBlock(): Promise<void> {
|
||||||
|
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="$style.board">
|
<div class="_woodenFrame">
|
||||||
<div :class="$style.boardInner">
|
<div :class="$style.boardInner">
|
||||||
<div v-if="showBoardLabels" :class="$style.labelsX">
|
<div v-if="showBoardLabels" :class="$style.labelsX">
|
||||||
<span v-for="i in game.map[0].length" :key="i" :class="$style.labelsXLabel">{{ String.fromCharCode(64 + i) }}</span>
|
<span v-for="i in game.map[0].length" :key="i" :class="$style.labelsXLabel">{{ String.fromCharCode(64 + i) }}</span>
|
||||||
|
@ -124,8 +124,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkFolder>
|
<MkFolder>
|
||||||
<template #label>{{ i18n.ts.options }}</template>
|
<template #label>{{ i18n.ts.options }}</template>
|
||||||
<div class="_gaps_s" style="text-align: left;">
|
<div class="_gaps_s" style="text-align: left;">
|
||||||
<MkSwitch v-model="showBoardLabels">Show labels</MkSwitch>
|
<MkSwitch v-model="showBoardLabels">{{ i18n.ts._reversi.showBoardLabels }}</MkSwitch>
|
||||||
<MkSwitch v-model="useAvatarAsStone">useAvatarAsStone</MkSwitch>
|
<MkSwitch v-model="useAvatarAsStone">{{ i18n.ts._reversi.useAvatarAsStone }}</MkSwitch>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ if (game.value.isStarted && !game.value.isEnded) {
|
||||||
crc32: crc32.toString(),
|
crc32: crc32.toString(),
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
if (res.desynced) {
|
if (res.desynced) {
|
||||||
console.log('resynced');
|
if (_DEV_) console.log('resynced');
|
||||||
restoreGame(res.game!);
|
restoreGame(res.game!);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -500,17 +500,6 @@ $gap: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.board {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
padding: 7px;
|
|
||||||
background: #8C4F26;
|
|
||||||
box-shadow: 0 6px 16px #0007, 0 0 1px 1px #693410, inset 0 0 2px 1px #ce8a5c;
|
|
||||||
border-radius: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.boardInner {
|
.boardInner {
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
|
|
||||||
|
|
|
@ -2,14 +2,18 @@ import { unisonReload } from '@/scripts/unison-reload.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
import { fetchCustomEmojis } from '@/custom-emojis.js';
|
||||||
|
import { fetchInstance } from '@/instance.js';
|
||||||
|
|
||||||
export async function clearCache() {
|
export async function clearCache() {
|
||||||
os.waiting();
|
os.waiting();
|
||||||
|
miLocalStorage.removeItem('instance');
|
||||||
|
miLocalStorage.removeItem('instanceCachedAt');
|
||||||
miLocalStorage.removeItem('locale');
|
miLocalStorage.removeItem('locale');
|
||||||
miLocalStorage.removeItem('localeVersion');
|
miLocalStorage.removeItem('localeVersion');
|
||||||
miLocalStorage.removeItem('theme');
|
miLocalStorage.removeItem('theme');
|
||||||
miLocalStorage.removeItem('emojis');
|
miLocalStorage.removeItem('emojis');
|
||||||
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
miLocalStorage.removeItem('lastEmojisFetchedAt');
|
||||||
|
await fetchInstance(true);
|
||||||
await fetchCustomEmojis(true);
|
await fetchCustomEmojis(true);
|
||||||
unisonReload();
|
unisonReload();
|
||||||
}
|
}
|
||||||
|
|
101
packages/frontend/src/scripts/search-emoji.ts
Normal file
101
packages/frontend/src/scripts/search-emoji.ts
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
export type EmojiDef = {
|
||||||
|
emoji: string;
|
||||||
|
name: string;
|
||||||
|
url: string;
|
||||||
|
aliasOf?: string;
|
||||||
|
} | {
|
||||||
|
emoji: string;
|
||||||
|
name: string;
|
||||||
|
aliasOf?: string;
|
||||||
|
isCustomEmoji?: true;
|
||||||
|
};
|
||||||
|
type EmojiScore = { emoji: EmojiDef, score: number };
|
||||||
|
|
||||||
|
export function searchEmoji(query: string | null, emojiDb: EmojiDef[], max = 30): EmojiDef[] {
|
||||||
|
if (!query) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const matched = new Map<string, EmojiScore>();
|
||||||
|
// 完全一致(エイリアスなし)
|
||||||
|
emojiDb.some(x => {
|
||||||
|
if (x.name.toLowerCase() === query && !x.aliasOf) {
|
||||||
|
matched.set(x.name, { emoji: x, score: query.length + 3 });
|
||||||
|
}
|
||||||
|
return matched.size === max;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 完全一致(エイリアス込み)
|
||||||
|
if (matched.size < max) {
|
||||||
|
emojiDb.some(x => {
|
||||||
|
if (x.name.toLowerCase() === query && !matched.has(x.aliasOf ?? x.name)) {
|
||||||
|
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length + 2 });
|
||||||
|
}
|
||||||
|
return matched.size === max;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前方一致(エイリアスなし)
|
||||||
|
if (matched.size < max) {
|
||||||
|
emojiDb.some(x => {
|
||||||
|
if (x.name.toLowerCase().startsWith(query) && !x.aliasOf && !matched.has(x.name)) {
|
||||||
|
matched.set(x.name, { emoji: x, score: query.length + 1 });
|
||||||
|
}
|
||||||
|
return matched.size === max;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 前方一致(エイリアス込み)
|
||||||
|
if (matched.size < max) {
|
||||||
|
emojiDb.some(x => {
|
||||||
|
if (x.name.toLowerCase().startsWith(query) && !matched.has(x.aliasOf ?? x.name)) {
|
||||||
|
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length });
|
||||||
|
}
|
||||||
|
return matched.size === max;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 部分一致(エイリアス込み)
|
||||||
|
if (matched.size < max) {
|
||||||
|
emojiDb.some(x => {
|
||||||
|
if (x.name.toLowerCase().includes(query) && !matched.has(x.aliasOf ?? x.name)) {
|
||||||
|
matched.set(x.aliasOf ?? x.name, { emoji: x, score: query.length - 1 });
|
||||||
|
}
|
||||||
|
return matched.size === max;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 簡易あいまい検索(3文字以上)
|
||||||
|
if (matched.size < max && query.length > 3) {
|
||||||
|
const queryChars = [...query];
|
||||||
|
const hitEmojis = new Map<string, EmojiScore>();
|
||||||
|
|
||||||
|
for (const x of emojiDb) {
|
||||||
|
// 文字列の位置を進めながら、クエリの文字を順番に探す
|
||||||
|
|
||||||
|
let pos = 0;
|
||||||
|
let hit = 0;
|
||||||
|
for (const c of queryChars) {
|
||||||
|
pos = x.name.indexOf(c, pos);
|
||||||
|
if (pos <= -1) break;
|
||||||
|
hit++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 半分以上の文字が含まれていればヒットとする
|
||||||
|
if (hit > Math.ceil(queryChars.length / 2) && hit - 2 > (matched.get(x.aliasOf ?? x.name)?.score ?? 0)) {
|
||||||
|
hitEmojis.set(x.aliasOf ?? x.name, { emoji: x, score: hit - 2 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ヒットしたものを全部追加すると雑多になるので、先頭の6件程度だけにしておく(6件=オートコンプリートのポップアップのサイズ分)
|
||||||
|
[...hitEmojis.values()]
|
||||||
|
.sort((x, y) => y.score - x.score)
|
||||||
|
.slice(0, 6)
|
||||||
|
.forEach(it => matched.set(it.emoji.name, it));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...matched.values()]
|
||||||
|
.sort((x, y) => y.score - x.score)
|
||||||
|
.slice(0, max)
|
||||||
|
.map(it => it.emoji);
|
||||||
|
}
|
|
@ -126,7 +126,7 @@ export async function loadAudio(url: string, options?: { useCache?: boolean; })
|
||||||
*/
|
*/
|
||||||
export function playMisskeySfx(operationType: OperationType) {
|
export function playMisskeySfx(operationType: OperationType) {
|
||||||
const sound = defaultStore.state[`sound_${operationType}`];
|
const sound = defaultStore.state[`sound_${operationType}`];
|
||||||
if (sound.type == null || !canPlay) return;
|
if (sound.type == null || !canPlay || !navigator.userActivation.hasBeenActive) return;
|
||||||
|
|
||||||
canPlay = false;
|
canPlay = false;
|
||||||
playMisskeySfxFile(sound).finally(() => {
|
playMisskeySfxFile(sound).finally(() => {
|
||||||
|
|
|
@ -451,6 +451,39 @@ rt {
|
||||||
transition-timing-function: cubic-bezier(0,.5,.5,1);
|
transition-timing-function: cubic-bezier(0,.5,.5,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
._woodenFrame {
|
||||||
|
padding: 7px;
|
||||||
|
background: #8C4F26;
|
||||||
|
box-shadow: 0 6px 16px #0007, 0 0 1px 1px #693410, inset 0 0 2px 1px #ce8a5c;
|
||||||
|
border-radius: 10px;
|
||||||
|
|
||||||
|
--bg: #F1E8DC;
|
||||||
|
--panel: #fff;
|
||||||
|
--fg: #693410;
|
||||||
|
--switchOffBg: rgba(0, 0, 0, 0.1);
|
||||||
|
--switchOffFg: rgb(255, 255, 255);
|
||||||
|
--switchOnBg: var(--accent);
|
||||||
|
--switchOnFg: rgb(255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
._woodenFrameH {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
._woodenFrameInner {
|
||||||
|
padding: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
background: var(--bg);
|
||||||
|
box-shadow: 0 0 2px 1px #ce8a5c, inset 0 0 1px 1px #693410;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: var(--fg);
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
._transition_zoom-enter-active, ._transition_zoom-leave-active {
|
._transition_zoom-enter-active, ._transition_zoom-leave-active {
|
||||||
transition: opacity 0.5s, transform 0.5s !important;
|
transition: opacity 0.5s, transform 0.5s !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template v-if="column.channelId">
|
<template v-if="column.channelId">
|
||||||
<div style="padding: 8px; text-align: center;">
|
<div style="padding: 8px; text-align: center;">
|
||||||
<MkButton primary gradate rounded inline @click="post"><i class="ph-pencil-simple ph-bold ph-lg"></i></MkButton>
|
<MkButton primary gradate rounded inline small @click="post"><i class="ph-pencil-simple ph-bold ph-lg"></i></MkButton>
|
||||||
</div>
|
</div>
|
||||||
<MkTimeline ref="timeline" src="channel" :channel="column.channelId"/>
|
<MkTimeline ref="timeline" src="channel" :channel="column.channelId"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
34
packages/frontend/test/autocomplete.test.ts
Normal file
34
packages/frontend/test/autocomplete.test.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { assert, describe, test } from 'vitest';
|
||||||
|
import { searchEmoji } from '@/scripts/search-emoji.js';
|
||||||
|
|
||||||
|
describe('emoji autocomplete', () => {
|
||||||
|
test('名前の完全一致は名前の前方一致より優先される', async () => {
|
||||||
|
const result = searchEmoji('foooo', [{ emoji: ':foooo:', name: 'foooo' }, { emoji: ':foooobaaar:', name: 'foooobaaar' }]);
|
||||||
|
assert.equal(result[0].emoji, ':foooo:');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('名前の前方一致は名前の部分一致より優先される', async () => {
|
||||||
|
const result = searchEmoji('baaa', [{ emoji: ':baaar:', name: 'baaar' }, { emoji: ':foooobaaar:', name: 'foooobaaar' }]);
|
||||||
|
assert.equal(result[0].emoji, ':baaar:');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('名前の完全一致はタグの完全一致より優先される', async () => {
|
||||||
|
const result = searchEmoji('foooo', [{ emoji: ':foooo:', name: 'foooo' }, { emoji: ':baaar:', name: 'foooo', aliasOf: 'baaar' }]);
|
||||||
|
assert.equal(result[0].emoji, ':foooo:');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('名前の前方一致はタグの前方一致より優先される', async () => {
|
||||||
|
const result = searchEmoji('foo', [{ emoji: ':foooo:', name: 'foooo' }, { emoji: ':baaar:', name: 'foooo', aliasOf: 'baaar' }]);
|
||||||
|
assert.equal(result[0].emoji, ':foooo:');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('名前の部分一致はタグの部分一致より優先される', async () => {
|
||||||
|
const result = searchEmoji('oooo', [{ emoji: ':foooo:', name: 'foooo' }, { emoji: ':baaar:', name: 'foooo', aliasOf: 'baaar' }]);
|
||||||
|
assert.equal(result[0].emoji, ':foooo:');
|
||||||
|
});
|
||||||
|
});
|
|
@ -558,6 +558,7 @@ export type Channels = {
|
||||||
readAntenna: (payload: Antenna) => void;
|
readAntenna: (payload: Antenna) => void;
|
||||||
receiveFollowRequest: (payload: User) => void;
|
receiveFollowRequest: (payload: User) => void;
|
||||||
announcementCreated: (payload: AnnouncementCreated) => void;
|
announcementCreated: (payload: AnnouncementCreated) => void;
|
||||||
|
edited: (payload: Note) => void;
|
||||||
};
|
};
|
||||||
receives: null;
|
receives: null;
|
||||||
};
|
};
|
||||||
|
@ -1760,7 +1761,10 @@ declare namespace entities {
|
||||||
Role,
|
Role,
|
||||||
RolePolicies,
|
RolePolicies,
|
||||||
ReversiGameLite,
|
ReversiGameLite,
|
||||||
ReversiGameDetailed
|
ReversiGameDetailed,
|
||||||
|
MetaLite,
|
||||||
|
MetaDetailedOnly,
|
||||||
|
MetaDetailed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export { entities }
|
export { entities }
|
||||||
|
@ -2274,6 +2278,15 @@ type MeDetailed = components['schemas']['MeDetailed'];
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MeDetailedOnly = components['schemas']['MeDetailedOnly'];
|
type MeDetailedOnly = components['schemas']['MeDetailedOnly'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MetaDetailed = components['schemas']['MetaDetailed'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MetaDetailedOnly = components['schemas']['MetaDetailedOnly'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type MetaLite = components['schemas']['MetaLite'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MetaRequest = operations['meta']['requestBody']['content']['application/json'];
|
type MetaRequest = operations['meta']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
@ -2370,6 +2383,9 @@ type ModerationLog = {
|
||||||
} | {
|
} | {
|
||||||
type: 'unsuspendRemoteInstance';
|
type: 'unsuspendRemoteInstance';
|
||||||
info: ModerationLogPayloads['unsuspendRemoteInstance'];
|
info: ModerationLogPayloads['unsuspendRemoteInstance'];
|
||||||
|
} | {
|
||||||
|
type: 'updateRemoteInstanceNote';
|
||||||
|
info: ModerationLogPayloads['updateRemoteInstanceNote'];
|
||||||
} | {
|
} | {
|
||||||
type: 'markSensitiveDriveFile';
|
type: 'markSensitiveDriveFile';
|
||||||
info: ModerationLogPayloads['markSensitiveDriveFile'];
|
info: ModerationLogPayloads['markSensitiveDriveFile'];
|
||||||
|
@ -2409,7 +2425,7 @@ type ModerationLog = {
|
||||||
});
|
});
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "approve", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"];
|
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "approve", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type MuteCreateRequest = operations['mute/create']['requestBody']['content']['application/json'];
|
type MuteCreateRequest = operations['mute/create']['requestBody']['content']['application/json'];
|
||||||
|
@ -2628,7 +2644,7 @@ type Notification_2 = components['schemas']['Notification'];
|
||||||
type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json'];
|
type NotificationsCreateRequest = operations['notifications/create']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned"];
|
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollVote", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "achievementEarned", "edited"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type Page = components['schemas']['Page'];
|
type Page = components['schemas']['Page'];
|
||||||
|
|
|
@ -46,3 +46,6 @@ export type Role = components['schemas']['Role'];
|
||||||
export type RolePolicies = components['schemas']['RolePolicies'];
|
export type RolePolicies = components['schemas']['RolePolicies'];
|
||||||
export type ReversiGameLite = components['schemas']['ReversiGameLite'];
|
export type ReversiGameLite = components['schemas']['ReversiGameLite'];
|
||||||
export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
|
export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
|
||||||
|
export type MetaLite = components['schemas']['MetaLite'];
|
||||||
|
export type MetaDetailedOnly = components['schemas']['MetaDetailedOnly'];
|
||||||
|
export type MetaDetailed = components['schemas']['MetaDetailed'];
|
||||||
|
|
|
@ -4624,6 +4624,7 @@ export type components = {
|
||||||
/** Format: date-time */
|
/** Format: date-time */
|
||||||
latestRequestReceivedAt: string | null;
|
latestRequestReceivedAt: string | null;
|
||||||
isNSFW: boolean;
|
isNSFW: boolean;
|
||||||
|
moderationNote?: string | null;
|
||||||
};
|
};
|
||||||
GalleryPost: {
|
GalleryPost: {
|
||||||
/**
|
/**
|
||||||
|
@ -4867,6 +4868,100 @@ export type components = {
|
||||||
logs: number[][];
|
logs: number[][];
|
||||||
map: string[];
|
map: string[];
|
||||||
};
|
};
|
||||||
|
MetaLite: {
|
||||||
|
maintainerName: string | null;
|
||||||
|
maintainerEmail: string | null;
|
||||||
|
version: string;
|
||||||
|
providesTarball: boolean;
|
||||||
|
name: string | null;
|
||||||
|
shortName: string | null;
|
||||||
|
/**
|
||||||
|
* Format: url
|
||||||
|
* @example https://misskey.example.com
|
||||||
|
*/
|
||||||
|
uri: string;
|
||||||
|
description: string | null;
|
||||||
|
langs: string[];
|
||||||
|
tosUrl: string | null;
|
||||||
|
/** @default https://github.com/misskey-dev/misskey */
|
||||||
|
repositoryUrl: string | null;
|
||||||
|
/** @default https://github.com/misskey-dev/misskey/issues/new */
|
||||||
|
feedbackUrl: string | null;
|
||||||
|
donationUrl: string | null;
|
||||||
|
defaultDarkTheme: string | null;
|
||||||
|
defaultLightTheme: string | null;
|
||||||
|
defaultLike: string | null;
|
||||||
|
disableRegistration: boolean;
|
||||||
|
emailRequiredForSignup: boolean;
|
||||||
|
approvalRequiredForSignup: boolean;
|
||||||
|
enableHcaptcha: boolean;
|
||||||
|
hcaptchaSiteKey: string | null;
|
||||||
|
enableMcaptcha: boolean;
|
||||||
|
mcaptchaSiteKey: string | null;
|
||||||
|
mcaptchaInstanceUrl: string | null;
|
||||||
|
enableRecaptcha: boolean;
|
||||||
|
recaptchaSiteKey: string | null;
|
||||||
|
enableTurnstile: boolean;
|
||||||
|
turnstileSiteKey: string | null;
|
||||||
|
enableAchievements: boolean | null;
|
||||||
|
swPublickey: string | null;
|
||||||
|
/** @default /assets/ai.png */
|
||||||
|
mascotImageUrl: string;
|
||||||
|
bannerUrl: string | null;
|
||||||
|
serverErrorImageUrl: string | null;
|
||||||
|
infoImageUrl: string | null;
|
||||||
|
notFoundImageUrl: string | null;
|
||||||
|
iconUrl: string | null;
|
||||||
|
maxNoteTextLength: number;
|
||||||
|
ads: {
|
||||||
|
/**
|
||||||
|
* Format: id
|
||||||
|
* @example xxxxxxxxxx
|
||||||
|
*/
|
||||||
|
id: string;
|
||||||
|
/** Format: url */
|
||||||
|
url: string;
|
||||||
|
place: string;
|
||||||
|
ratio: number;
|
||||||
|
/** Format: url */
|
||||||
|
imageUrl: string;
|
||||||
|
dayOfWeek: number;
|
||||||
|
}[];
|
||||||
|
/** @default 0 */
|
||||||
|
notesPerOneAd: number;
|
||||||
|
enableEmail: boolean;
|
||||||
|
enableServiceWorker: boolean;
|
||||||
|
translatorAvailable: boolean;
|
||||||
|
mediaProxy: string;
|
||||||
|
backgroundImageUrl: string | null;
|
||||||
|
impressumUrl: string | null;
|
||||||
|
logoImageUrl: string | null;
|
||||||
|
privacyPolicyUrl: string | null;
|
||||||
|
serverRules: string[];
|
||||||
|
themeColor: string | null;
|
||||||
|
policies: components['schemas']['RolePolicies'];
|
||||||
|
};
|
||||||
|
MetaDetailedOnly: {
|
||||||
|
features?: {
|
||||||
|
registration: boolean;
|
||||||
|
emailRequiredForSignup: boolean;
|
||||||
|
localTimeline: boolean;
|
||||||
|
globalTimeline: boolean;
|
||||||
|
hcaptcha: boolean;
|
||||||
|
turnstile: boolean;
|
||||||
|
recaptcha: boolean;
|
||||||
|
objectStorage: boolean;
|
||||||
|
serviceWorker: boolean;
|
||||||
|
/** @default true */
|
||||||
|
miauth?: boolean;
|
||||||
|
};
|
||||||
|
proxyAccountName: string | null;
|
||||||
|
/** @example false */
|
||||||
|
requireSetup: boolean;
|
||||||
|
cacheRemoteFiles: boolean;
|
||||||
|
cacheRemoteSensitiveFiles: boolean;
|
||||||
|
};
|
||||||
|
MetaDetailed: components['schemas']['MetaLite'] & components['schemas']['MetaDetailedOnly'];
|
||||||
};
|
};
|
||||||
responses: never;
|
responses: never;
|
||||||
parameters: never;
|
parameters: never;
|
||||||
|
@ -7366,6 +7461,7 @@ export type operations = {
|
||||||
host: string;
|
host: string;
|
||||||
isSuspended?: boolean;
|
isSuspended?: boolean;
|
||||||
isNSFW?: boolean;
|
isNSFW?: boolean;
|
||||||
|
moderationNote?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -20037,94 +20133,7 @@ export type operations = {
|
||||||
/** @description OK (with results) */
|
/** @description OK (with results) */
|
||||||
200: {
|
200: {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': components['schemas']['MetaLite'] | components['schemas']['MetaDetailed'];
|
||||||
maintainerName: string | null;
|
|
||||||
maintainerEmail: string | null;
|
|
||||||
version: string;
|
|
||||||
providesTarball: boolean;
|
|
||||||
name: string;
|
|
||||||
shortName: string | null;
|
|
||||||
/**
|
|
||||||
* Format: url
|
|
||||||
* @example https://misskey.example.com
|
|
||||||
*/
|
|
||||||
uri: string;
|
|
||||||
description: string | null;
|
|
||||||
langs: string[];
|
|
||||||
tosUrl: string | null;
|
|
||||||
/** @default https://github.com/misskey-dev/misskey */
|
|
||||||
repositoryUrl: string | null;
|
|
||||||
/** @default https://github.com/misskey-dev/misskey/issues/new */
|
|
||||||
feedbackUrl: string | null;
|
|
||||||
defaultDarkTheme: string | null;
|
|
||||||
defaultLightTheme: string | null;
|
|
||||||
defaultLike: string | null;
|
|
||||||
disableRegistration: boolean;
|
|
||||||
cacheRemoteFiles: boolean;
|
|
||||||
cacheRemoteSensitiveFiles: boolean;
|
|
||||||
emailRequiredForSignup: boolean;
|
|
||||||
approvalRequiredForSignup: boolean;
|
|
||||||
enableHcaptcha: boolean;
|
|
||||||
hcaptchaSiteKey: string | null;
|
|
||||||
enableMcaptcha: boolean;
|
|
||||||
mcaptchaSiteKey: string | null;
|
|
||||||
mcaptchaInstanceUrl: string | null;
|
|
||||||
enableRecaptcha: boolean;
|
|
||||||
recaptchaSiteKey: string | null;
|
|
||||||
enableTurnstile: boolean;
|
|
||||||
turnstileSiteKey: string | null;
|
|
||||||
swPublickey: string | null;
|
|
||||||
/** @default /assets/ai.png */
|
|
||||||
mascotImageUrl: string;
|
|
||||||
bannerUrl: string;
|
|
||||||
serverErrorImageUrl: string | null;
|
|
||||||
infoImageUrl: string | null;
|
|
||||||
notFoundImageUrl: string | null;
|
|
||||||
iconUrl: string | null;
|
|
||||||
maxNoteTextLength: number;
|
|
||||||
ads: {
|
|
||||||
/**
|
|
||||||
* Format: id
|
|
||||||
* @example xxxxxxxxxx
|
|
||||||
*/
|
|
||||||
id: string;
|
|
||||||
/** Format: url */
|
|
||||||
url: string;
|
|
||||||
place: string;
|
|
||||||
ratio: number;
|
|
||||||
/** Format: url */
|
|
||||||
imageUrl: string;
|
|
||||||
dayOfWeek: number;
|
|
||||||
}[];
|
|
||||||
/** @default 0 */
|
|
||||||
notesPerOneAd: number;
|
|
||||||
/** @example false */
|
|
||||||
requireSetup: boolean;
|
|
||||||
enableEmail: boolean;
|
|
||||||
enableServiceWorker: boolean;
|
|
||||||
translatorAvailable: boolean;
|
|
||||||
proxyAccountName: string | null;
|
|
||||||
mediaProxy: string;
|
|
||||||
features?: {
|
|
||||||
registration: boolean;
|
|
||||||
localTimeline: boolean;
|
|
||||||
globalTimeline: boolean;
|
|
||||||
hcaptcha: boolean;
|
|
||||||
recaptcha: boolean;
|
|
||||||
objectStorage: boolean;
|
|
||||||
serviceWorker: boolean;
|
|
||||||
/** @default true */
|
|
||||||
miauth?: boolean;
|
|
||||||
};
|
|
||||||
backgroundImageUrl: string | null;
|
|
||||||
impressumUrl: string | null;
|
|
||||||
donationUrl: string | null;
|
|
||||||
logoImageUrl: string | null;
|
|
||||||
privacyPolicyUrl: string | null;
|
|
||||||
serverRules: string[];
|
|
||||||
themeColor: string | null;
|
|
||||||
policies: components['schemas']['RolePolicies'];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/** @description Client error */
|
/** @description Client error */
|
||||||
|
@ -23807,10 +23816,10 @@ export type operations = {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
flashId: string;
|
flashId: string;
|
||||||
title: string;
|
title?: string;
|
||||||
summary: string;
|
summary?: string;
|
||||||
script: string;
|
script?: string;
|
||||||
permissions: string[];
|
permissions?: string[];
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
visibility?: 'public' | 'private';
|
visibility?: 'public' | 'private';
|
||||||
};
|
};
|
||||||
|
|
|
@ -127,6 +127,7 @@ export const moderationLogTypes = [
|
||||||
'resetPassword',
|
'resetPassword',
|
||||||
'suspendRemoteInstance',
|
'suspendRemoteInstance',
|
||||||
'unsuspendRemoteInstance',
|
'unsuspendRemoteInstance',
|
||||||
|
'updateRemoteInstanceNote',
|
||||||
'markSensitiveDriveFile',
|
'markSensitiveDriveFile',
|
||||||
'unmarkSensitiveDriveFile',
|
'unmarkSensitiveDriveFile',
|
||||||
'resolveAbuseReport',
|
'resolveAbuseReport',
|
||||||
|
@ -272,6 +273,12 @@ export type ModerationLogPayloads = {
|
||||||
id: string;
|
id: string;
|
||||||
host: string;
|
host: string;
|
||||||
};
|
};
|
||||||
|
updateRemoteInstanceNote: {
|
||||||
|
id: string;
|
||||||
|
host: string;
|
||||||
|
before: string | null;
|
||||||
|
after: string | null;
|
||||||
|
};
|
||||||
markSensitiveDriveFile: {
|
markSensitiveDriveFile: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
fileUserId: string | null;
|
fileUserId: string | null;
|
||||||
|
|
|
@ -98,6 +98,9 @@ export type ModerationLog = {
|
||||||
} | {
|
} | {
|
||||||
type: 'unsuspendRemoteInstance';
|
type: 'unsuspendRemoteInstance';
|
||||||
info: ModerationLogPayloads['unsuspendRemoteInstance'];
|
info: ModerationLogPayloads['unsuspendRemoteInstance'];
|
||||||
|
} | {
|
||||||
|
type: 'updateRemoteInstanceNote';
|
||||||
|
info: ModerationLogPayloads['updateRemoteInstanceNote'];
|
||||||
} | {
|
} | {
|
||||||
type: 'markSensitiveDriveFile';
|
type: 'markSensitiveDriveFile';
|
||||||
info: ModerationLogPayloads['markSensitiveDriveFile'];
|
info: ModerationLogPayloads['markSensitiveDriveFile'];
|
||||||
|
|
430
pnpm-lock.yaml
430
pnpm-lock.yaml
|
@ -107,8 +107,8 @@ importers:
|
||||||
specifier: 8.2.0
|
specifier: 8.2.0
|
||||||
version: 8.2.0
|
version: 8.2.0
|
||||||
'@misskey-dev/sharp-read-bmp':
|
'@misskey-dev/sharp-read-bmp':
|
||||||
specifier: ^1.1.1
|
specifier: ^1.2.0
|
||||||
version: 1.1.1
|
version: 1.2.0
|
||||||
'@misskey-dev/summaly':
|
'@misskey-dev/summaly':
|
||||||
specifier: ^5.0.3
|
specifier: ^5.0.3
|
||||||
version: 5.0.3
|
version: 5.0.3
|
||||||
|
@ -235,6 +235,9 @@ importers:
|
||||||
hpagent:
|
hpagent:
|
||||||
specifier: 1.2.0
|
specifier: 1.2.0
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
|
htmlescape:
|
||||||
|
specifier: ^1.1.1
|
||||||
|
version: 1.1.1
|
||||||
http-link-header:
|
http-link-header:
|
||||||
specifier: 1.1.1
|
specifier: 1.1.1
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
|
@ -371,8 +374,8 @@ importers:
|
||||||
specifier: 2.7.0
|
specifier: 2.7.0
|
||||||
version: 2.7.0
|
version: 2.7.0
|
||||||
sharp:
|
sharp:
|
||||||
specifier: 0.32.6
|
specifier: 0.33.2
|
||||||
version: 0.32.6
|
version: 0.33.2
|
||||||
slacc:
|
slacc:
|
||||||
specifier: 0.0.10
|
specifier: 0.0.10
|
||||||
version: 0.0.10
|
version: 0.0.10
|
||||||
|
@ -540,6 +543,9 @@ importers:
|
||||||
'@types/fluent-ffmpeg':
|
'@types/fluent-ffmpeg':
|
||||||
specifier: 2.1.24
|
specifier: 2.1.24
|
||||||
version: 2.1.24
|
version: 2.1.24
|
||||||
|
'@types/htmlescape':
|
||||||
|
specifier: ^1.1.3
|
||||||
|
version: 1.1.3
|
||||||
'@types/http-link-header':
|
'@types/http-link-header':
|
||||||
specifier: 1.0.5
|
specifier: 1.0.5
|
||||||
version: 1.0.5
|
version: 1.0.5
|
||||||
|
@ -1988,7 +1994,7 @@ packages:
|
||||||
'@babel/traverse': 7.23.4
|
'@babel/traverse': 7.23.4
|
||||||
'@babel/types': 7.23.4
|
'@babel/types': 7.23.4
|
||||||
convert-source-map: 2.0.0
|
convert-source-map: 2.0.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
gensync: 1.0.0-beta.2
|
gensync: 1.0.0-beta.2
|
||||||
json5: 2.2.3
|
json5: 2.2.3
|
||||||
semver: 6.3.1
|
semver: 6.3.1
|
||||||
|
@ -2080,7 +2086,7 @@ packages:
|
||||||
'@babel/core': 7.23.3
|
'@babel/core': 7.23.3
|
||||||
'@babel/helper-compilation-targets': 7.23.6
|
'@babel/helper-compilation-targets': 7.23.6
|
||||||
'@babel/helper-plugin-utils': 7.22.5
|
'@babel/helper-plugin-utils': 7.22.5
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
lodash.debounce: 4.0.8
|
lodash.debounce: 4.0.8
|
||||||
resolve: 1.22.8
|
resolve: 1.22.8
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -3263,7 +3269,7 @@ packages:
|
||||||
'@babel/helper-split-export-declaration': 7.22.6
|
'@babel/helper-split-export-declaration': 7.22.6
|
||||||
'@babel/parser': 7.23.4
|
'@babel/parser': 7.23.4
|
||||||
'@babel/types': 7.23.4
|
'@babel/types': 7.23.4
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
globals: 11.12.0
|
globals: 11.12.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -3535,6 +3541,14 @@ packages:
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@emnapi/runtime@0.45.0:
|
||||||
|
resolution: {integrity: sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
tslib: 2.6.2
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
/@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0):
|
/@emotion/use-insertion-effect-with-fallbacks@1.0.1(react@18.2.0):
|
||||||
resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==}
|
resolution: {integrity: sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3965,7 +3979,7 @@ packages:
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
espree: 9.6.1
|
espree: 9.6.1
|
||||||
globals: 13.23.0
|
globals: 13.23.0
|
||||||
ignore: 5.3.0
|
ignore: 5.3.0
|
||||||
|
@ -3982,7 +3996,7 @@ packages:
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
espree: 9.6.1
|
espree: 9.6.1
|
||||||
globals: 13.23.0
|
globals: 13.23.0
|
||||||
ignore: 5.3.0
|
ignore: 5.3.0
|
||||||
|
@ -4195,7 +4209,7 @@ packages:
|
||||||
engines: {node: '>=10.10.0'}
|
engines: {node: '>=10.10.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@humanwhocodes/object-schema': 2.0.1
|
'@humanwhocodes/object-schema': 2.0.1
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
minimatch: 3.1.2
|
minimatch: 3.1.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -4215,6 +4229,194 @@ packages:
|
||||||
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@img/sharp-darwin-arm64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==}
|
||||||
|
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-darwin-x64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==}
|
||||||
|
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-darwin-arm64@1.0.1:
|
||||||
|
resolution: {integrity: sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==}
|
||||||
|
engines: {macos: '>=11', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-darwin-x64@1.0.1:
|
||||||
|
resolution: {integrity: sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==}
|
||||||
|
engines: {macos: '>=10.13', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-linux-arm64@1.0.1:
|
||||||
|
resolution: {integrity: sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==}
|
||||||
|
engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-linux-arm@1.0.1:
|
||||||
|
resolution: {integrity: sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==}
|
||||||
|
engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-linux-s390x@1.0.1:
|
||||||
|
resolution: {integrity: sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==}
|
||||||
|
engines: {glibc: '>=2.28', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-linux-x64@1.0.1:
|
||||||
|
resolution: {integrity: sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==}
|
||||||
|
engines: {glibc: '>=2.26', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-linuxmusl-arm64@1.0.1:
|
||||||
|
resolution: {integrity: sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==}
|
||||||
|
engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-libvips-linuxmusl-x64@1.0.1:
|
||||||
|
resolution: {integrity: sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==}
|
||||||
|
engines: {musl: '>=1.2.2', npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-linux-arm64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==}
|
||||||
|
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-linux-arm@0.33.2:
|
||||||
|
resolution: {integrity: sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==}
|
||||||
|
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-linux-s390x@0.33.2:
|
||||||
|
resolution: {integrity: sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==}
|
||||||
|
engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [s390x]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-linux-x64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==}
|
||||||
|
engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-linuxmusl-arm64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==}
|
||||||
|
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-linuxmusl-x64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==}
|
||||||
|
engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
requiresBuild: true
|
||||||
|
optionalDependencies:
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-wasm32@0.33.2:
|
||||||
|
resolution: {integrity: sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [wasm32]
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
'@emnapi/runtime': 0.45.0
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-win32-ia32@0.33.2:
|
||||||
|
resolution: {integrity: sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [ia32]
|
||||||
|
os: [win32]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/@img/sharp-win32-x64@0.33.2:
|
||||||
|
resolution: {integrity: sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==}
|
||||||
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
/@ioredis/commands@1.2.0:
|
/@ioredis/commands@1.2.0:
|
||||||
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
|
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -4654,12 +4856,12 @@ packages:
|
||||||
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.1)(eslint@8.56.0)
|
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.18.1)(eslint@8.56.0)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@misskey-dev/sharp-read-bmp@1.1.1:
|
/@misskey-dev/sharp-read-bmp@1.2.0:
|
||||||
resolution: {integrity: sha512-X52BQYL/I9mafypQ+wBhst+BUlYiPWnHhKGcF6ybcYSLl+zhcV0q5mezIXHozhM0Sv0A7xCdrWmR7TCNxHLrtQ==}
|
resolution: {integrity: sha512-er4pRakXzHYfEgOFAFfQagqDouG+wLm+kwNq1I30oSdIHDa0wM3KjFpfIGQ25Fks4GcmOl1s7Zh6xoQu5dNjTw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
decode-bmp: 0.2.1
|
decode-bmp: 0.2.1
|
||||||
decode-ico: 0.4.1
|
decode-ico: 0.4.1
|
||||||
sharp: 0.32.6
|
sharp: 0.33.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@misskey-dev/summaly@5.0.3:
|
/@misskey-dev/summaly@5.0.3:
|
||||||
|
@ -7309,6 +7511,10 @@ packages:
|
||||||
'@types/unist': 2.0.6
|
'@types/unist': 2.0.6
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/@types/htmlescape@1.1.3:
|
||||||
|
resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/http-cache-semantics@4.0.4:
|
/@types/http-cache-semantics@4.0.4:
|
||||||
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
||||||
|
|
||||||
|
@ -7710,7 +7916,7 @@ packages:
|
||||||
'@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
|
'@typescript-eslint/type-utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 6.11.0
|
'@typescript-eslint/visitor-keys': 6.11.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.53.0
|
eslint: 8.53.0
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.0
|
ignore: 5.3.0
|
||||||
|
@ -7739,7 +7945,7 @@ packages:
|
||||||
'@typescript-eslint/type-utils': 6.12.0(eslint@8.54.0)(typescript@5.1.6)
|
'@typescript-eslint/type-utils': 6.12.0(eslint@8.54.0)(typescript@5.1.6)
|
||||||
'@typescript-eslint/utils': 6.12.0(eslint@8.54.0)(typescript@5.1.6)
|
'@typescript-eslint/utils': 6.12.0(eslint@8.54.0)(typescript@5.1.6)
|
||||||
'@typescript-eslint/visitor-keys': 6.12.0
|
'@typescript-eslint/visitor-keys': 6.12.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.54.0
|
eslint: 8.54.0
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.0
|
ignore: 5.3.0
|
||||||
|
@ -7768,7 +7974,7 @@ packages:
|
||||||
'@typescript-eslint/type-utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/type-utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 6.18.1
|
'@typescript-eslint/visitor-keys': 6.18.1
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
graphemer: 1.4.0
|
graphemer: 1.4.0
|
||||||
ignore: 5.3.0
|
ignore: 5.3.0
|
||||||
|
@ -7794,7 +8000,7 @@ packages:
|
||||||
'@typescript-eslint/types': 6.11.0
|
'@typescript-eslint/types': 6.11.0
|
||||||
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 6.11.0
|
'@typescript-eslint/visitor-keys': 6.11.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.53.0
|
eslint: 8.53.0
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -7815,7 +8021,7 @@ packages:
|
||||||
'@typescript-eslint/types': 6.12.0
|
'@typescript-eslint/types': 6.12.0
|
||||||
'@typescript-eslint/typescript-estree': 6.12.0(typescript@5.1.6)
|
'@typescript-eslint/typescript-estree': 6.12.0(typescript@5.1.6)
|
||||||
'@typescript-eslint/visitor-keys': 6.12.0
|
'@typescript-eslint/visitor-keys': 6.12.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.54.0
|
eslint: 8.54.0
|
||||||
typescript: 5.1.6
|
typescript: 5.1.6
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -7836,7 +8042,7 @@ packages:
|
||||||
'@typescript-eslint/types': 6.18.1
|
'@typescript-eslint/types': 6.18.1
|
||||||
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
|
||||||
'@typescript-eslint/visitor-keys': 6.18.1
|
'@typescript-eslint/visitor-keys': 6.18.1
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -7879,7 +8085,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.11.0(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.11.0(eslint@8.53.0)(typescript@5.3.3)
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.53.0
|
eslint: 8.53.0
|
||||||
ts-api-utils: 1.0.3(typescript@5.3.3)
|
ts-api-utils: 1.0.3(typescript@5.3.3)
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
|
@ -7899,7 +8105,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 6.12.0(typescript@5.1.6)
|
'@typescript-eslint/typescript-estree': 6.12.0(typescript@5.1.6)
|
||||||
'@typescript-eslint/utils': 6.12.0(eslint@8.54.0)(typescript@5.1.6)
|
'@typescript-eslint/utils': 6.12.0(eslint@8.54.0)(typescript@5.1.6)
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.54.0
|
eslint: 8.54.0
|
||||||
ts-api-utils: 1.0.3(typescript@5.1.6)
|
ts-api-utils: 1.0.3(typescript@5.1.6)
|
||||||
typescript: 5.1.6
|
typescript: 5.1.6
|
||||||
|
@ -7919,7 +8125,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
|
'@typescript-eslint/typescript-estree': 6.18.1(typescript@5.3.3)
|
||||||
'@typescript-eslint/utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
|
'@typescript-eslint/utils': 6.18.1(eslint@8.56.0)(typescript@5.3.3)
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
ts-api-utils: 1.0.3(typescript@5.3.3)
|
ts-api-utils: 1.0.3(typescript@5.3.3)
|
||||||
typescript: 5.3.3
|
typescript: 5.3.3
|
||||||
|
@ -7953,7 +8159,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 6.11.0
|
'@typescript-eslint/types': 6.11.0
|
||||||
'@typescript-eslint/visitor-keys': 6.11.0
|
'@typescript-eslint/visitor-keys': 6.11.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
semver: 7.5.4
|
semver: 7.5.4
|
||||||
|
@ -7974,7 +8180,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 6.12.0
|
'@typescript-eslint/types': 6.12.0
|
||||||
'@typescript-eslint/visitor-keys': 6.12.0
|
'@typescript-eslint/visitor-keys': 6.12.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
semver: 7.5.4
|
semver: 7.5.4
|
||||||
|
@ -7995,7 +8201,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@typescript-eslint/types': 6.18.1
|
'@typescript-eslint/types': 6.18.1
|
||||||
'@typescript-eslint/visitor-keys': 6.18.1
|
'@typescript-eslint/visitor-keys': 6.18.1
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
globby: 11.1.0
|
globby: 11.1.0
|
||||||
is-glob: 4.0.3
|
is-glob: 4.0.3
|
||||||
minimatch: 9.0.3
|
minimatch: 9.0.3
|
||||||
|
@ -8425,7 +8631,7 @@ packages:
|
||||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
@ -8433,7 +8639,7 @@ packages:
|
||||||
resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==}
|
resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==}
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -8818,7 +9024,7 @@ packages:
|
||||||
resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==}
|
resolution: {integrity: sha512-TAlMYvOuwGyLK3PfBb5WKBXZmXz2fVCgv23d6zZFdle/q3gPjmxBaeuC0pY0Dzs5PWMSgfqqEZkrye19GlDTgw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
archy: 1.0.0
|
archy: 1.0.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
fastq: 1.15.0
|
fastq: 1.15.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -9066,6 +9272,7 @@ packages:
|
||||||
buffer: 5.7.1
|
buffer: 5.7.1
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/blob-util@2.0.2:
|
/blob-util@2.0.2:
|
||||||
resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
|
resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==}
|
||||||
|
@ -9232,6 +9439,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
base64-js: 1.5.1
|
base64-js: 1.5.1
|
||||||
ieee754: 1.2.1
|
ieee754: 1.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/buffer@6.0.3:
|
/buffer@6.0.3:
|
||||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
||||||
|
@ -9594,6 +9802,7 @@ packages:
|
||||||
|
|
||||||
/chownr@1.1.4:
|
/chownr@1.1.4:
|
||||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/chownr@2.0.0:
|
/chownr@2.0.0:
|
||||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||||
|
@ -10348,6 +10557,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.2
|
ms: 2.1.2
|
||||||
supports-color: 5.5.0
|
supports-color: 5.5.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/debug@4.3.4(supports-color@8.1.1):
|
/debug@4.3.4(supports-color@8.1.1):
|
||||||
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
|
||||||
|
@ -10360,7 +10570,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
ms: 2.1.2
|
ms: 2.1.2
|
||||||
supports-color: 8.1.1
|
supports-color: 8.1.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/decamelize-keys@1.1.1:
|
/decamelize-keys@1.1.1:
|
||||||
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
|
resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==}
|
||||||
|
@ -10456,11 +10665,6 @@ packages:
|
||||||
which-typed-array: 1.1.11
|
which-typed-array: 1.1.11
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/deep-extend@0.6.0:
|
|
||||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
|
||||||
engines: {node: '>=4.0.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/deep-is@0.1.4:
|
/deep-is@0.1.4:
|
||||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -10577,7 +10781,7 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
address: 1.2.2
|
address: 1.2.2
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -10899,7 +11103,7 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
esbuild: '>=0.12 <1'
|
esbuild: '>=0.12 <1'
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
esbuild: 0.18.20
|
esbuild: 0.18.20
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -11215,7 +11419,7 @@ packages:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
doctrine: 3.0.0
|
doctrine: 3.0.0
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 7.2.2
|
eslint-scope: 7.2.2
|
||||||
|
@ -11262,7 +11466,7 @@ packages:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
doctrine: 3.0.0
|
doctrine: 3.0.0
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 7.2.2
|
eslint-scope: 7.2.2
|
||||||
|
@ -11309,7 +11513,7 @@ packages:
|
||||||
ajv: 6.12.6
|
ajv: 6.12.6
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
doctrine: 3.0.0
|
doctrine: 3.0.0
|
||||||
escape-string-regexp: 4.0.0
|
escape-string-regexp: 4.0.0
|
||||||
eslint-scope: 7.2.2
|
eslint-scope: 7.2.2
|
||||||
|
@ -11507,11 +11711,6 @@ packages:
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/expand-template@2.0.3:
|
|
||||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
|
||||||
engines: {node: '>=6'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/expect@29.7.0:
|
/expect@29.7.0:
|
||||||
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
|
resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==}
|
||||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||||
|
@ -11950,7 +12149,7 @@ packages:
|
||||||
debug:
|
debug:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
|
|
||||||
/for-each@0.3.3:
|
/for-each@0.3.3:
|
||||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||||
|
@ -12015,6 +12214,7 @@ packages:
|
||||||
|
|
||||||
/fs-constants@1.0.0:
|
/fs-constants@1.0.0:
|
||||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/fs-extra@11.1.1:
|
/fs-extra@11.1.1:
|
||||||
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
|
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
|
||||||
|
@ -12203,10 +12403,6 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/github-from-package@0.0.0:
|
|
||||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/github-slugger@2.0.0:
|
/github-slugger@2.0.0:
|
||||||
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
|
resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -12550,6 +12746,11 @@ packages:
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/htmlescape@1.1.1:
|
||||||
|
resolution: {integrity: sha512-eVcrzgbR4tim7c7soKQKtxa/kQM4TzjnlU83rcZ9bHU6t31ehfV7SktN6McWgwPWg+JYMA/O3qpGxBvFq1z2Jg==}
|
||||||
|
engines: {node: '>=0.10'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/htmlparser2@8.0.1:
|
/htmlparser2@8.0.1:
|
||||||
resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==}
|
resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -12590,7 +12791,7 @@ packages:
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.0
|
agent-base: 7.1.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -12629,7 +12830,7 @@ packages:
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 6.0.2
|
agent-base: 6.0.2
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
@ -12638,7 +12839,7 @@ packages:
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.0
|
agent-base: 7.1.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -12744,6 +12945,7 @@ packages:
|
||||||
|
|
||||||
/ini@1.3.8:
|
/ini@1.3.8:
|
||||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/ini@2.0.0:
|
/ini@2.0.0:
|
||||||
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
|
resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==}
|
||||||
|
@ -12799,7 +13001,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@ioredis/commands': 1.2.0
|
'@ioredis/commands': 1.2.0
|
||||||
cluster-key-slot: 1.1.2
|
cluster-key-slot: 1.1.2
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
denque: 2.1.0
|
denque: 2.1.0
|
||||||
lodash.defaults: 4.2.0
|
lodash.defaults: 4.2.0
|
||||||
lodash.isarguments: 3.1.0
|
lodash.isarguments: 3.1.0
|
||||||
|
@ -13229,7 +13431,7 @@ packages:
|
||||||
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
|
resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
istanbul-lib-coverage: 3.2.2
|
istanbul-lib-coverage: 3.2.2
|
||||||
source-map: 0.6.1
|
source-map: 0.6.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
|
@ -14784,7 +14986,7 @@ packages:
|
||||||
resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
|
resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/debug': 4.1.12
|
'@types/debug': 4.1.12
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
decode-named-character-reference: 1.0.2
|
decode-named-character-reference: 1.0.2
|
||||||
devlop: 1.1.0
|
devlop: 1.1.0
|
||||||
micromark-core-commonmark: 2.0.0
|
micromark-core-commonmark: 2.0.0
|
||||||
|
@ -14964,6 +15166,7 @@ packages:
|
||||||
|
|
||||||
/mkdirp-classic@0.5.3:
|
/mkdirp-classic@0.5.3:
|
||||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/mkdirp@0.5.6:
|
/mkdirp@0.5.6:
|
||||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||||
|
@ -15139,10 +15342,6 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/napi-build-utils@1.0.2:
|
|
||||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/natural-compare@1.4.0:
|
/natural-compare@1.4.0:
|
||||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -15189,21 +15388,10 @@ packages:
|
||||||
path-to-regexp: 1.8.0
|
path-to-regexp: 1.8.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/node-abi@3.31.0:
|
|
||||||
resolution: {integrity: sha512-eSKV6s+APenqVh8ubJyiu/YhZgxQpGP66ntzUb3lY1xB9ukSRaGnx0AIxI+IM+1+IVYC1oWobgG5L3Lt9ARykQ==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
dependencies:
|
|
||||||
semver: 7.5.4
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/node-abort-controller@3.1.1:
|
/node-abort-controller@3.1.1:
|
||||||
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/node-addon-api@6.1.0:
|
|
||||||
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/node-addon-api@7.0.0:
|
/node-addon-api@7.0.0:
|
||||||
resolution: {integrity: sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==}
|
resolution: {integrity: sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -16479,25 +16667,6 @@ packages:
|
||||||
resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
|
resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/prebuild-install@7.1.1:
|
|
||||||
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
detect-libc: 2.0.2
|
|
||||||
expand-template: 2.0.3
|
|
||||||
github-from-package: 0.0.0
|
|
||||||
minimist: 1.2.8
|
|
||||||
mkdirp-classic: 0.5.3
|
|
||||||
napi-build-utils: 1.0.2
|
|
||||||
node-abi: 3.31.0
|
|
||||||
pump: 3.0.0
|
|
||||||
rc: 1.2.8
|
|
||||||
simple-get: 4.0.1
|
|
||||||
tar-fs: 2.1.1
|
|
||||||
tunnel-agent: 0.6.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/prelude-ls@1.2.1:
|
/prelude-ls@1.2.1:
|
||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
@ -16889,16 +17058,6 @@ packages:
|
||||||
iconv-lite: 0.4.24
|
iconv-lite: 0.4.24
|
||||||
unpipe: 1.0.0
|
unpipe: 1.0.0
|
||||||
|
|
||||||
/rc@1.2.8:
|
|
||||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
deep-extend: 0.6.0
|
|
||||||
ini: 1.3.8
|
|
||||||
minimist: 1.2.8
|
|
||||||
strip-json-comments: 2.0.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/rdf-canonize@3.4.0:
|
/rdf-canonize@3.4.0:
|
||||||
resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==}
|
resolution: {integrity: sha512-fUeWjrkOO0t1rg7B2fdyDTvngj+9RlUyL92vOdiB7c0FPguWVsniIMjEtHH+meLBO9rzkUlUzBVXgWrjI8P9LA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -17600,19 +17759,34 @@ packages:
|
||||||
kind-of: 6.0.3
|
kind-of: 6.0.3
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/sharp@0.32.6:
|
/sharp@0.33.2:
|
||||||
resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==}
|
resolution: {integrity: sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==}
|
||||||
engines: {node: '>=14.15.0'}
|
engines: {libvips: '>=8.15.1', node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
dependencies:
|
dependencies:
|
||||||
color: 4.2.3
|
color: 4.2.3
|
||||||
detect-libc: 2.0.2
|
detect-libc: 2.0.2
|
||||||
node-addon-api: 6.1.0
|
|
||||||
prebuild-install: 7.1.1
|
|
||||||
semver: 7.5.4
|
semver: 7.5.4
|
||||||
simple-get: 4.0.1
|
optionalDependencies:
|
||||||
tar-fs: 3.0.4
|
'@img/sharp-darwin-arm64': 0.33.2
|
||||||
tunnel-agent: 0.6.0
|
'@img/sharp-darwin-x64': 0.33.2
|
||||||
|
'@img/sharp-libvips-darwin-arm64': 1.0.1
|
||||||
|
'@img/sharp-libvips-darwin-x64': 1.0.1
|
||||||
|
'@img/sharp-libvips-linux-arm': 1.0.1
|
||||||
|
'@img/sharp-libvips-linux-arm64': 1.0.1
|
||||||
|
'@img/sharp-libvips-linux-s390x': 1.0.1
|
||||||
|
'@img/sharp-libvips-linux-x64': 1.0.1
|
||||||
|
'@img/sharp-libvips-linuxmusl-arm64': 1.0.1
|
||||||
|
'@img/sharp-libvips-linuxmusl-x64': 1.0.1
|
||||||
|
'@img/sharp-linux-arm': 0.33.2
|
||||||
|
'@img/sharp-linux-arm64': 0.33.2
|
||||||
|
'@img/sharp-linux-s390x': 0.33.2
|
||||||
|
'@img/sharp-linux-x64': 0.33.2
|
||||||
|
'@img/sharp-linuxmusl-arm64': 0.33.2
|
||||||
|
'@img/sharp-linuxmusl-x64': 0.33.2
|
||||||
|
'@img/sharp-wasm32': 0.33.2
|
||||||
|
'@img/sharp-win32-ia32': 0.33.2
|
||||||
|
'@img/sharp-win32-x64': 0.33.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/shebang-command@1.2.0:
|
/shebang-command@1.2.0:
|
||||||
|
@ -17670,24 +17844,12 @@ packages:
|
||||||
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
/simple-concat@1.0.1:
|
|
||||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/simple-get@4.0.1:
|
|
||||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
|
||||||
dependencies:
|
|
||||||
decompress-response: 6.0.0
|
|
||||||
once: 1.4.0
|
|
||||||
simple-concat: 1.0.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/simple-oauth2@5.0.0:
|
/simple-oauth2@5.0.0:
|
||||||
resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==}
|
resolution: {integrity: sha512-8291lo/z5ZdpmiOFzOs1kF3cxn22bMj5FFH+DNUppLJrpoIlM1QnFiE7KpshHu3J3i21TVcx4yW+gXYjdCKDLQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@hapi/hoek': 10.0.1
|
'@hapi/hoek': 10.0.1
|
||||||
'@hapi/wreck': 18.0.1
|
'@hapi/wreck': 18.0.1
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
joi: 17.7.0
|
joi: 17.7.0
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -17888,7 +18050,7 @@ packages:
|
||||||
engines: {node: '>= 14'}
|
engines: {node: '>= 14'}
|
||||||
dependencies:
|
dependencies:
|
||||||
agent-base: 7.1.0
|
agent-base: 7.1.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
socks: 2.7.1
|
socks: 2.7.1
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
@ -18041,7 +18203,7 @@ packages:
|
||||||
arg: 5.0.2
|
arg: 5.0.2
|
||||||
bluebird: 3.7.2
|
bluebird: 3.7.2
|
||||||
check-more-types: 2.24.0
|
check-more-types: 2.24.0
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
execa: 5.1.1
|
execa: 5.1.1
|
||||||
lazy-ass: 1.6.0
|
lazy-ass: 1.6.0
|
||||||
ps-tree: 1.2.0
|
ps-tree: 1.2.0
|
||||||
|
@ -18251,11 +18413,6 @@ packages:
|
||||||
min-indent: 1.0.1
|
min-indent: 1.0.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/strip-json-comments@2.0.1:
|
|
||||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/strip-json-comments@3.1.1:
|
/strip-json-comments@3.1.1:
|
||||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -18362,14 +18519,7 @@ packages:
|
||||||
mkdirp-classic: 0.5.3
|
mkdirp-classic: 0.5.3
|
||||||
pump: 3.0.0
|
pump: 3.0.0
|
||||||
tar-stream: 2.2.0
|
tar-stream: 2.2.0
|
||||||
|
dev: true
|
||||||
/tar-fs@3.0.4:
|
|
||||||
resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==}
|
|
||||||
dependencies:
|
|
||||||
mkdirp-classic: 0.5.3
|
|
||||||
pump: 3.0.0
|
|
||||||
tar-stream: 3.1.6
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/tar-stream@2.2.0:
|
/tar-stream@2.2.0:
|
||||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||||
|
@ -18380,6 +18530,7 @@ packages:
|
||||||
fs-constants: 1.0.0
|
fs-constants: 1.0.0
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
readable-stream: 3.6.2
|
readable-stream: 3.6.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tar-stream@3.1.6:
|
/tar-stream@3.1.6:
|
||||||
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
|
resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==}
|
||||||
|
@ -18772,6 +18923,7 @@ packages:
|
||||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
safe-buffer: 5.2.1
|
safe-buffer: 5.2.1
|
||||||
|
dev: true
|
||||||
|
|
||||||
/tweetnacl@0.14.5:
|
/tweetnacl@0.14.5:
|
||||||
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
|
resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==}
|
||||||
|
@ -18953,7 +19105,7 @@ packages:
|
||||||
chalk: 4.1.2
|
chalk: 4.1.2
|
||||||
cli-highlight: 2.1.11
|
cli-highlight: 2.1.11
|
||||||
dayjs: 1.11.10
|
dayjs: 1.11.10
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
dotenv: 16.0.3
|
dotenv: 16.0.3
|
||||||
glob: 10.3.10
|
glob: 10.3.10
|
||||||
ioredis: 5.3.2
|
ioredis: 5.3.2
|
||||||
|
@ -19288,7 +19440,7 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dependencies:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
mlly: 1.5.0
|
mlly: 1.5.0
|
||||||
pathe: 1.1.2
|
pathe: 1.1.2
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
|
@ -19400,7 +19552,7 @@ packages:
|
||||||
acorn-walk: 8.3.2
|
acorn-walk: 8.3.2
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
chai: 4.3.10
|
chai: 4.3.10
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
happy-dom: 10.0.3
|
happy-dom: 10.0.3
|
||||||
local-pkg: 0.4.3
|
local-pkg: 0.4.3
|
||||||
magic-string: 0.30.5
|
magic-string: 0.30.5
|
||||||
|
@ -19518,7 +19670,7 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
eslint: '>=6.0.0'
|
eslint: '>=6.0.0'
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.3.4(supports-color@5.5.0)
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
eslint: 8.56.0
|
eslint: 8.56.0
|
||||||
eslint-scope: 7.2.2
|
eslint-scope: 7.2.2
|
||||||
eslint-visitor-keys: 3.4.3
|
eslint-visitor-keys: 3.4.3
|
||||||
|
|
Loading…
Reference in a new issue