Compare commits
No commits in common. "develop" and "2025.9.1-alpha.0" have entirely different histories.
develop
...
2025.9.1-a
|
@ -105,16 +105,6 @@ port: 3000
|
||||||
# socket: /path/to/misskey.sock
|
# socket: /path/to/misskey.sock
|
||||||
# chmodSocket: '777'
|
# chmodSocket: '777'
|
||||||
|
|
||||||
# Proxy trust settings
|
|
||||||
#
|
|
||||||
# Changes how the server interpret the origin IP of the request.
|
|
||||||
#
|
|
||||||
# Any format supported by Fastify is accepted.
|
|
||||||
# Default: trust all proxies (i.e. trustProxy: true)
|
|
||||||
# See: https://fastify.dev/docs/latest/reference/server/#trustproxy
|
|
||||||
#
|
|
||||||
# trustProxy: 1
|
|
||||||
|
|
||||||
# ┌──────────────────────────┐
|
# ┌──────────────────────────┐
|
||||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||||
|
|
||||||
|
|
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -1,27 +1,19 @@
|
||||||
## 2025.9.1
|
## 2025.9.1
|
||||||
|
|
||||||
### NOTE
|
|
||||||
- pnpm 10.16.0 が必要です
|
|
||||||
|
|
||||||
### General
|
### General
|
||||||
- Feat: 予約投稿ができるようになりました
|
|
||||||
- デフォルトで作成可能数は1になっています。適宜ロールのポリシーで設定を行ってください。
|
|
||||||
- Enhance: 広告ごとにセンシティブフラグを設定できるようになりました
|
- Enhance: 広告ごとにセンシティブフラグを設定できるようになりました
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Feat: アカウントのQRコードを表示・読み取りできるようになりました
|
- Feat: アカウントのQRコードを表示・読み取りできるようになりました
|
||||||
- Feat: 動画を圧縮してアップロードできるようになりました
|
|
||||||
- Enhance: チャットの日本語名称がダイレクトメッセージに戻るとともに、ベータ版機能ではなくなりました
|
- Enhance: チャットの日本語名称がダイレクトメッセージに戻るとともに、ベータ版機能ではなくなりました
|
||||||
- Enhance: 画像編集にマスクエフェクト(塗りつぶし、ぼかし、モザイク)を追加
|
- Enhance: 画像編集にマスクエフェクトを追加
|
||||||
- Enhance: ウォーターマークにアカウントのQRコードを追加できるように
|
- Enhance: ウォーターマークにアカウントのQRコードを追加できるように
|
||||||
- Enhance: テーマをドラッグ&ドロップできるように
|
|
||||||
- Enhance: 絵文字ピッカーのサイズをより大きくできるように
|
|
||||||
- Enhance: 時刻計算のための基準値を一か所で管理するようにし、パフォーマンスを向上
|
- Enhance: 時刻計算のための基準値を一か所で管理するようにし、パフォーマンスを向上
|
||||||
- Fix: iOSで、デバイスがダークモードだと初回読み込み時にエラーになる問題を修正
|
- Fix: iOSで、デバイスがダークモードだと初回読み込み時にエラーになる問題を修正
|
||||||
- Fix: アクティビティウィジェットのグラフモードが動作しない問題を修正
|
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Enhance: ユーザーIPを確実に取得できるために設定ファイルにFastifyOptions.trustProxyを追加しました
|
-
|
||||||
|
|
||||||
|
|
||||||
## 2025.9.0
|
## 2025.9.0
|
||||||
|
|
||||||
|
|
|
@ -3194,7 +3194,6 @@ _imageEffector:
|
||||||
mirror: "Mirror"
|
mirror: "Mirror"
|
||||||
invert: "Invert Colors"
|
invert: "Invert Colors"
|
||||||
grayscale: "Grayscale"
|
grayscale: "Grayscale"
|
||||||
blur: "Blur"
|
|
||||||
colorAdjust: "Color Correction"
|
colorAdjust: "Color Correction"
|
||||||
colorClamp: "Color Compression"
|
colorClamp: "Color Compression"
|
||||||
colorClampAdvanced: "Color Compression (Advanced)"
|
colorClampAdvanced: "Color Compression (Advanced)"
|
||||||
|
@ -3210,8 +3209,6 @@ _imageEffector:
|
||||||
angle: "Angle"
|
angle: "Angle"
|
||||||
scale: "Size"
|
scale: "Size"
|
||||||
size: "Size"
|
size: "Size"
|
||||||
radius: "Radius"
|
|
||||||
samples: "Samples"
|
|
||||||
color: "Color"
|
color: "Color"
|
||||||
opacity: "Opacity"
|
opacity: "Opacity"
|
||||||
normalize: "Normalize"
|
normalize: "Normalize"
|
||||||
|
|
|
@ -1030,10 +1030,6 @@ export interface Locale extends ILocale {
|
||||||
* 処理中
|
* 処理中
|
||||||
*/
|
*/
|
||||||
"processing": string;
|
"processing": string;
|
||||||
/**
|
|
||||||
* 準備中
|
|
||||||
*/
|
|
||||||
"preprocessing": string;
|
|
||||||
/**
|
/**
|
||||||
* プレビュー
|
* プレビュー
|
||||||
*/
|
*/
|
||||||
|
@ -5286,10 +5282,6 @@ export interface Locale extends ILocale {
|
||||||
* 下書き
|
* 下書き
|
||||||
*/
|
*/
|
||||||
"draft": string;
|
"draft": string;
|
||||||
/**
|
|
||||||
* 下書きと予約投稿
|
|
||||||
*/
|
|
||||||
"draftsAndScheduledNotes": string;
|
|
||||||
/**
|
/**
|
||||||
* リアクションする際に確認する
|
* リアクションする際に確認する
|
||||||
*/
|
*/
|
||||||
|
@ -5517,14 +5509,6 @@ export interface Locale extends ILocale {
|
||||||
* 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。
|
* 低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。
|
||||||
*/
|
*/
|
||||||
"defaultImageCompressionLevel_description": string;
|
"defaultImageCompressionLevel_description": string;
|
||||||
/**
|
|
||||||
* デフォルトの圧縮度
|
|
||||||
*/
|
|
||||||
"defaultCompressionLevel": string;
|
|
||||||
/**
|
|
||||||
* 低くすると品質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、品質は低下します。
|
|
||||||
*/
|
|
||||||
"defaultCompressionLevel_description": string;
|
|
||||||
/**
|
/**
|
||||||
* 分
|
* 分
|
||||||
*/
|
*/
|
||||||
|
@ -5557,56 +5541,6 @@ export interface Locale extends ILocale {
|
||||||
* ユーザー指定ノートを作成
|
* ユーザー指定ノートを作成
|
||||||
*/
|
*/
|
||||||
"createUserSpecifiedNote": string;
|
"createUserSpecifiedNote": string;
|
||||||
/**
|
|
||||||
* 投稿を予約
|
|
||||||
*/
|
|
||||||
"schedulePost": string;
|
|
||||||
/**
|
|
||||||
* {x}に投稿を予約します
|
|
||||||
*/
|
|
||||||
"scheduleToPostOnX": ParameterizedString<"x">;
|
|
||||||
/**
|
|
||||||
* {x}に投稿が予約されています
|
|
||||||
*/
|
|
||||||
"scheduledToPostOnX": ParameterizedString<"x">;
|
|
||||||
/**
|
|
||||||
* 予約
|
|
||||||
*/
|
|
||||||
"schedule": string;
|
|
||||||
/**
|
|
||||||
* 予約
|
|
||||||
*/
|
|
||||||
"scheduled": string;
|
|
||||||
"_compression": {
|
|
||||||
"_quality": {
|
|
||||||
/**
|
|
||||||
* 高品質
|
|
||||||
*/
|
|
||||||
"high": string;
|
|
||||||
/**
|
|
||||||
* 中品質
|
|
||||||
*/
|
|
||||||
"medium": string;
|
|
||||||
/**
|
|
||||||
* 低品質
|
|
||||||
*/
|
|
||||||
"low": string;
|
|
||||||
};
|
|
||||||
"_size": {
|
|
||||||
/**
|
|
||||||
* サイズ大
|
|
||||||
*/
|
|
||||||
"large": string;
|
|
||||||
/**
|
|
||||||
* サイズ中
|
|
||||||
*/
|
|
||||||
"medium": string;
|
|
||||||
/**
|
|
||||||
* サイズ小
|
|
||||||
*/
|
|
||||||
"small": string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
"_order": {
|
"_order": {
|
||||||
/**
|
/**
|
||||||
* 新しい順
|
* 新しい順
|
||||||
|
@ -7957,10 +7891,6 @@ export interface Locale extends ILocale {
|
||||||
* サーバーサイドのノートの下書きの作成可能数
|
* サーバーサイドのノートの下書きの作成可能数
|
||||||
*/
|
*/
|
||||||
"noteDraftLimit": string;
|
"noteDraftLimit": string;
|
||||||
/**
|
|
||||||
* 予約投稿の同時作成可能数
|
|
||||||
*/
|
|
||||||
"scheduledNoteLimit": string;
|
|
||||||
/**
|
/**
|
||||||
* ウォーターマーク機能の使用可否
|
* ウォーターマーク機能の使用可否
|
||||||
*/
|
*/
|
||||||
|
@ -10356,14 +10286,6 @@ export interface Locale extends ILocale {
|
||||||
* アンケートの結果が出ました
|
* アンケートの結果が出ました
|
||||||
*/
|
*/
|
||||||
"pollEnded": string;
|
"pollEnded": string;
|
||||||
/**
|
|
||||||
* 予約ノートが投稿されました
|
|
||||||
*/
|
|
||||||
"scheduledNotePosted": string;
|
|
||||||
/**
|
|
||||||
* 予約ノートの投稿に失敗しました
|
|
||||||
*/
|
|
||||||
"scheduledNotePostFailed": string;
|
|
||||||
/**
|
/**
|
||||||
* 新しい投稿
|
* 新しい投稿
|
||||||
*/
|
*/
|
||||||
|
@ -12424,14 +12346,6 @@ export interface Locale extends ILocale {
|
||||||
* 白黒
|
* 白黒
|
||||||
*/
|
*/
|
||||||
"grayscale": string;
|
"grayscale": string;
|
||||||
/**
|
|
||||||
* ぼかし
|
|
||||||
*/
|
|
||||||
"blur": string;
|
|
||||||
/**
|
|
||||||
* モザイク
|
|
||||||
*/
|
|
||||||
"pixelate": string;
|
|
||||||
/**
|
/**
|
||||||
* 色調補正
|
* 色調補正
|
||||||
*/
|
*/
|
||||||
|
@ -12477,9 +12391,9 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"tearing": string;
|
"tearing": string;
|
||||||
/**
|
/**
|
||||||
* 塗りつぶし
|
* 塗りつぶし(四角)
|
||||||
*/
|
*/
|
||||||
"fill": string;
|
"fillSquare": string;
|
||||||
};
|
};
|
||||||
"_fxProps": {
|
"_fxProps": {
|
||||||
/**
|
/**
|
||||||
|
@ -12494,14 +12408,6 @@ export interface Locale extends ILocale {
|
||||||
* サイズ
|
* サイズ
|
||||||
*/
|
*/
|
||||||
"size": string;
|
"size": string;
|
||||||
/**
|
|
||||||
* 半径
|
|
||||||
*/
|
|
||||||
"radius": string;
|
|
||||||
/**
|
|
||||||
* サンプル数
|
|
||||||
*/
|
|
||||||
"samples": string;
|
|
||||||
/**
|
/**
|
||||||
* 位置
|
* 位置
|
||||||
*/
|
*/
|
||||||
|
@ -12618,10 +12524,6 @@ export interface Locale extends ILocale {
|
||||||
* 黒色にする
|
* 黒色にする
|
||||||
*/
|
*/
|
||||||
"zoomLinesBlack": string;
|
"zoomLinesBlack": string;
|
||||||
/**
|
|
||||||
* 円形
|
|
||||||
*/
|
|
||||||
"circle": string;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
|
@ -12681,18 +12583,6 @@ export interface Locale extends ILocale {
|
||||||
* 下書き一覧
|
* 下書き一覧
|
||||||
*/
|
*/
|
||||||
"listDrafts": string;
|
"listDrafts": string;
|
||||||
/**
|
|
||||||
* 投稿予約
|
|
||||||
*/
|
|
||||||
"schedule": string;
|
|
||||||
/**
|
|
||||||
* 予約投稿一覧
|
|
||||||
*/
|
|
||||||
"listScheduledNotes": string;
|
|
||||||
/**
|
|
||||||
* 予約解除
|
|
||||||
*/
|
|
||||||
"cancelSchedule": string;
|
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* 二次元コード
|
* 二次元コード
|
||||||
|
|
|
@ -253,7 +253,6 @@ noteDeleteConfirm: "このノートを削除しますか?"
|
||||||
pinLimitExceeded: "これ以上ピン留めできません"
|
pinLimitExceeded: "これ以上ピン留めできません"
|
||||||
done: "完了"
|
done: "完了"
|
||||||
processing: "処理中"
|
processing: "処理中"
|
||||||
preprocessing: "準備中"
|
|
||||||
preview: "プレビュー"
|
preview: "プレビュー"
|
||||||
default: "デフォルト"
|
default: "デフォルト"
|
||||||
defaultValueIs: "デフォルト: {value}"
|
defaultValueIs: "デフォルト: {value}"
|
||||||
|
@ -1317,7 +1316,6 @@ acknowledgeNotesAndEnable: "注意事項を理解した上でオンにします
|
||||||
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
|
federationSpecified: "このサーバーはホワイトリスト連合で運用されています。管理者が指定したサーバー以外とやり取りすることはできません。"
|
||||||
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
|
federationDisabled: "このサーバーは連合が無効化されています。他のサーバーのユーザーとやり取りすることはできません。"
|
||||||
draft: "下書き"
|
draft: "下書き"
|
||||||
draftsAndScheduledNotes: "下書きと予約投稿"
|
|
||||||
confirmOnReact: "リアクションする際に確認する"
|
confirmOnReact: "リアクションする際に確認する"
|
||||||
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
|
reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
|
||||||
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
|
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
|
||||||
|
@ -1374,8 +1372,6 @@ redisplayAllTips: "全ての「ヒントとコツ」を再表示"
|
||||||
hideAllTips: "全ての「ヒントとコツ」を非表示"
|
hideAllTips: "全ての「ヒントとコツ」を非表示"
|
||||||
defaultImageCompressionLevel: "デフォルトの画像圧縮度"
|
defaultImageCompressionLevel: "デフォルトの画像圧縮度"
|
||||||
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。"
|
defaultImageCompressionLevel_description: "低くすると画質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、画質は低下します。"
|
||||||
defaultCompressionLevel: "デフォルトの圧縮度"
|
|
||||||
defaultCompressionLevel_description: "低くすると品質を保てますが、ファイルサイズは増加します。<br>高くするとファイルサイズを減らせますが、品質は低下します。"
|
|
||||||
inMinutes: "分"
|
inMinutes: "分"
|
||||||
inDays: "日"
|
inDays: "日"
|
||||||
safeModeEnabled: "セーフモードが有効です"
|
safeModeEnabled: "セーフモードが有効です"
|
||||||
|
@ -1384,21 +1380,6 @@ customCssIsDisabledBecauseSafeMode: "セーフモードが有効なため、カ
|
||||||
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
|
themeIsDefaultBecauseSafeMode: "セーフモードが有効な間はデフォルトのテーマが使用されます。セーフモードをオフにすると元に戻ります。"
|
||||||
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
|
thankYouForTestingBeta: "ベータ版の検証にご協力いただきありがとうございます!"
|
||||||
createUserSpecifiedNote: "ユーザー指定ノートを作成"
|
createUserSpecifiedNote: "ユーザー指定ノートを作成"
|
||||||
schedulePost: "投稿を予約"
|
|
||||||
scheduleToPostOnX: "{x}に投稿を予約します"
|
|
||||||
scheduledToPostOnX: "{x}に投稿が予約されています"
|
|
||||||
schedule: "予約"
|
|
||||||
scheduled: "予約"
|
|
||||||
|
|
||||||
_compression:
|
|
||||||
_quality:
|
|
||||||
high: "高品質"
|
|
||||||
medium: "中品質"
|
|
||||||
low: "低品質"
|
|
||||||
_size:
|
|
||||||
large: "サイズ大"
|
|
||||||
medium: "サイズ中"
|
|
||||||
small: "サイズ小"
|
|
||||||
|
|
||||||
_order:
|
_order:
|
||||||
newest: "新しい順"
|
newest: "新しい順"
|
||||||
|
@ -2062,7 +2043,6 @@ _role:
|
||||||
uploadableFileTypes_caption: "MIMEタイプを指定します。改行で区切って複数指定できるほか、アスタリスク(*)でワイルドカード指定できます。(例: image/*)"
|
uploadableFileTypes_caption: "MIMEタイプを指定します。改行で区切って複数指定できるほか、アスタリスク(*)でワイルドカード指定できます。(例: image/*)"
|
||||||
uploadableFileTypes_caption2: "ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。"
|
uploadableFileTypes_caption2: "ファイルによっては種別を判定できないことがあります。そのようなファイルを許可する場合は {x} を指定に追加してください。"
|
||||||
noteDraftLimit: "サーバーサイドのノートの下書きの作成可能数"
|
noteDraftLimit: "サーバーサイドのノートの下書きの作成可能数"
|
||||||
scheduledNoteLimit: "予約投稿の同時作成可能数"
|
|
||||||
watermarkAvailable: "ウォーターマーク機能の使用可否"
|
watermarkAvailable: "ウォーターマーク機能の使用可否"
|
||||||
_condition:
|
_condition:
|
||||||
roleAssignedTo: "マニュアルロールにアサイン済み"
|
roleAssignedTo: "マニュアルロールにアサイン済み"
|
||||||
|
@ -2735,8 +2715,6 @@ _notification:
|
||||||
youReceivedFollowRequest: "フォローリクエストが来ました"
|
youReceivedFollowRequest: "フォローリクエストが来ました"
|
||||||
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
yourFollowRequestAccepted: "フォローリクエストが承認されました"
|
||||||
pollEnded: "アンケートの結果が出ました"
|
pollEnded: "アンケートの結果が出ました"
|
||||||
scheduledNotePosted: "予約ノートが投稿されました"
|
|
||||||
scheduledNotePostFailed: "予約ノートの投稿に失敗しました"
|
|
||||||
newNote: "新しい投稿"
|
newNote: "新しい投稿"
|
||||||
unreadAntennaNote: "アンテナ {name}"
|
unreadAntennaNote: "アンテナ {name}"
|
||||||
roleAssigned: "ロールが付与されました"
|
roleAssigned: "ロールが付与されました"
|
||||||
|
@ -3328,8 +3306,6 @@ _imageEffector:
|
||||||
mirror: "ミラー"
|
mirror: "ミラー"
|
||||||
invert: "色の反転"
|
invert: "色の反転"
|
||||||
grayscale: "白黒"
|
grayscale: "白黒"
|
||||||
blur: "ぼかし"
|
|
||||||
pixelate: "モザイク"
|
|
||||||
colorAdjust: "色調補正"
|
colorAdjust: "色調補正"
|
||||||
colorClamp: "色の圧縮"
|
colorClamp: "色の圧縮"
|
||||||
colorClampAdvanced: "色の圧縮(高度)"
|
colorClampAdvanced: "色の圧縮(高度)"
|
||||||
|
@ -3341,14 +3317,12 @@ _imageEffector:
|
||||||
checker: "チェッカー"
|
checker: "チェッカー"
|
||||||
blockNoise: "ブロックノイズ"
|
blockNoise: "ブロックノイズ"
|
||||||
tearing: "ティアリング"
|
tearing: "ティアリング"
|
||||||
fill: "塗りつぶし"
|
fillSquare: "塗りつぶし(四角)"
|
||||||
|
|
||||||
_fxProps:
|
_fxProps:
|
||||||
angle: "角度"
|
angle: "角度"
|
||||||
scale: "サイズ"
|
scale: "サイズ"
|
||||||
size: "サイズ"
|
size: "サイズ"
|
||||||
radius: "半径"
|
|
||||||
samples: "サンプル数"
|
|
||||||
offset: "位置"
|
offset: "位置"
|
||||||
color: "色"
|
color: "色"
|
||||||
opacity: "不透明度"
|
opacity: "不透明度"
|
||||||
|
@ -3378,7 +3352,6 @@ _imageEffector:
|
||||||
zoomLinesThreshold: "集中線の幅"
|
zoomLinesThreshold: "集中線の幅"
|
||||||
zoomLinesMaskSize: "中心径"
|
zoomLinesMaskSize: "中心径"
|
||||||
zoomLinesBlack: "黒色にする"
|
zoomLinesBlack: "黒色にする"
|
||||||
circle: "円形"
|
|
||||||
|
|
||||||
drafts: "下書き"
|
drafts: "下書き"
|
||||||
_drafts:
|
_drafts:
|
||||||
|
@ -3395,9 +3368,6 @@ _drafts:
|
||||||
restoreFromDraft: "下書きから復元"
|
restoreFromDraft: "下書きから復元"
|
||||||
restore: "復元"
|
restore: "復元"
|
||||||
listDrafts: "下書き一覧"
|
listDrafts: "下書き一覧"
|
||||||
schedule: "投稿予約"
|
|
||||||
listScheduledNotes: "予約投稿一覧"
|
|
||||||
cancelSchedule: "予約解除"
|
|
||||||
|
|
||||||
qr: "二次元コード"
|
qr: "二次元コード"
|
||||||
_qr:
|
_qr:
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "2025.9.1-alpha.2",
|
"version": "2025.9.1-alpha.0",
|
||||||
"codename": "nasubi",
|
"codename": "nasubi",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/misskey-dev/misskey.git"
|
"url": "https://github.com/misskey-dev/misskey.git"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.16.0",
|
"packageManager": "pnpm@10.15.1",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/frontend-shared",
|
"packages/frontend-shared",
|
||||||
"packages/frontend",
|
"packages/frontend",
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
"eslint": "9.35.0",
|
"eslint": "9.35.0",
|
||||||
"globals": "16.3.0",
|
"globals": "16.3.0",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"pnpm": "10.16.0",
|
"pnpm": "10.15.1",
|
||||||
"start-server-and-test": "2.1.0"
|
"start-server-and-test": "2.1.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
export class ScheduledPost1758677617888 {
|
|
||||||
name = 'ScheduledPost1758677617888'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {QueryRunner} queryRunner
|
|
||||||
*/
|
|
||||||
async up(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" ADD "scheduledAt" TIMESTAMP WITH TIME ZONE`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" ADD "isActuallyScheduled" boolean NOT NULL DEFAULT false`);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {QueryRunner} queryRunner
|
|
||||||
*/
|
|
||||||
async down(queryRunner) {
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP COLUMN "isActuallyScheduled"`);
|
|
||||||
await queryRunner.query(`ALTER TABLE "note_draft" DROP COLUMN "scheduledAt"`);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ import * as fs from 'node:fs';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { dirname, resolve } from 'node:path';
|
import { dirname, resolve } from 'node:path';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import { type FastifyServerOptions } from 'fastify';
|
|
||||||
import type * as Sentry from '@sentry/node';
|
import type * as Sentry from '@sentry/node';
|
||||||
import type * as SentryVue from '@sentry/vue';
|
import type * as SentryVue from '@sentry/vue';
|
||||||
import type { RedisOptions } from 'ioredis';
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
@ -28,7 +27,6 @@ type Source = {
|
||||||
url?: string;
|
url?: string;
|
||||||
port?: number;
|
port?: number;
|
||||||
socket?: string;
|
socket?: string;
|
||||||
trustProxy?: FastifyServerOptions['trustProxy'];
|
|
||||||
chmodSocket?: string;
|
chmodSocket?: string;
|
||||||
disableHsts?: boolean;
|
disableHsts?: boolean;
|
||||||
db: {
|
db: {
|
||||||
|
@ -120,7 +118,6 @@ export type Config = {
|
||||||
url: string;
|
url: string;
|
||||||
port: number;
|
port: number;
|
||||||
socket: string | undefined;
|
socket: string | undefined;
|
||||||
trustProxy: FastifyServerOptions['trustProxy'];
|
|
||||||
chmodSocket: string | undefined;
|
chmodSocket: string | undefined;
|
||||||
disableHsts: boolean | undefined;
|
disableHsts: boolean | undefined;
|
||||||
db: {
|
db: {
|
||||||
|
@ -269,7 +266,6 @@ export function loadConfig(): Config {
|
||||||
url: url.origin,
|
url: url.origin,
|
||||||
port: config.port ?? parseInt(process.env.PORT ?? '', 10),
|
port: config.port ?? parseInt(process.env.PORT ?? '', 10),
|
||||||
socket: config.socket,
|
socket: config.socket,
|
||||||
trustProxy: config.trustProxy,
|
|
||||||
chmodSocket: config.chmodSocket,
|
chmodSocket: config.chmodSocket,
|
||||||
disableHsts: config.disableHsts,
|
disableHsts: config.disableHsts,
|
||||||
host,
|
host,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import { extractCustomEmojisFromMfm } from '@/misc/extract-custom-emojis-from-mf
|
||||||
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
import { extractHashtags } from '@/misc/extract-hashtags.js';
|
||||||
import type { IMentionedRemoteUsers } from '@/models/Note.js';
|
import type { IMentionedRemoteUsers } from '@/models/Note.js';
|
||||||
import { MiNote } from '@/models/Note.js';
|
import { MiNote } from '@/models/Note.js';
|
||||||
import type { BlockingsRepository, ChannelFollowingsRepository, ChannelsRepository, DriveFilesRepository, FollowingsRepository, InstancesRepository, MiFollowing, MiMeta, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
import type { ChannelFollowingsRepository, ChannelsRepository, FollowingsRepository, InstancesRepository, MiFollowing, MiMeta, MutingsRepository, NotesRepository, NoteThreadMutingsRepository, UserListMembershipsRepository, UserProfilesRepository, UsersRepository } from '@/models/_.js';
|
||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
import type { MiApp } from '@/models/App.js';
|
import type { MiApp } from '@/models/App.js';
|
||||||
import { concat } from '@/misc/prelude/array.js';
|
import { concat } from '@/misc/prelude/array.js';
|
||||||
|
@ -56,7 +56,6 @@ import { trackPromise } from '@/misc/promise-tracker.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
import { CollapsedQueue } from '@/misc/collapsed-queue.js';
|
||||||
import { CacheService } from '@/core/CacheService.js';
|
import { CacheService } from '@/core/CacheService.js';
|
||||||
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
|
||||||
|
|
||||||
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';
|
||||||
|
|
||||||
|
@ -193,12 +192,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
@Inject(DI.channelFollowingsRepository)
|
@Inject(DI.channelFollowingsRepository)
|
||||||
private channelFollowingsRepository: ChannelFollowingsRepository,
|
private channelFollowingsRepository: ChannelFollowingsRepository,
|
||||||
|
|
||||||
@Inject(DI.blockingsRepository)
|
|
||||||
private blockingsRepository: BlockingsRepository,
|
|
||||||
|
|
||||||
@Inject(DI.driveFilesRepository)
|
|
||||||
private driveFilesRepository: DriveFilesRepository,
|
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
|
@ -228,167 +221,6 @@ export class NoteCreateService implements OnApplicationShutdown {
|
||||||
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
this.updateNotesCountQueue = new CollapsedQueue(process.env.NODE_ENV !== 'test' ? 60 * 1000 * 5 : 0, this.collapseNotesCount, this.performUpdateNotesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async fetchAndCreate(user: {
|
|
||||||
id: MiUser['id'];
|
|
||||||
username: MiUser['username'];
|
|
||||||
host: MiUser['host'];
|
|
||||||
isBot: MiUser['isBot'];
|
|
||||||
isCat: MiUser['isCat'];
|
|
||||||
}, data: {
|
|
||||||
createdAt: Date;
|
|
||||||
replyId: MiNote['id'] | null;
|
|
||||||
renoteId: MiNote['id'] | null;
|
|
||||||
fileIds: MiDriveFile['id'][];
|
|
||||||
text: string | null;
|
|
||||||
cw: string | null;
|
|
||||||
visibility: string;
|
|
||||||
visibleUserIds: MiUser['id'][];
|
|
||||||
channelId: MiChannel['id'] | null;
|
|
||||||
localOnly: boolean;
|
|
||||||
reactionAcceptance: MiNote['reactionAcceptance'];
|
|
||||||
poll: IPoll | null;
|
|
||||||
apMentions?: MinimumUser[] | null;
|
|
||||||
apHashtags?: string[] | null;
|
|
||||||
apEmojis?: string[] | null;
|
|
||||||
}): Promise<MiNote> {
|
|
||||||
const visibleUsers = data.visibleUserIds.length > 0 ? await this.usersRepository.findBy({
|
|
||||||
id: In(data.visibleUserIds),
|
|
||||||
}) : [];
|
|
||||||
|
|
||||||
let files: MiDriveFile[] = [];
|
|
||||||
if (data.fileIds.length > 0) {
|
|
||||||
files = await this.driveFilesRepository.createQueryBuilder('file')
|
|
||||||
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
|
|
||||||
userId: user.id,
|
|
||||||
fileIds: data.fileIds,
|
|
||||||
})
|
|
||||||
.orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
|
|
||||||
.setParameters({ fileIds: data.fileIds })
|
|
||||||
.getMany();
|
|
||||||
|
|
||||||
if (files.length !== data.fileIds.length) {
|
|
||||||
throw new IdentifiableError('801c046c-5bf5-4234-ad2b-e78fc20a2ac7', 'No such file');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let renote: MiNote | null = null;
|
|
||||||
if (data.renoteId != null) {
|
|
||||||
// Fetch renote to note
|
|
||||||
renote = await this.notesRepository.findOne({
|
|
||||||
where: { id: data.renoteId },
|
|
||||||
relations: ['user', 'renote', 'reply'],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (renote == null) {
|
|
||||||
throw new IdentifiableError('53983c56-e163-45a6-942f-4ddc485d4290', 'No such renote target');
|
|
||||||
} else if (isRenote(renote) && !isQuote(renote)) {
|
|
||||||
throw new IdentifiableError('bde24c37-121f-4e7d-980d-cec52f599f02', 'Cannot renote pure renote');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check blocking
|
|
||||||
if (renote.userId !== user.id) {
|
|
||||||
const blockExist = await this.blockingsRepository.exists({
|
|
||||||
where: {
|
|
||||||
blockerId: renote.userId,
|
|
||||||
blockeeId: user.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (blockExist) {
|
|
||||||
throw new IdentifiableError('2b4fe776-4414-4a2d-ae39-f3418b8fd4d3', 'You have been blocked by the user');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renote.visibility === 'followers' && renote.userId !== user.id) {
|
|
||||||
// 他人のfollowers noteはreject
|
|
||||||
throw new IdentifiableError('90b9d6f0-893a-4fef-b0f1-e9a33989f71a', 'Renote target visibility');
|
|
||||||
} else if (renote.visibility === 'specified') {
|
|
||||||
// specified / direct noteはreject
|
|
||||||
throw new IdentifiableError('48d7a997-da5c-4716-b3c3-92db3f37bf7d', 'Renote target visibility');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renote.channelId && renote.channelId !== data.channelId) {
|
|
||||||
// チャンネルのノートに対しリノート要求がきたとき、チャンネル外へのリノート可否をチェック
|
|
||||||
// リノートのユースケースのうち、チャンネル内→チャンネル外は少数だと考えられるため、JOINはせず必要な時に都度取得する
|
|
||||||
const renoteChannel = await this.channelsRepository.findOneBy({ id: renote.channelId });
|
|
||||||
if (renoteChannel == null) {
|
|
||||||
// リノートしたいノートが書き込まれているチャンネルが無い
|
|
||||||
throw new IdentifiableError('b060f9a6-8909-4080-9e0b-94d9fa6f6a77', 'No such channel');
|
|
||||||
} else if (!renoteChannel.allowRenoteToExternal) {
|
|
||||||
// リノート作成のリクエストだが、対象チャンネルがリノート禁止だった場合
|
|
||||||
throw new IdentifiableError('7e435f4a-780d-4cfc-a15a-42519bd6fb67', 'Channel does not allow renote to external');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let reply: MiNote | null = null;
|
|
||||||
if (data.replyId != null) {
|
|
||||||
// Fetch reply
|
|
||||||
reply = await this.notesRepository.findOne({
|
|
||||||
where: { id: data.replyId },
|
|
||||||
relations: ['user'],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (reply == null) {
|
|
||||||
throw new IdentifiableError('60142edb-1519-408e-926d-4f108d27bee0', 'No such reply target');
|
|
||||||
} else if (isRenote(reply) && !isQuote(reply)) {
|
|
||||||
throw new IdentifiableError('f089e4e2-c0e7-4f60-8a23-e5a6bf786b36', 'Cannot reply to pure renote');
|
|
||||||
} else if (!await this.noteEntityService.isVisibleForMe(reply, user.id)) {
|
|
||||||
throw new IdentifiableError('11cd37b3-a411-4f77-8633-c580ce6a8dce', 'No such reply target');
|
|
||||||
} else if (reply.visibility === 'specified' && data.visibility !== 'specified') {
|
|
||||||
throw new IdentifiableError('ced780a1-2012-4caf-bc7e-a95a291294cb', 'Cannot reply to specified note with different visibility');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check blocking
|
|
||||||
if (reply.userId !== user.id) {
|
|
||||||
const blockExist = await this.blockingsRepository.exists({
|
|
||||||
where: {
|
|
||||||
blockerId: reply.userId,
|
|
||||||
blockeeId: user.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (blockExist) {
|
|
||||||
throw new IdentifiableError('b0df6025-f2e8-44b4-a26a-17ad99104612', 'You have been blocked by the user');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.poll) {
|
|
||||||
if (data.poll.expiresAt != null) {
|
|
||||||
if (data.poll.expiresAt.getTime() < Date.now()) {
|
|
||||||
throw new IdentifiableError('0c11c11e-0c8d-48e7-822c-76ccef660068', 'Poll expiration must be future time');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let channel: MiChannel | null = null;
|
|
||||||
if (data.channelId != null) {
|
|
||||||
channel = await this.channelsRepository.findOneBy({ id: data.channelId, isArchived: false });
|
|
||||||
|
|
||||||
if (channel == null) {
|
|
||||||
throw new IdentifiableError('bfa3905b-25f5-4894-b430-da331a490e4b', 'No such channel');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.create(user, {
|
|
||||||
createdAt: data.createdAt,
|
|
||||||
files: files,
|
|
||||||
poll: data.poll,
|
|
||||||
text: data.text,
|
|
||||||
reply,
|
|
||||||
renote,
|
|
||||||
cw: data.cw,
|
|
||||||
localOnly: data.localOnly,
|
|
||||||
reactionAcceptance: data.reactionAcceptance,
|
|
||||||
visibility: data.visibility,
|
|
||||||
visibleUsers,
|
|
||||||
channel,
|
|
||||||
apMentions: data.apMentions,
|
|
||||||
apHashtags: data.apHashtags,
|
|
||||||
apEmojis: data.apEmojis,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async create(user: {
|
public async create(user: {
|
||||||
id: MiUser['id'];
|
id: MiUser['id'];
|
||||||
|
|
|
@ -5,18 +5,32 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
|
import type { noteVisibilities, noteReactionAcceptances } from '@/types.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { MiNoteDraft, NoteDraftsRepository, MiNote, MiDriveFile, MiChannel, UsersRepository, DriveFilesRepository, NotesRepository, BlockingsRepository, ChannelsRepository } from '@/models/_.js';
|
import type { MiNoteDraft, NoteDraftsRepository, MiNote, MiDriveFile, MiChannel, UsersRepository, DriveFilesRepository, NotesRepository, BlockingsRepository, ChannelsRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
||||||
|
import { IPoll } from '@/models/Poll.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { isRenote, isQuote } from '@/misc/is-renote.js';
|
import { isRenote, isQuote } from '@/misc/is-renote.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { QueueService } from '@/core/QueueService.js';
|
|
||||||
|
|
||||||
export type NoteDraftOptions = Omit<MiNoteDraft, 'id' | 'userId' | 'user' | 'reply' | 'renote' | 'channel'>;
|
export type NoteDraftOptions = {
|
||||||
|
replyId?: MiNote['id'] | null;
|
||||||
|
renoteId?: MiNote['id'] | null;
|
||||||
|
text?: string | null;
|
||||||
|
cw?: string | null;
|
||||||
|
localOnly?: boolean | null;
|
||||||
|
reactionAcceptance?: typeof noteReactionAcceptances[number];
|
||||||
|
visibility?: typeof noteVisibilities[number];
|
||||||
|
fileIds?: MiDriveFile['id'][];
|
||||||
|
visibleUserIds?: MiUser['id'][];
|
||||||
|
hashtag?: string;
|
||||||
|
channelId?: MiChannel['id'] | null;
|
||||||
|
poll?: (IPoll & { expiredAfter?: number | null }) | null;
|
||||||
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NoteDraftService {
|
export class NoteDraftService {
|
||||||
|
@ -42,7 +56,6 @@ export class NoteDraftService {
|
||||||
private roleService: RoleService,
|
private roleService: RoleService,
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private queueService: QueueService,
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,43 +72,36 @@ export class NoteDraftService {
|
||||||
@bindThis
|
@bindThis
|
||||||
public async create(me: MiLocalUser, data: NoteDraftOptions): Promise<MiNoteDraft> {
|
public async create(me: MiLocalUser, data: NoteDraftOptions): Promise<MiNoteDraft> {
|
||||||
//#region check draft limit
|
//#region check draft limit
|
||||||
const policies = await this.roleService.getUserPolicies(me.id);
|
|
||||||
|
|
||||||
const currentCount = await this.noteDraftsRepository.countBy({
|
const currentCount = await this.noteDraftsRepository.countBy({
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
if (currentCount >= policies.noteDraftLimit) {
|
if (currentCount >= (await this.roleService.getUserPolicies(me.id)).noteDraftLimit) {
|
||||||
throw new IdentifiableError('9ee33bbe-fde3-4c71-9b51-e50492c6b9c8', 'Too many drafts');
|
throw new IdentifiableError('9ee33bbe-fde3-4c71-9b51-e50492c6b9c8', 'Too many drafts');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.isActuallyScheduled) {
|
|
||||||
const currentScheduledCount = await this.noteDraftsRepository.countBy({
|
|
||||||
userId: me.id,
|
|
||||||
isActuallyScheduled: true,
|
|
||||||
});
|
|
||||||
if (currentScheduledCount >= policies.scheduledNoteLimit) {
|
|
||||||
throw new IdentifiableError('c3275f19-4558-4c59-83e1-4f684b5fab66', 'Too many scheduled notes');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
await this.validate(me, data);
|
if (data.poll) {
|
||||||
|
if (typeof data.poll.expiresAt === 'number') {
|
||||||
const draft = await this.noteDraftsRepository.insertOne({
|
if (data.poll.expiresAt < Date.now()) {
|
||||||
...data,
|
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
|
||||||
id: this.idService.gen(),
|
|
||||||
userId: me.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (draft.scheduledAt && draft.isActuallyScheduled) {
|
|
||||||
this.schedule(draft);
|
|
||||||
}
|
}
|
||||||
|
} else if (typeof data.poll.expiredAfter === 'number') {
|
||||||
|
data.poll.expiresAt = new Date(Date.now() + data.poll.expiredAfter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, this.noteDraftsRepository.create(), data);
|
||||||
|
|
||||||
|
appliedDraft.id = this.idService.gen();
|
||||||
|
appliedDraft.userId = me.id;
|
||||||
|
const draft = this.noteDraftsRepository.save(appliedDraft);
|
||||||
|
|
||||||
return draft;
|
return draft;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async update(me: MiLocalUser, draftId: MiNoteDraft['id'], data: Partial<NoteDraftOptions>): Promise<MiNoteDraft> {
|
public async update(me: MiLocalUser, draftId: MiNoteDraft['id'], data: NoteDraftOptions): Promise<MiNoteDraft> {
|
||||||
const draft = await this.noteDraftsRepository.findOneBy({
|
const draft = await this.noteDraftsRepository.findOneBy({
|
||||||
id: draftId,
|
id: draftId,
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
|
@ -105,36 +111,19 @@ export class NoteDraftService {
|
||||||
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
|
throw new IdentifiableError('49cd6b9d-848e-41ee-b0b9-adaca711a6b1', 'No such note draft');
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region check draft limit
|
if (data.poll) {
|
||||||
const policies = await this.roleService.getUserPolicies(me.id);
|
if (typeof data.poll.expiresAt === 'number') {
|
||||||
|
if (data.poll.expiresAt < Date.now()) {
|
||||||
if (!draft.isActuallyScheduled && data.isActuallyScheduled) {
|
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
|
||||||
const currentScheduledCount = await this.noteDraftsRepository.countBy({
|
}
|
||||||
userId: me.id,
|
} else if (typeof data.poll.expiredAfter === 'number') {
|
||||||
isActuallyScheduled: true,
|
data.poll.expiresAt = new Date(Date.now() + data.poll.expiredAfter);
|
||||||
});
|
|
||||||
if (currentScheduledCount >= policies.scheduledNoteLimit) {
|
|
||||||
throw new IdentifiableError('bacdf856-5c51-4159-b88a-804fa5103be5', 'Too many scheduled notes');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#endregion
|
|
||||||
|
|
||||||
await this.validate(me, data);
|
const appliedDraft = await this.checkAndSetDraftNoteOptions(me, draft, data);
|
||||||
|
|
||||||
const updatedDraft = await this.noteDraftsRepository.createQueryBuilder().update()
|
return await this.noteDraftsRepository.save(appliedDraft);
|
||||||
.set(data)
|
|
||||||
.where('id = :id', { id: draftId })
|
|
||||||
.returning('*')
|
|
||||||
.execute()
|
|
||||||
.then((response) => response.raw[0]);
|
|
||||||
|
|
||||||
this.clearSchedule(draftId).then(() => {
|
|
||||||
if (updatedDraft.scheduledAt != null && updatedDraft.isActuallyScheduled) {
|
|
||||||
this.schedule(updatedDraft);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return updatedDraft;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -149,8 +138,6 @@ export class NoteDraftService {
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.noteDraftsRepository.delete(draft.id);
|
await this.noteDraftsRepository.delete(draft.id);
|
||||||
|
|
||||||
this.clearSchedule(draftId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -167,20 +154,27 @@ export class NoteDraftService {
|
||||||
return draft;
|
return draft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 関連エンティティを取得し紐づける部分を共通化する
|
||||||
@bindThis
|
@bindThis
|
||||||
public async validate(
|
public async checkAndSetDraftNoteOptions(
|
||||||
me: MiLocalUser,
|
me: MiLocalUser,
|
||||||
data: Partial<NoteDraftOptions>,
|
draft: MiNoteDraft,
|
||||||
): Promise<void> {
|
data: NoteDraftOptions,
|
||||||
if (data.pollExpiresAt != null) {
|
): Promise<MiNoteDraft> {
|
||||||
if (data.pollExpiresAt.getTime() < Date.now()) {
|
data.visibility ??= 'public';
|
||||||
throw new IdentifiableError('04da457d-b083-4055-9082-955525eda5a5', 'Cannot create expired poll');
|
data.localOnly ??= false;
|
||||||
}
|
if (data.reactionAcceptance === undefined) data.reactionAcceptance = null;
|
||||||
|
if (data.channelId != null) {
|
||||||
|
data.visibility = 'public';
|
||||||
|
data.visibleUserIds = [];
|
||||||
|
data.localOnly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let appliedDraft = draft;
|
||||||
|
|
||||||
//#region visibleUsers
|
//#region visibleUsers
|
||||||
let visibleUsers: MiUser[] = [];
|
let visibleUsers: MiUser[] = [];
|
||||||
if (data.visibleUserIds != null && data.visibleUserIds.length > 0) {
|
if (data.visibleUserIds != null) {
|
||||||
visibleUsers = await this.usersRepository.findBy({
|
visibleUsers = await this.usersRepository.findBy({
|
||||||
id: In(data.visibleUserIds),
|
id: In(data.visibleUserIds),
|
||||||
});
|
});
|
||||||
|
@ -190,7 +184,7 @@ export class NoteDraftService {
|
||||||
//#region files
|
//#region files
|
||||||
let files: MiDriveFile[] = [];
|
let files: MiDriveFile[] = [];
|
||||||
const fileIds = data.fileIds ?? null;
|
const fileIds = data.fileIds ?? null;
|
||||||
if (fileIds != null && fileIds.length > 0) {
|
if (fileIds != null) {
|
||||||
files = await this.driveFilesRepository.createQueryBuilder('file')
|
files = await this.driveFilesRepository.createQueryBuilder('file')
|
||||||
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
|
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
|
||||||
userId: me.id,
|
userId: me.id,
|
||||||
|
@ -294,37 +288,27 @@ export class NoteDraftService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
appliedDraft = {
|
||||||
public async schedule(draft: MiNoteDraft): Promise<void> {
|
...appliedDraft,
|
||||||
if (!draft.isActuallyScheduled) return;
|
visibility: data.visibility,
|
||||||
if (draft.scheduledAt == null) return;
|
cw: data.cw ?? null,
|
||||||
if (draft.scheduledAt.getTime() <= Date.now()) return;
|
fileIds: fileIds ?? [],
|
||||||
|
replyId: data.replyId ?? null,
|
||||||
|
renoteId: data.renoteId ?? null,
|
||||||
|
channelId: data.channelId ?? null,
|
||||||
|
text: data.text ?? null,
|
||||||
|
hashtag: data.hashtag ?? null,
|
||||||
|
hasPoll: data.poll != null,
|
||||||
|
pollChoices: data.poll ? data.poll.choices : [],
|
||||||
|
pollMultiple: data.poll ? data.poll.multiple : false,
|
||||||
|
pollExpiresAt: data.poll ? data.poll.expiresAt : null,
|
||||||
|
pollExpiredAfter: data.poll ? data.poll.expiredAfter ?? null : null,
|
||||||
|
visibleUserIds: data.visibleUserIds ?? [],
|
||||||
|
localOnly: data.localOnly,
|
||||||
|
reactionAcceptance: data.reactionAcceptance,
|
||||||
|
} satisfies MiNoteDraft;
|
||||||
|
|
||||||
const delay = draft.scheduledAt.getTime() - Date.now();
|
return appliedDraft;
|
||||||
this.queueService.postScheduledNoteQueue.add(draft.id, {
|
|
||||||
noteDraftId: draft.id,
|
|
||||||
}, {
|
|
||||||
delay,
|
|
||||||
removeOnComplete: {
|
|
||||||
age: 3600 * 24 * 7, // keep up to 7 days
|
|
||||||
count: 30,
|
|
||||||
},
|
|
||||||
removeOnFail: {
|
|
||||||
age: 3600 * 24 * 7, // keep up to 7 days
|
|
||||||
count: 100,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async clearSchedule(draftId: MiNoteDraft['id']): Promise<void> {
|
|
||||||
const jobs = await this.queueService.postScheduledNoteQueue.getJobs(['delayed', 'waiting', 'active']);
|
|
||||||
for (const job of jobs) {
|
|
||||||
if (job.data.noteDraftId === draftId) {
|
|
||||||
await job.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,11 @@ import {
|
||||||
RelationshipJobData,
|
RelationshipJobData,
|
||||||
UserWebhookDeliverJobData,
|
UserWebhookDeliverJobData,
|
||||||
SystemWebhookDeliverJobData,
|
SystemWebhookDeliverJobData,
|
||||||
PostScheduledNoteJobData,
|
|
||||||
} from '../queue/types.js';
|
} from '../queue/types.js';
|
||||||
import type { Provider } from '@nestjs/common';
|
import type { Provider } from '@nestjs/common';
|
||||||
|
|
||||||
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
|
export type SystemQueue = Bull.Queue<Record<string, unknown>>;
|
||||||
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
|
export type EndedPollNotificationQueue = Bull.Queue<EndedPollNotificationJobData>;
|
||||||
export type PostScheduledNoteQueue = Bull.Queue<PostScheduledNoteJobData>;
|
|
||||||
export type DeliverQueue = Bull.Queue<DeliverJobData>;
|
export type DeliverQueue = Bull.Queue<DeliverJobData>;
|
||||||
export type InboxQueue = Bull.Queue<InboxJobData>;
|
export type InboxQueue = Bull.Queue<InboxJobData>;
|
||||||
export type DbQueue = Bull.Queue;
|
export type DbQueue = Bull.Queue;
|
||||||
|
@ -43,12 +41,6 @@ const $endedPollNotification: Provider = {
|
||||||
inject: [DI.config],
|
inject: [DI.config],
|
||||||
};
|
};
|
||||||
|
|
||||||
const $postScheduledNote: Provider = {
|
|
||||||
provide: 'queue:postScheduledNote',
|
|
||||||
useFactory: (config: Config) => new Bull.Queue(QUEUE.POST_SCHEDULED_NOTE, baseQueueOptions(config, QUEUE.POST_SCHEDULED_NOTE)),
|
|
||||||
inject: [DI.config],
|
|
||||||
};
|
|
||||||
|
|
||||||
const $deliver: Provider = {
|
const $deliver: Provider = {
|
||||||
provide: 'queue:deliver',
|
provide: 'queue:deliver',
|
||||||
useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)),
|
useFactory: (config: Config) => new Bull.Queue(QUEUE.DELIVER, baseQueueOptions(config, QUEUE.DELIVER)),
|
||||||
|
@ -97,7 +89,6 @@ const $systemWebhookDeliver: Provider = {
|
||||||
providers: [
|
providers: [
|
||||||
$system,
|
$system,
|
||||||
$endedPollNotification,
|
$endedPollNotification,
|
||||||
$postScheduledNote,
|
|
||||||
$deliver,
|
$deliver,
|
||||||
$inbox,
|
$inbox,
|
||||||
$db,
|
$db,
|
||||||
|
@ -109,7 +100,6 @@ const $systemWebhookDeliver: Provider = {
|
||||||
exports: [
|
exports: [
|
||||||
$system,
|
$system,
|
||||||
$endedPollNotification,
|
$endedPollNotification,
|
||||||
$postScheduledNote,
|
|
||||||
$deliver,
|
$deliver,
|
||||||
$inbox,
|
$inbox,
|
||||||
$db,
|
$db,
|
||||||
|
@ -123,7 +113,6 @@ export class QueueModule implements OnApplicationShutdown {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
@Inject('queue:postScheduledNote') public postScheduledNoteQueue: PostScheduledNoteQueue,
|
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
@ -140,7 +129,6 @@ export class QueueModule implements OnApplicationShutdown {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.systemQueue.close(),
|
this.systemQueue.close(),
|
||||||
this.endedPollNotificationQueue.close(),
|
this.endedPollNotificationQueue.close(),
|
||||||
this.postScheduledNoteQueue.close(),
|
|
||||||
this.deliverQueue.close(),
|
this.deliverQueue.close(),
|
||||||
this.inboxQueue.close(),
|
this.inboxQueue.close(),
|
||||||
this.dbQueue.close(),
|
this.dbQueue.close(),
|
||||||
|
|
|
@ -31,7 +31,6 @@ import type {
|
||||||
DbQueue,
|
DbQueue,
|
||||||
DeliverQueue,
|
DeliverQueue,
|
||||||
EndedPollNotificationQueue,
|
EndedPollNotificationQueue,
|
||||||
PostScheduledNoteQueue,
|
|
||||||
InboxQueue,
|
InboxQueue,
|
||||||
ObjectStorageQueue,
|
ObjectStorageQueue,
|
||||||
RelationshipQueue,
|
RelationshipQueue,
|
||||||
|
@ -45,7 +44,6 @@ import type * as Bull from 'bullmq';
|
||||||
export const QUEUE_TYPES = [
|
export const QUEUE_TYPES = [
|
||||||
'system',
|
'system',
|
||||||
'endedPollNotification',
|
'endedPollNotification',
|
||||||
'postScheduledNote',
|
|
||||||
'deliver',
|
'deliver',
|
||||||
'inbox',
|
'inbox',
|
||||||
'db',
|
'db',
|
||||||
|
@ -94,7 +92,6 @@ export class QueueService {
|
||||||
|
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
@Inject('queue:postScheduledNote') public postScheduledNoteQueue: PostScheduledNoteQueue,
|
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
@ -720,7 +717,6 @@ export class QueueService {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'system': return this.systemQueue;
|
case 'system': return this.systemQueue;
|
||||||
case 'endedPollNotification': return this.endedPollNotificationQueue;
|
case 'endedPollNotification': return this.endedPollNotificationQueue;
|
||||||
case 'postScheduledNote': return this.postScheduledNoteQueue;
|
|
||||||
case 'deliver': return this.deliverQueue;
|
case 'deliver': return this.deliverQueue;
|
||||||
case 'inbox': return this.inboxQueue;
|
case 'inbox': return this.inboxQueue;
|
||||||
case 'db': return this.dbQueue;
|
case 'db': return this.dbQueue;
|
||||||
|
|
|
@ -69,7 +69,6 @@ export type RolePolicies = {
|
||||||
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
||||||
uploadableFileTypes: string[];
|
uploadableFileTypes: string[];
|
||||||
noteDraftLimit: number;
|
noteDraftLimit: number;
|
||||||
scheduledNoteLimit: number;
|
|
||||||
watermarkAvailable: boolean;
|
watermarkAvailable: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -117,7 +116,6 @@ export const DEFAULT_POLICIES: RolePolicies = {
|
||||||
'audio/*',
|
'audio/*',
|
||||||
],
|
],
|
||||||
noteDraftLimit: 10,
|
noteDraftLimit: 10,
|
||||||
scheduledNoteLimit: 1,
|
|
||||||
watermarkAvailable: true,
|
watermarkAvailable: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -442,7 +440,6 @@ export class RoleService implements OnApplicationShutdown, OnModuleInit {
|
||||||
return [...set];
|
return [...set];
|
||||||
}),
|
}),
|
||||||
noteDraftLimit: calc('noteDraftLimit', vs => Math.max(...vs)),
|
noteDraftLimit: calc('noteDraftLimit', vs => Math.max(...vs)),
|
||||||
scheduledNoteLimit: calc('scheduledNoteLimit', vs => Math.max(...vs)),
|
|
||||||
watermarkAvailable: calc('watermarkAvailable', vs => vs.some(v => v === true)),
|
watermarkAvailable: calc('watermarkAvailable', vs => vs.some(v => v === true)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,6 @@ export class NoteDraftEntityService implements OnModuleInit {
|
||||||
const packed: Packed<'NoteDraft'> = await awaitAll({
|
const packed: Packed<'NoteDraft'> = await awaitAll({
|
||||||
id: noteDraft.id,
|
id: noteDraft.id,
|
||||||
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
|
createdAt: this.idService.parse(noteDraft.id).date.toISOString(),
|
||||||
scheduledAt: noteDraft.scheduledAt?.getTime() ?? null,
|
|
||||||
isActuallyScheduled: noteDraft.isActuallyScheduled,
|
|
||||||
userId: noteDraft.userId,
|
userId: noteDraft.userId,
|
||||||
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
|
user: packedUsers?.get(noteDraft.userId) ?? this.userEntityService.pack(noteDraft.user ?? noteDraft.userId, me),
|
||||||
text: text,
|
text: text,
|
||||||
|
@ -114,13 +112,13 @@ export class NoteDraftEntityService implements OnModuleInit {
|
||||||
visibility: noteDraft.visibility,
|
visibility: noteDraft.visibility,
|
||||||
localOnly: noteDraft.localOnly,
|
localOnly: noteDraft.localOnly,
|
||||||
reactionAcceptance: noteDraft.reactionAcceptance,
|
reactionAcceptance: noteDraft.reactionAcceptance,
|
||||||
visibleUserIds: noteDraft.visibleUserIds,
|
visibleUserIds: noteDraft.visibility === 'specified' ? noteDraft.visibleUserIds : undefined,
|
||||||
hashtag: noteDraft.hashtag,
|
hashtag: noteDraft.hashtag ?? undefined,
|
||||||
fileIds: noteDraft.fileIds,
|
fileIds: noteDraft.fileIds,
|
||||||
files: packedFiles != null ? this.packAttachedFiles(noteDraft.fileIds, packedFiles) : this.driveFileEntityService.packManyByIds(noteDraft.fileIds),
|
files: packedFiles != null ? this.packAttachedFiles(noteDraft.fileIds, packedFiles) : this.driveFileEntityService.packManyByIds(noteDraft.fileIds),
|
||||||
replyId: noteDraft.replyId,
|
replyId: noteDraft.replyId,
|
||||||
renoteId: noteDraft.renoteId,
|
renoteId: noteDraft.renoteId,
|
||||||
channelId: noteDraft.channelId,
|
channelId: noteDraft.channelId ?? undefined,
|
||||||
channel: channel ? {
|
channel: channel ? {
|
||||||
id: channel.id,
|
id: channel.id,
|
||||||
name: channel.name,
|
name: channel.name,
|
||||||
|
@ -129,12 +127,6 @@ export class NoteDraftEntityService implements OnModuleInit {
|
||||||
allowRenoteToExternal: channel.allowRenoteToExternal,
|
allowRenoteToExternal: channel.allowRenoteToExternal,
|
||||||
userId: channel.userId,
|
userId: channel.userId,
|
||||||
} : undefined,
|
} : undefined,
|
||||||
poll: noteDraft.hasPoll ? {
|
|
||||||
choices: noteDraft.pollChoices,
|
|
||||||
multiple: noteDraft.pollMultiple,
|
|
||||||
expiresAt: noteDraft.pollExpiresAt?.toISOString(),
|
|
||||||
expiredAfter: noteDraft.pollExpiredAfter,
|
|
||||||
} : null,
|
|
||||||
|
|
||||||
...(opts.detail ? {
|
...(opts.detail ? {
|
||||||
reply: noteDraft.replyId ? nullIfEntityNotFound(this.noteEntityService.pack(noteDraft.replyId, me, {
|
reply: noteDraft.replyId ? nullIfEntityNotFound(this.noteEntityService.pack(noteDraft.replyId, me, {
|
||||||
|
@ -146,6 +138,13 @@ export class NoteDraftEntityService implements OnModuleInit {
|
||||||
detail: true,
|
detail: true,
|
||||||
skipHide: opts.skipHide,
|
skipHide: opts.skipHide,
|
||||||
})) : undefined,
|
})) : undefined,
|
||||||
|
|
||||||
|
poll: noteDraft.hasPoll ? {
|
||||||
|
choices: noteDraft.pollChoices,
|
||||||
|
multiple: noteDraft.pollMultiple,
|
||||||
|
expiresAt: noteDraft.pollExpiresAt?.toISOString(),
|
||||||
|
expiredAfter: noteDraft.pollExpiredAfter,
|
||||||
|
} : undefined,
|
||||||
} : {} ),
|
} : {} ),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,18 +21,7 @@ import type { OnModuleInit } from '@nestjs/common';
|
||||||
import type { UserEntityService } from './UserEntityService.js';
|
import type { UserEntityService } from './UserEntityService.js';
|
||||||
import type { NoteEntityService } from './NoteEntityService.js';
|
import type { NoteEntityService } from './NoteEntityService.js';
|
||||||
|
|
||||||
const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set([
|
const NOTE_REQUIRED_NOTIFICATION_TYPES = new Set(['note', 'mention', 'reply', 'renote', 'renote:grouped', 'quote', 'reaction', 'reaction:grouped', 'pollEnded'] as (typeof groupedNotificationTypes[number])[]);
|
||||||
'note',
|
|
||||||
'mention',
|
|
||||||
'reply',
|
|
||||||
'renote',
|
|
||||||
'renote:grouped',
|
|
||||||
'quote',
|
|
||||||
'reaction',
|
|
||||||
'reaction:grouped',
|
|
||||||
'pollEnded',
|
|
||||||
'scheduledNotePosted',
|
|
||||||
] as (typeof groupedNotificationTypes[number])[]);
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class NotificationEntityService implements OnModuleInit {
|
export class NotificationEntityService implements OnModuleInit {
|
||||||
|
|
|
@ -126,7 +126,7 @@ export class MiNoteDraft {
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public channel: MiChannel | null;
|
public channel: MiChannel | null;
|
||||||
|
|
||||||
//#region 以下、Pollについて追加
|
// 以下、Pollについて追加
|
||||||
|
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -151,15 +151,13 @@ export class MiNoteDraft {
|
||||||
})
|
})
|
||||||
public pollExpiredAfter: number | null;
|
public pollExpiredAfter: number | null;
|
||||||
|
|
||||||
//#endregion
|
// ここまで追加
|
||||||
|
|
||||||
@Column('timestamp with time zone', {
|
constructor(data: Partial<MiNoteDraft>) {
|
||||||
nullable: true,
|
if (data == null) return;
|
||||||
})
|
|
||||||
public scheduledAt: Date | null;
|
|
||||||
|
|
||||||
@Column('boolean', {
|
for (const [k, v] of Object.entries(data)) {
|
||||||
default: false,
|
(this as any)[k] = v;
|
||||||
})
|
}
|
||||||
public isActuallyScheduled: boolean;
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { MiNote } from './Note.js';
|
||||||
import { MiAccessToken } from './AccessToken.js';
|
import { MiAccessToken } from './AccessToken.js';
|
||||||
import { MiRole } from './Role.js';
|
import { MiRole } from './Role.js';
|
||||||
import { MiDriveFile } from './DriveFile.js';
|
import { MiDriveFile } from './DriveFile.js';
|
||||||
import { MiNoteDraft } from './NoteDraft.js';
|
|
||||||
|
|
||||||
// misskey-js の notificationTypes と同期すべし
|
// misskey-js の notificationTypes と同期すべし
|
||||||
export type MiNotification = {
|
export type MiNotification = {
|
||||||
|
@ -61,16 +60,6 @@ export type MiNotification = {
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
notifierId: MiUser['id'];
|
notifierId: MiUser['id'];
|
||||||
noteId: MiNote['id'];
|
noteId: MiNote['id'];
|
||||||
} | {
|
|
||||||
type: 'scheduledNotePosted';
|
|
||||||
id: string;
|
|
||||||
createdAt: string;
|
|
||||||
noteId: MiNote['id'];
|
|
||||||
} | {
|
|
||||||
type: 'scheduledNotePostFailed';
|
|
||||||
id: string;
|
|
||||||
createdAt: string;
|
|
||||||
noteDraftId: MiNoteDraft['id'];
|
|
||||||
} | {
|
} | {
|
||||||
type: 'receiveFollowRequest';
|
type: 'receiveFollowRequest';
|
||||||
id: string;
|
id: string;
|
||||||
|
|
|
@ -23,7 +23,7 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
cw: {
|
cw: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: true, nullable: true,
|
||||||
},
|
},
|
||||||
userId: {
|
userId: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -37,23 +37,27 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
replyId: {
|
replyId: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: true, nullable: true,
|
||||||
format: 'id',
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
},
|
},
|
||||||
renoteId: {
|
renoteId: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: true, nullable: true,
|
||||||
format: 'id',
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
},
|
},
|
||||||
reply: {
|
reply: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: true, nullable: true,
|
optional: true, nullable: true,
|
||||||
ref: 'Note',
|
ref: 'Note',
|
||||||
|
description: 'The reply target note contents if exists. If the reply target has been deleted since the draft was created, this will be null while replyId is not null.',
|
||||||
},
|
},
|
||||||
renote: {
|
renote: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: true, nullable: true,
|
optional: true, nullable: true,
|
||||||
ref: 'Note',
|
ref: 'Note',
|
||||||
|
description: 'The renote target note contents if exists. If the renote target has been deleted since the draft was created, this will be null while renoteId is not null.',
|
||||||
},
|
},
|
||||||
visibility: {
|
visibility: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -62,7 +66,7 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
visibleUserIds: {
|
visibleUserIds: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: true, nullable: false,
|
||||||
items: {
|
items: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@ -71,7 +75,7 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
fileIds: {
|
fileIds: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
optional: false, nullable: false,
|
optional: true, nullable: false,
|
||||||
items: {
|
items: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
@ -89,11 +93,11 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
hashtag: {
|
hashtag: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: true, nullable: false,
|
||||||
},
|
},
|
||||||
poll: {
|
poll: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
optional: false, nullable: true,
|
optional: true, nullable: true,
|
||||||
properties: {
|
properties: {
|
||||||
expiresAt: {
|
expiresAt: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -120,8 +124,9 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
channelId: {
|
channelId: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: true, nullable: true,
|
||||||
format: 'id',
|
format: 'id',
|
||||||
|
example: 'xxxxxxxxxx',
|
||||||
},
|
},
|
||||||
channel: {
|
channel: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
|
@ -155,20 +160,12 @@ export const packedNoteDraftSchema = {
|
||||||
},
|
},
|
||||||
localOnly: {
|
localOnly: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: true, nullable: false,
|
||||||
},
|
},
|
||||||
reactionAcceptance: {
|
reactionAcceptance: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
optional: false, nullable: true,
|
optional: false, nullable: true,
|
||||||
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
|
enum: ['likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote', null],
|
||||||
},
|
},
|
||||||
scheduledAt: {
|
|
||||||
type: 'number',
|
|
||||||
optional: false, nullable: true,
|
|
||||||
},
|
|
||||||
isActuallyScheduled: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
|
@ -207,36 +207,6 @@ export const packedNotificationSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
...baseSchema.properties,
|
|
||||||
type: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
enum: ['scheduledNotePosted'],
|
|
||||||
},
|
|
||||||
note: {
|
|
||||||
type: 'object',
|
|
||||||
ref: 'Note',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
...baseSchema.properties,
|
|
||||||
type: {
|
|
||||||
type: 'string',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
enum: ['scheduledNotePostFailed'],
|
|
||||||
},
|
|
||||||
noteDraft: {
|
|
||||||
type: 'object',
|
|
||||||
ref: 'NoteDraft',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, {
|
}, {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
|
|
|
@ -317,10 +317,6 @@ export const packedRolePoliciesSchema = {
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
},
|
},
|
||||||
scheduledNoteLimit: {
|
|
||||||
type: 'integer',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
watermarkAvailable: {
|
watermarkAvailable: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -609,8 +609,6 @@ export const packedMeDetailedOnlySchema = {
|
||||||
quote: { optional: true, ...notificationRecieveConfig },
|
quote: { optional: true, ...notificationRecieveConfig },
|
||||||
reaction: { optional: true, ...notificationRecieveConfig },
|
reaction: { optional: true, ...notificationRecieveConfig },
|
||||||
pollEnded: { optional: true, ...notificationRecieveConfig },
|
pollEnded: { optional: true, ...notificationRecieveConfig },
|
||||||
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
|
||||||
scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
|
|
||||||
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
||||||
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
||||||
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { QueueLoggerService } from './QueueLoggerService.js';
|
||||||
import { QueueProcessorService } from './QueueProcessorService.js';
|
import { QueueProcessorService } from './QueueProcessorService.js';
|
||||||
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
||||||
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
||||||
import { PostScheduledNoteProcessorService } from './processors/PostScheduledNoteProcessorService.js';
|
|
||||||
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
||||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||||
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
||||||
|
@ -80,7 +79,6 @@ import { RelationshipProcessorService } from './processors/RelationshipProcessor
|
||||||
UserWebhookDeliverProcessorService,
|
UserWebhookDeliverProcessorService,
|
||||||
SystemWebhookDeliverProcessorService,
|
SystemWebhookDeliverProcessorService,
|
||||||
EndedPollNotificationProcessorService,
|
EndedPollNotificationProcessorService,
|
||||||
PostScheduledNoteProcessorService,
|
|
||||||
DeliverProcessorService,
|
DeliverProcessorService,
|
||||||
InboxProcessorService,
|
InboxProcessorService,
|
||||||
AggregateRetentionProcessorService,
|
AggregateRetentionProcessorService,
|
||||||
|
|
|
@ -14,7 +14,6 @@ import { CheckModeratorsActivityProcessorService } from '@/queue/processors/Chec
|
||||||
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
import { UserWebhookDeliverProcessorService } from './processors/UserWebhookDeliverProcessorService.js';
|
||||||
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
import { SystemWebhookDeliverProcessorService } from './processors/SystemWebhookDeliverProcessorService.js';
|
||||||
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
import { EndedPollNotificationProcessorService } from './processors/EndedPollNotificationProcessorService.js';
|
||||||
import { PostScheduledNoteProcessorService } from './processors/PostScheduledNoteProcessorService.js';
|
|
||||||
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
import { DeliverProcessorService } from './processors/DeliverProcessorService.js';
|
||||||
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
import { InboxProcessorService } from './processors/InboxProcessorService.js';
|
||||||
import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js';
|
import { DeleteDriveFilesProcessorService } from './processors/DeleteDriveFilesProcessorService.js';
|
||||||
|
@ -86,7 +85,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
private relationshipQueueWorker: Bull.Worker;
|
private relationshipQueueWorker: Bull.Worker;
|
||||||
private objectStorageQueueWorker: Bull.Worker;
|
private objectStorageQueueWorker: Bull.Worker;
|
||||||
private endedPollNotificationQueueWorker: Bull.Worker;
|
private endedPollNotificationQueueWorker: Bull.Worker;
|
||||||
private postScheduledNoteQueueWorker: Bull.Worker;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(DI.config)
|
@Inject(DI.config)
|
||||||
|
@ -96,7 +94,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
|
private userWebhookDeliverProcessorService: UserWebhookDeliverProcessorService,
|
||||||
private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
|
private systemWebhookDeliverProcessorService: SystemWebhookDeliverProcessorService,
|
||||||
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
|
private endedPollNotificationProcessorService: EndedPollNotificationProcessorService,
|
||||||
private postScheduledNoteProcessorService: PostScheduledNoteProcessorService,
|
|
||||||
private deliverProcessorService: DeliverProcessorService,
|
private deliverProcessorService: DeliverProcessorService,
|
||||||
private inboxProcessorService: InboxProcessorService,
|
private inboxProcessorService: InboxProcessorService,
|
||||||
private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService,
|
private deleteDriveFilesProcessorService: DeleteDriveFilesProcessorService,
|
||||||
|
@ -523,21 +520,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
//#region post scheduled note
|
|
||||||
{
|
|
||||||
this.postScheduledNoteQueueWorker = new Bull.Worker(QUEUE.POST_SCHEDULED_NOTE, async (job) => {
|
|
||||||
if (this.config.sentryForBackend) {
|
|
||||||
return Sentry.startSpan({ name: 'Queue: PostScheduledNote' }, () => this.postScheduledNoteProcessorService.process(job));
|
|
||||||
} else {
|
|
||||||
return this.postScheduledNoteProcessorService.process(job);
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
...baseWorkerOptions(this.config, QUEUE.POST_SCHEDULED_NOTE),
|
|
||||||
autorun: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
//#endregion
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@ -552,7 +534,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
this.relationshipQueueWorker.run(),
|
this.relationshipQueueWorker.run(),
|
||||||
this.objectStorageQueueWorker.run(),
|
this.objectStorageQueueWorker.run(),
|
||||||
this.endedPollNotificationQueueWorker.run(),
|
this.endedPollNotificationQueueWorker.run(),
|
||||||
this.postScheduledNoteQueueWorker.run(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -568,7 +549,6 @@ export class QueueProcessorService implements OnApplicationShutdown {
|
||||||
this.relationshipQueueWorker.close(),
|
this.relationshipQueueWorker.close(),
|
||||||
this.objectStorageQueueWorker.close(),
|
this.objectStorageQueueWorker.close(),
|
||||||
this.endedPollNotificationQueueWorker.close(),
|
this.endedPollNotificationQueueWorker.close(),
|
||||||
this.postScheduledNoteQueueWorker.close(),
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,6 @@ export const QUEUE = {
|
||||||
INBOX: 'inbox',
|
INBOX: 'inbox',
|
||||||
SYSTEM: 'system',
|
SYSTEM: 'system',
|
||||||
ENDED_POLL_NOTIFICATION: 'endedPollNotification',
|
ENDED_POLL_NOTIFICATION: 'endedPollNotification',
|
||||||
POST_SCHEDULED_NOTE: 'postScheduledNote',
|
|
||||||
DB: 'db',
|
DB: 'db',
|
||||||
RELATIONSHIP: 'relationship',
|
RELATIONSHIP: 'relationship',
|
||||||
OBJECT_STORAGE: 'objectStorage',
|
OBJECT_STORAGE: 'objectStorage',
|
||||||
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
|
||||||
import { DI } from '@/di-symbols.js';
|
|
||||||
import type { NoteDraftsRepository } from '@/models/_.js';
|
|
||||||
import type Logger from '@/logger.js';
|
|
||||||
import { NotificationService } from '@/core/NotificationService.js';
|
|
||||||
import { bindThis } from '@/decorators.js';
|
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
|
||||||
import { QueueLoggerService } from '../QueueLoggerService.js';
|
|
||||||
import type * as Bull from 'bullmq';
|
|
||||||
import type { PostScheduledNoteJobData } from '../types.js';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class PostScheduledNoteProcessorService {
|
|
||||||
private logger: Logger;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Inject(DI.noteDraftsRepository)
|
|
||||||
private noteDraftsRepository: NoteDraftsRepository,
|
|
||||||
|
|
||||||
private noteCreateService: NoteCreateService,
|
|
||||||
private notificationService: NotificationService,
|
|
||||||
private queueLoggerService: QueueLoggerService,
|
|
||||||
) {
|
|
||||||
this.logger = this.queueLoggerService.logger.createSubLogger('post-scheduled-note');
|
|
||||||
}
|
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async process(job: Bull.Job<PostScheduledNoteJobData>): Promise<void> {
|
|
||||||
const draft = await this.noteDraftsRepository.findOne({ where: { id: job.data.noteDraftId }, relations: ['user'] });
|
|
||||||
if (draft == null || draft.user == null || draft.scheduledAt == null || !draft.isActuallyScheduled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const note = await this.noteCreateService.fetchAndCreate(draft.user, {
|
|
||||||
createdAt: new Date(),
|
|
||||||
fileIds: draft.fileIds,
|
|
||||||
poll: draft.hasPoll ? {
|
|
||||||
choices: draft.pollChoices,
|
|
||||||
multiple: draft.pollMultiple,
|
|
||||||
expiresAt: draft.pollExpiredAfter ? new Date(Date.now() + draft.pollExpiredAfter) : draft.pollExpiresAt ? new Date(draft.pollExpiresAt) : null,
|
|
||||||
} : null,
|
|
||||||
text: draft.text ?? null,
|
|
||||||
replyId: draft.replyId,
|
|
||||||
renoteId: draft.renoteId,
|
|
||||||
cw: draft.cw,
|
|
||||||
localOnly: draft.localOnly,
|
|
||||||
reactionAcceptance: draft.reactionAcceptance,
|
|
||||||
visibility: draft.visibility,
|
|
||||||
visibleUserIds: draft.visibleUserIds,
|
|
||||||
channelId: draft.channelId,
|
|
||||||
});
|
|
||||||
|
|
||||||
// await不要
|
|
||||||
this.noteDraftsRepository.remove(draft);
|
|
||||||
|
|
||||||
// await不要
|
|
||||||
this.notificationService.createNotification(draft.userId, 'scheduledNotePosted', {
|
|
||||||
noteId: note.id,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
this.notificationService.createNotification(draft.userId, 'scheduledNotePostFailed', {
|
|
||||||
noteDraftId: draft.id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -109,10 +109,6 @@ export type EndedPollNotificationJobData = {
|
||||||
noteId: MiNote['id'];
|
noteId: MiNote['id'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PostScheduledNoteJobData = {
|
|
||||||
noteDraftId: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type SystemWebhookDeliverJobData<T extends SystemWebhookEventType = SystemWebhookEventType> = {
|
export type SystemWebhookDeliverJobData<T extends SystemWebhookEventType = SystemWebhookEventType> = {
|
||||||
type: T;
|
type: T;
|
||||||
content: SystemWebhookPayload<T>;
|
content: SystemWebhookPayload<T>;
|
||||||
|
|
|
@ -75,7 +75,7 @@ export class ServerService implements OnApplicationShutdown {
|
||||||
@bindThis
|
@bindThis
|
||||||
public async launch(): Promise<void> {
|
public async launch(): Promise<void> {
|
||||||
const fastify = Fastify({
|
const fastify = Fastify({
|
||||||
trustProxy: this.config.trustProxy ?? true,
|
trustProxy: true,
|
||||||
logger: false,
|
logger: false,
|
||||||
});
|
});
|
||||||
this.#fastify = fastify;
|
this.#fastify = fastify;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, PostScheduledNoteQueue, InboxQueue, ObjectStorageQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue } from '@/core/QueueModule.js';
|
import type { DbQueue, DeliverQueue, EndedPollNotificationQueue, InboxQueue, ObjectStorageQueue, SystemQueue, UserWebhookDeliverQueue, SystemWebhookDeliverQueue } from '@/core/QueueModule.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
@ -49,7 +49,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
constructor(
|
constructor(
|
||||||
@Inject('queue:system') public systemQueue: SystemQueue,
|
@Inject('queue:system') public systemQueue: SystemQueue,
|
||||||
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
@Inject('queue:endedPollNotification') public endedPollNotificationQueue: EndedPollNotificationQueue,
|
||||||
@Inject('queue:postScheduledNote') public postScheduledNoteQueue: PostScheduledNoteQueue,
|
|
||||||
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
@Inject('queue:deliver') public deliverQueue: DeliverQueue,
|
||||||
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
@Inject('queue:inbox') public inboxQueue: InboxQueue,
|
||||||
@Inject('queue:db') public dbQueue: DbQueue,
|
@Inject('queue:db') public dbQueue: DbQueue,
|
||||||
|
|
|
@ -103,8 +103,6 @@ export const meta = {
|
||||||
quote: { optional: true, ...notificationRecieveConfig },
|
quote: { optional: true, ...notificationRecieveConfig },
|
||||||
reaction: { optional: true, ...notificationRecieveConfig },
|
reaction: { optional: true, ...notificationRecieveConfig },
|
||||||
pollEnded: { optional: true, ...notificationRecieveConfig },
|
pollEnded: { optional: true, ...notificationRecieveConfig },
|
||||||
scheduledNotePosted: { optional: true, ...notificationRecieveConfig },
|
|
||||||
scheduledNotePostFailed: { optional: true, ...notificationRecieveConfig },
|
|
||||||
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
receiveFollowRequest: { optional: true, ...notificationRecieveConfig },
|
||||||
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
followRequestAccepted: { optional: true, ...notificationRecieveConfig },
|
||||||
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
roleAssigned: { optional: true, ...notificationRecieveConfig },
|
||||||
|
|
|
@ -209,8 +209,6 @@ export const paramDef = {
|
||||||
quote: notificationRecieveConfig,
|
quote: notificationRecieveConfig,
|
||||||
reaction: notificationRecieveConfig,
|
reaction: notificationRecieveConfig,
|
||||||
pollEnded: notificationRecieveConfig,
|
pollEnded: notificationRecieveConfig,
|
||||||
scheduledNotePosted: notificationRecieveConfig,
|
|
||||||
scheduledNotePostFailed: notificationRecieveConfig,
|
|
||||||
receiveFollowRequest: notificationRecieveConfig,
|
receiveFollowRequest: notificationRecieveConfig,
|
||||||
followRequestAccepted: notificationRecieveConfig,
|
followRequestAccepted: notificationRecieveConfig,
|
||||||
roleAssigned: notificationRecieveConfig,
|
roleAssigned: notificationRecieveConfig,
|
||||||
|
|
|
@ -6,10 +6,17 @@
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import { In } from 'typeorm';
|
import { In } from 'typeorm';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import type { MiUser } from '@/models/User.js';
|
||||||
|
import type { UsersRepository, NotesRepository, BlockingsRepository, DriveFilesRepository, ChannelsRepository } from '@/models/_.js';
|
||||||
|
import type { MiDriveFile } from '@/models/DriveFile.js';
|
||||||
|
import type { MiNote } from '@/models/Note.js';
|
||||||
|
import type { MiChannel } from '@/models/Channel.js';
|
||||||
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
import { MAX_NOTE_TEXT_LENGTH } from '@/const.js';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
|
||||||
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
import { NoteCreateService } from '@/core/NoteCreateService.js';
|
||||||
|
import { DI } from '@/di-symbols.js';
|
||||||
|
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
||||||
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
import { IdentifiableError } from '@/misc/identifiable-error.js';
|
||||||
import { ApiError } from '../../error.js';
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
|
@ -216,28 +223,168 @@ 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.usersRepository)
|
||||||
|
private usersRepository: UsersRepository,
|
||||||
|
|
||||||
|
@Inject(DI.notesRepository)
|
||||||
|
private notesRepository: NotesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.blockingsRepository)
|
||||||
|
private blockingsRepository: BlockingsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.driveFilesRepository)
|
||||||
|
private driveFilesRepository: DriveFilesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.channelsRepository)
|
||||||
|
private channelsRepository: ChannelsRepository,
|
||||||
|
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private noteCreateService: NoteCreateService,
|
private noteCreateService: NoteCreateService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
let visibleUsers: MiUser[] = [];
|
||||||
|
if (ps.visibleUserIds) {
|
||||||
|
visibleUsers = await this.usersRepository.findBy({
|
||||||
|
id: In(ps.visibleUserIds),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let files: MiDriveFile[] = [];
|
||||||
|
const fileIds = ps.fileIds ?? ps.mediaIds ?? null;
|
||||||
|
if (fileIds != null) {
|
||||||
|
files = await this.driveFilesRepository.createQueryBuilder('file')
|
||||||
|
.where('file.userId = :userId AND file.id IN (:...fileIds)', {
|
||||||
|
userId: me.id,
|
||||||
|
fileIds,
|
||||||
|
})
|
||||||
|
.orderBy('array_position(ARRAY[:...fileIds], "id"::text)')
|
||||||
|
.setParameters({ fileIds })
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
if (files.length !== fileIds.length) {
|
||||||
|
throw new ApiError(meta.errors.noSuchFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let renote: MiNote | null = null;
|
||||||
|
if (ps.renoteId != null) {
|
||||||
|
// Fetch renote to note
|
||||||
|
renote = await this.notesRepository.findOne({
|
||||||
|
where: { id: ps.renoteId },
|
||||||
|
relations: ['user', 'renote', 'reply'],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (renote == null) {
|
||||||
|
throw new ApiError(meta.errors.noSuchRenoteTarget);
|
||||||
|
} else if (isRenote(renote) && !isQuote(renote)) {
|
||||||
|
throw new ApiError(meta.errors.cannotReRenote);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check blocking
|
||||||
|
if (renote.userId !== me.id) {
|
||||||
|
const blockExist = await this.blockingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
blockerId: renote.userId,
|
||||||
|
blockeeId: me.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (blockExist) {
|
||||||
|
throw new ApiError(meta.errors.youHaveBeenBlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renote.visibility === 'followers' && renote.userId !== me.id) {
|
||||||
|
// 他人のfollowers noteはreject
|
||||||
|
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
|
||||||
|
} else if (renote.visibility === 'specified') {
|
||||||
|
// specified / direct noteはreject
|
||||||
|
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renote.channelId && renote.channelId !== ps.channelId) {
|
||||||
|
// チャンネルのノートに対しリノート要求がきたとき、チャンネル外へのリノート可否をチェック
|
||||||
|
// リノートのユースケースのうち、チャンネル内→チャンネル外は少数だと考えられるため、JOINはせず必要な時に都度取得する
|
||||||
|
const renoteChannel = await this.channelsRepository.findOneBy({ id: renote.channelId });
|
||||||
|
if (renoteChannel == null) {
|
||||||
|
// リノートしたいノートが書き込まれているチャンネルが無い
|
||||||
|
throw new ApiError(meta.errors.noSuchChannel);
|
||||||
|
} else if (!renoteChannel.allowRenoteToExternal) {
|
||||||
|
// リノート作成のリクエストだが、対象チャンネルがリノート禁止だった場合
|
||||||
|
throw new ApiError(meta.errors.cannotRenoteOutsideOfChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let reply: MiNote | null = null;
|
||||||
|
if (ps.replyId != null) {
|
||||||
|
// Fetch reply
|
||||||
|
reply = await this.notesRepository.findOne({
|
||||||
|
where: { id: ps.replyId },
|
||||||
|
relations: ['user'],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (reply == null) {
|
||||||
|
throw new ApiError(meta.errors.noSuchReplyTarget);
|
||||||
|
} else if (isRenote(reply) && !isQuote(reply)) {
|
||||||
|
throw new ApiError(meta.errors.cannotReplyToPureRenote);
|
||||||
|
} else if (!await this.noteEntityService.isVisibleForMe(reply, me.id)) {
|
||||||
|
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
||||||
|
} else if (reply.visibility === 'specified' && ps.visibility !== 'specified') {
|
||||||
|
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check blocking
|
||||||
|
if (reply.userId !== me.id) {
|
||||||
|
const blockExist = await this.blockingsRepository.exists({
|
||||||
|
where: {
|
||||||
|
blockerId: reply.userId,
|
||||||
|
blockeeId: me.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (blockExist) {
|
||||||
|
throw new ApiError(meta.errors.youHaveBeenBlocked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ps.poll) {
|
||||||
|
if (typeof ps.poll.expiresAt === 'number') {
|
||||||
|
if (ps.poll.expiresAt < Date.now()) {
|
||||||
|
throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
|
||||||
|
}
|
||||||
|
} else if (typeof ps.poll.expiredAfter === 'number') {
|
||||||
|
ps.poll.expiresAt = Date.now() + ps.poll.expiredAfter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let channel: MiChannel | null = null;
|
||||||
|
if (ps.channelId != null) {
|
||||||
|
channel = await this.channelsRepository.findOneBy({ id: ps.channelId, isArchived: false });
|
||||||
|
|
||||||
|
if (channel == null) {
|
||||||
|
throw new ApiError(meta.errors.noSuchChannel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 投稿を作成
|
||||||
try {
|
try {
|
||||||
const note = await this.noteCreateService.fetchAndCreate(me, {
|
const note = await this.noteCreateService.create(me, {
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
fileIds: ps.fileIds ?? ps.mediaIds ?? [],
|
files: files,
|
||||||
poll: ps.poll ? {
|
poll: ps.poll ? {
|
||||||
choices: ps.poll.choices,
|
choices: ps.poll.choices,
|
||||||
multiple: ps.poll.multiple ?? false,
|
multiple: ps.poll.multiple ?? false,
|
||||||
expiresAt: ps.poll.expiredAfter ? new Date(Date.now() + ps.poll.expiredAfter) : ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
||||||
} : null,
|
} : undefined,
|
||||||
text: ps.text ?? null,
|
text: ps.text ?? undefined,
|
||||||
replyId: ps.replyId ?? null,
|
reply,
|
||||||
renoteId: ps.renoteId ?? null,
|
renote,
|
||||||
cw: ps.cw ?? null,
|
cw: ps.cw,
|
||||||
localOnly: ps.localOnly,
|
localOnly: ps.localOnly,
|
||||||
reactionAcceptance: ps.reactionAcceptance,
|
reactionAcceptance: ps.reactionAcceptance,
|
||||||
visibility: ps.visibility,
|
visibility: ps.visibility,
|
||||||
visibleUserIds: ps.visibleUserIds ?? [],
|
visibleUsers,
|
||||||
channelId: ps.channelId ?? null,
|
channel,
|
||||||
apMentions: ps.noExtractMentions ? [] : undefined,
|
apMentions: ps.noExtractMentions ? [] : undefined,
|
||||||
apHashtags: ps.noExtractHashtags ? [] : undefined,
|
apHashtags: ps.noExtractHashtags ? [] : undefined,
|
||||||
apEmojis: ps.noExtractEmojis ? [] : undefined,
|
apEmojis: ps.noExtractEmojis ? [] : undefined,
|
||||||
|
@ -246,46 +393,16 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
return {
|
return {
|
||||||
createdNote: await this.noteEntityService.pack(note, me),
|
createdNote: await this.noteEntityService.pack(note, me),
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
// TODO: 他のErrorもここでキャッチしてエラーメッセージを当てるようにしたい
|
// TODO: 他のErrorもここでキャッチしてエラーメッセージを当てるようにしたい
|
||||||
if (err instanceof IdentifiableError) {
|
if (e instanceof IdentifiableError) {
|
||||||
if (err.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') {
|
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') {
|
||||||
throw new ApiError(meta.errors.containsProhibitedWords);
|
throw new ApiError(meta.errors.containsProhibitedWords);
|
||||||
} else if (err.id === '9f466dab-c856-48cd-9e65-ff90ff750580') {
|
} else if (e.id === '9f466dab-c856-48cd-9e65-ff90ff750580') {
|
||||||
throw new ApiError(meta.errors.containsTooManyMentions);
|
throw new ApiError(meta.errors.containsTooManyMentions);
|
||||||
} else if (err.id === '801c046c-5bf5-4234-ad2b-e78fc20a2ac7') {
|
|
||||||
throw new ApiError(meta.errors.noSuchFile);
|
|
||||||
} else if (err.id === '53983c56-e163-45a6-942f-4ddc485d4290') {
|
|
||||||
throw new ApiError(meta.errors.noSuchRenoteTarget);
|
|
||||||
} else if (err.id === 'bde24c37-121f-4e7d-980d-cec52f599f02') {
|
|
||||||
throw new ApiError(meta.errors.cannotReRenote);
|
|
||||||
} else if (err.id === '2b4fe776-4414-4a2d-ae39-f3418b8fd4d3') {
|
|
||||||
throw new ApiError(meta.errors.youHaveBeenBlocked);
|
|
||||||
} else if (err.id === '90b9d6f0-893a-4fef-b0f1-e9a33989f71a') {
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
|
|
||||||
} else if (err.id === '48d7a997-da5c-4716-b3c3-92db3f37bf7d') {
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteDueToVisibility);
|
|
||||||
} else if (err.id === 'b060f9a6-8909-4080-9e0b-94d9fa6f6a77') {
|
|
||||||
throw new ApiError(meta.errors.noSuchChannel);
|
|
||||||
} else if (err.id === '7e435f4a-780d-4cfc-a15a-42519bd6fb67') {
|
|
||||||
throw new ApiError(meta.errors.cannotRenoteOutsideOfChannel);
|
|
||||||
} else if (err.id === '60142edb-1519-408e-926d-4f108d27bee0') {
|
|
||||||
throw new ApiError(meta.errors.noSuchReplyTarget);
|
|
||||||
} else if (err.id === 'f089e4e2-c0e7-4f60-8a23-e5a6bf786b36') {
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToPureRenote);
|
|
||||||
} else if (err.id === '11cd37b3-a411-4f77-8633-c580ce6a8dce') {
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
|
||||||
} else if (err.id === 'ced780a1-2012-4caf-bc7e-a95a291294cb') {
|
|
||||||
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
|
||||||
} else if (err.id === 'b0df6025-f2e8-44b4-a26a-17ad99104612') {
|
|
||||||
throw new ApiError(meta.errors.youHaveBeenBlocked);
|
|
||||||
} else if (err.id === '0c11c11e-0c8d-48e7-822c-76ccef660068') {
|
|
||||||
throw new ApiError(meta.errors.cannotCreateAlreadyExpiredPoll);
|
|
||||||
} else if (err.id === 'bfa3905b-25f5-4894-b430-da331a490e4b') {
|
|
||||||
throw new ApiError(meta.errors.noSuchChannel);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw err;
|
throw e;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,12 +124,6 @@ export const meta = {
|
||||||
id: '9ee33bbe-fde3-4c71-9b51-e50492c6b9c8',
|
id: '9ee33bbe-fde3-4c71-9b51-e50492c6b9c8',
|
||||||
},
|
},
|
||||||
|
|
||||||
tooManyScheduledNotes: {
|
|
||||||
message: 'You cannot create scheduled notes any more.',
|
|
||||||
code: 'TOO_MANY_SCHEDULED_NOTES',
|
|
||||||
id: '22ae69eb-09e3-4541-a850-773cfa45e693',
|
|
||||||
},
|
|
||||||
|
|
||||||
cannotRenoteToExternal: {
|
cannotRenoteToExternal: {
|
||||||
message: 'Cannot Renote to External.',
|
message: 'Cannot Renote to External.',
|
||||||
code: 'CANNOT_RENOTE_TO_EXTERNAL',
|
code: 'CANNOT_RENOTE_TO_EXTERNAL',
|
||||||
|
@ -168,7 +162,7 @@ export const paramDef = {
|
||||||
fileIds: {
|
fileIds: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
uniqueItems: true,
|
uniqueItems: true,
|
||||||
minItems: 0,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: { type: 'string', format: 'misskey:id' },
|
items: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
|
@ -189,10 +183,8 @@ export const paramDef = {
|
||||||
},
|
},
|
||||||
required: ['choices'],
|
required: ['choices'],
|
||||||
},
|
},
|
||||||
scheduledAt: { type: 'integer', nullable: true },
|
|
||||||
isActuallyScheduled: { type: 'boolean', default: false },
|
|
||||||
},
|
},
|
||||||
required: ['visibility', 'visibleUserIds', 'cw', 'hashtag', 'localOnly', 'reactionAcceptance', 'replyId', 'renoteId', 'channelId', 'text', 'fileIds', 'poll', 'scheduledAt', 'isActuallyScheduled'],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -204,23 +196,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const draft = await this.noteDraftService.create(me, {
|
const draft = await this.noteDraftService.create(me, {
|
||||||
fileIds: ps.fileIds,
|
fileIds: ps.fileIds,
|
||||||
pollChoices: ps.poll?.choices ?? [],
|
poll: ps.poll ? {
|
||||||
pollMultiple: ps.poll?.multiple ?? false,
|
choices: ps.poll.choices,
|
||||||
pollExpiresAt: ps.poll?.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
multiple: ps.poll.multiple ?? false,
|
||||||
pollExpiredAfter: ps.poll?.expiredAfter ?? null,
|
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
||||||
hasPoll: ps.poll != null,
|
expiredAfter: ps.poll.expiredAfter ?? null,
|
||||||
text: ps.text,
|
} : undefined,
|
||||||
replyId: ps.replyId,
|
text: ps.text ?? null,
|
||||||
renoteId: ps.renoteId,
|
replyId: ps.replyId ?? undefined,
|
||||||
cw: ps.cw,
|
renoteId: ps.renoteId ?? undefined,
|
||||||
hashtag: ps.hashtag,
|
cw: ps.cw ?? null,
|
||||||
|
...(ps.hashtag ? { hashtag: ps.hashtag } : {}),
|
||||||
localOnly: ps.localOnly,
|
localOnly: ps.localOnly,
|
||||||
reactionAcceptance: ps.reactionAcceptance,
|
reactionAcceptance: ps.reactionAcceptance,
|
||||||
visibility: ps.visibility,
|
visibility: ps.visibility,
|
||||||
visibleUserIds: ps.visibleUserIds,
|
visibleUserIds: ps.visibleUserIds ?? [],
|
||||||
channelId: ps.channelId,
|
channelId: ps.channelId ?? undefined,
|
||||||
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
|
||||||
isActuallyScheduled: ps.isActuallyScheduled,
|
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
if (err instanceof IdentifiableError) {
|
if (err instanceof IdentifiableError) {
|
||||||
switch (err.id) {
|
switch (err.id) {
|
||||||
|
@ -250,8 +241,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
throw new ApiError(meta.errors.cannotReplyToInvisibleNote);
|
||||||
case '215dbc76-336c-4d2a-9605-95766ba7dab0':
|
case '215dbc76-336c-4d2a-9605-95766ba7dab0':
|
||||||
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
throw new ApiError(meta.errors.cannotReplyToSpecifiedVisibilityNoteWithExtendedVisibility);
|
||||||
case 'c3275f19-4558-4c59-83e1-4f684b5fab66':
|
|
||||||
throw new ApiError(meta.errors.tooManyScheduledNotes);
|
|
||||||
default:
|
default:
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ export const paramDef = {
|
||||||
untilId: { type: 'string', format: 'misskey:id' },
|
untilId: { type: 'string', format: 'misskey:id' },
|
||||||
sinceDate: { type: 'integer' },
|
sinceDate: { type: 'integer' },
|
||||||
untilDate: { type: 'integer' },
|
untilDate: { type: 'integer' },
|
||||||
scheduled: { type: 'boolean', nullable: true },
|
|
||||||
},
|
},
|
||||||
required: [],
|
required: [],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -59,12 +58,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
const query = this.queryService.makePaginationQuery<MiNoteDraft>(this.noteDraftsRepository.createQueryBuilder('drafts'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
const query = this.queryService.makePaginationQuery<MiNoteDraft>(this.noteDraftsRepository.createQueryBuilder('drafts'), ps.sinceId, ps.untilId, ps.sinceDate, ps.untilDate)
|
||||||
.andWhere('drafts.userId = :meId', { meId: me.id });
|
.andWhere('drafts.userId = :meId', { meId: me.id });
|
||||||
|
|
||||||
if (ps.scheduled === true) {
|
|
||||||
query.andWhere('drafts.isActuallyScheduled = true');
|
|
||||||
} else if (ps.scheduled === false) {
|
|
||||||
query.andWhere('drafts.isActuallyScheduled = false');
|
|
||||||
}
|
|
||||||
|
|
||||||
const drafts = await query
|
const drafts = await query
|
||||||
.limit(ps.limit)
|
.limit(ps.limit)
|
||||||
.getMany();
|
.getMany();
|
||||||
|
|
|
@ -159,12 +159,6 @@ export const meta = {
|
||||||
code: 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY',
|
code: 'CANNOT_REPLY_TO_SPECIFIED_VISIBILITY_NOTE_WITH_EXTENDED_VISIBILITY',
|
||||||
id: '215dbc76-336c-4d2a-9605-95766ba7dab0',
|
id: '215dbc76-336c-4d2a-9605-95766ba7dab0',
|
||||||
},
|
},
|
||||||
|
|
||||||
tooManyScheduledNotes: {
|
|
||||||
message: 'You cannot create scheduled notes any more.',
|
|
||||||
code: 'TOO_MANY_SCHEDULED_NOTES',
|
|
||||||
id: '02f5df79-08ae-4a33-8524-f1503c8f6212',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
|
||||||
limit: {
|
limit: {
|
||||||
|
@ -177,14 +171,14 @@ export const paramDef = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
draftId: { type: 'string', nullable: false, format: 'misskey:id' },
|
draftId: { type: 'string', nullable: false, format: 'misskey:id' },
|
||||||
visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'] },
|
visibility: { type: 'string', enum: ['public', 'home', 'followers', 'specified'], default: 'public' },
|
||||||
visibleUserIds: { type: 'array', uniqueItems: true, items: {
|
visibleUserIds: { type: 'array', uniqueItems: true, items: {
|
||||||
type: 'string', format: 'misskey:id',
|
type: 'string', format: 'misskey:id',
|
||||||
} },
|
} },
|
||||||
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
|
cw: { type: 'string', nullable: true, minLength: 1, maxLength: 100 },
|
||||||
hashtag: { type: 'string', nullable: true, maxLength: 200 },
|
hashtag: { type: 'string', nullable: true, maxLength: 200 },
|
||||||
localOnly: { type: 'boolean' },
|
localOnly: { type: 'boolean', default: false },
|
||||||
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'] },
|
reactionAcceptance: { type: 'string', nullable: true, enum: [null, 'likeOnly', 'likeOnlyForRemote', 'nonSensitiveOnly', 'nonSensitiveOnlyForLocalLikeOnlyForRemote'], default: null },
|
||||||
replyId: { type: 'string', format: 'misskey:id', nullable: true },
|
replyId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
|
renoteId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
channelId: { type: 'string', format: 'misskey:id', nullable: true },
|
channelId: { type: 'string', format: 'misskey:id', nullable: true },
|
||||||
|
@ -200,7 +194,7 @@ export const paramDef = {
|
||||||
fileIds: {
|
fileIds: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
uniqueItems: true,
|
uniqueItems: true,
|
||||||
minItems: 0,
|
minItems: 1,
|
||||||
maxItems: 16,
|
maxItems: 16,
|
||||||
items: { type: 'string', format: 'misskey:id' },
|
items: { type: 'string', format: 'misskey:id' },
|
||||||
},
|
},
|
||||||
|
@ -221,8 +215,6 @@ export const paramDef = {
|
||||||
},
|
},
|
||||||
required: ['choices'],
|
required: ['choices'],
|
||||||
},
|
},
|
||||||
scheduledAt: { type: 'integer', nullable: true },
|
|
||||||
isActuallyScheduled: { type: 'boolean' },
|
|
||||||
},
|
},
|
||||||
required: ['draftId'],
|
required: ['draftId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -236,22 +228,22 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const draft = await this.noteDraftService.update(me, ps.draftId, {
|
const draft = await this.noteDraftService.update(me, ps.draftId, {
|
||||||
fileIds: ps.fileIds,
|
fileIds: ps.fileIds,
|
||||||
pollChoices: ps.poll?.choices,
|
poll: ps.poll ? {
|
||||||
pollMultiple: ps.poll?.multiple,
|
choices: ps.poll.choices,
|
||||||
pollExpiresAt: ps.poll?.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
multiple: ps.poll.multiple ?? false,
|
||||||
pollExpiredAfter: ps.poll?.expiredAfter,
|
expiresAt: ps.poll.expiresAt ? new Date(ps.poll.expiresAt) : null,
|
||||||
text: ps.text,
|
expiredAfter: ps.poll.expiredAfter ?? null,
|
||||||
replyId: ps.replyId,
|
} : undefined,
|
||||||
renoteId: ps.renoteId,
|
text: ps.text ?? null,
|
||||||
cw: ps.cw,
|
replyId: ps.replyId ?? undefined,
|
||||||
hashtag: ps.hashtag,
|
renoteId: ps.renoteId ?? undefined,
|
||||||
|
cw: ps.cw ?? null,
|
||||||
|
...(ps.hashtag ? { hashtag: ps.hashtag } : {}),
|
||||||
localOnly: ps.localOnly,
|
localOnly: ps.localOnly,
|
||||||
reactionAcceptance: ps.reactionAcceptance,
|
reactionAcceptance: ps.reactionAcceptance,
|
||||||
visibility: ps.visibility,
|
visibility: ps.visibility,
|
||||||
visibleUserIds: ps.visibleUserIds,
|
visibleUserIds: ps.visibleUserIds ?? [],
|
||||||
channelId: ps.channelId,
|
channelId: ps.channelId ?? undefined,
|
||||||
scheduledAt: ps.scheduledAt ? new Date(ps.scheduledAt) : null,
|
|
||||||
isActuallyScheduled: ps.isActuallyScheduled,
|
|
||||||
}).catch((err) => {
|
}).catch((err) => {
|
||||||
if (err instanceof IdentifiableError) {
|
if (err instanceof IdentifiableError) {
|
||||||
switch (err.id) {
|
switch (err.id) {
|
||||||
|
@ -293,8 +285,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
throw new ApiError(meta.errors.containsProhibitedWords);
|
throw new ApiError(meta.errors.containsProhibitedWords);
|
||||||
case '4de0363a-3046-481b-9b0f-feff3e211025':
|
case '4de0363a-3046-481b-9b0f-feff3e211025':
|
||||||
throw new ApiError(meta.errors.containsTooManyMentions);
|
throw new ApiError(meta.errors.containsTooManyMentions);
|
||||||
case 'bacdf856-5c51-4159-b88a-804fa5103be5':
|
|
||||||
throw new ApiError(meta.errors.tooManyScheduledNotes);
|
|
||||||
default:
|
default:
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
* quote - 投稿が引用Renoteされた
|
* quote - 投稿が引用Renoteされた
|
||||||
* reaction - 投稿にリアクションされた
|
* reaction - 投稿にリアクションされた
|
||||||
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
||||||
* scheduledNotePosted - 予約したノートが投稿された
|
|
||||||
* scheduledNotePostFailed - 予約したノートの投稿に失敗した
|
|
||||||
* receiveFollowRequest - フォローリクエストされた
|
* receiveFollowRequest - フォローリクエストされた
|
||||||
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
||||||
* roleAssigned - ロールが付与された
|
* roleAssigned - ロールが付与された
|
||||||
|
@ -34,8 +32,6 @@ export const notificationTypes = [
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
'scheduledNotePosted',
|
|
||||||
'scheduledNotePostFailed',
|
|
||||||
'receiveFollowRequest',
|
'receiveFollowRequest',
|
||||||
'followRequestAccepted',
|
'followRequestAccepted',
|
||||||
'roleAssigned',
|
'roleAssigned',
|
||||||
|
|
|
@ -64,8 +64,6 @@ function toBase62(n: number): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfig(): UserConfig {
|
export function getConfig(): UserConfig {
|
||||||
const localesHash = toBase62(hash(JSON.stringify(locales)));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
base: '/embed_vite/',
|
base: '/embed_vite/',
|
||||||
|
|
||||||
|
@ -150,9 +148,9 @@ export function getConfig(): UserConfig {
|
||||||
// dependencies of i18n.ts
|
// dependencies of i18n.ts
|
||||||
'config': ['@@/js/config.js'],
|
'config': ['@@/js/config.js'],
|
||||||
},
|
},
|
||||||
entryFileNames: `scripts/${localesHash}-[hash:8].js`,
|
entryFileNames: 'scripts/[hash:8].js',
|
||||||
chunkFileNames: `scripts/${localesHash}-[hash:8].js`,
|
chunkFileNames: 'scripts/[hash:8].js',
|
||||||
assetFileNames: `assets/${localesHash}-[hash:8][extname]`,
|
assetFileNames: 'assets/[hash:8][extname]',
|
||||||
paths(id) {
|
paths(id) {
|
||||||
for (const p of externalPackages) {
|
for (const p of externalPackages) {
|
||||||
if (p.match.test(id)) {
|
if (p.match.test(id)) {
|
||||||
|
|
|
@ -57,7 +57,6 @@
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"magic-string": "0.30.18",
|
"magic-string": "0.30.18",
|
||||||
"matter-js": "0.20.0",
|
"matter-js": "0.20.0",
|
||||||
"mediabunny": "1.15.1",
|
|
||||||
"mfm-js": "0.25.0",
|
"mfm-js": "0.25.0",
|
||||||
"misskey-bubble-game": "workspace:*",
|
"misskey-bubble-game": "workspace:*",
|
||||||
"misskey-js": "workspace:*",
|
"misskey-js": "workspace:*",
|
||||||
|
|
|
@ -10,7 +10,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
|
import { onMounted, onUnmounted, useTemplateRef } from 'vue';
|
||||||
import isChromatic from 'chromatic/isChromatic';
|
import isChromatic from 'chromatic/isChromatic';
|
||||||
import { initShaderProgram } from '@/utility/webgl.js';
|
|
||||||
|
|
||||||
const canvasEl = useTemplateRef('canvasEl');
|
const canvasEl = useTemplateRef('canvasEl');
|
||||||
|
|
||||||
|
@ -22,6 +21,47 @@ const props = withDefaults(defineProps<{
|
||||||
focus: 1.0,
|
focus: 1.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function loadShader(gl: WebGLRenderingContext, type: number, source: string) {
|
||||||
|
const shader = gl.createShader(type);
|
||||||
|
if (shader == null) return null;
|
||||||
|
|
||||||
|
gl.shaderSource(shader, source);
|
||||||
|
gl.compileShader(shader);
|
||||||
|
|
||||||
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||||
|
alert(
|
||||||
|
`falied to compile shader: ${gl.getShaderInfoLog(shader)}`,
|
||||||
|
);
|
||||||
|
gl.deleteShader(shader);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
function initShaderProgram(gl: WebGLRenderingContext, vsSource: string, fsSource: string) {
|
||||||
|
const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
|
||||||
|
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
|
||||||
|
|
||||||
|
const shaderProgram = gl.createProgram();
|
||||||
|
if (vertexShader == null || fragmentShader == null) return null;
|
||||||
|
|
||||||
|
gl.attachShader(shaderProgram, vertexShader);
|
||||||
|
gl.attachShader(shaderProgram, fragmentShader);
|
||||||
|
gl.linkProgram(shaderProgram);
|
||||||
|
|
||||||
|
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
|
||||||
|
alert(
|
||||||
|
`failed to init shader: ${gl.getProgramInfoLog(
|
||||||
|
shaderProgram,
|
||||||
|
)}`,
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return shaderProgram;
|
||||||
|
}
|
||||||
|
|
||||||
let handle: ReturnType<typeof window['requestAnimationFrame']> | null = null;
|
let handle: ReturnType<typeof window['requestAnimationFrame']> | null = null;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -31,7 +71,7 @@ onMounted(() => {
|
||||||
canvas.width = width;
|
canvas.width = width;
|
||||||
canvas.height = height;
|
canvas.height = height;
|
||||||
|
|
||||||
const maybeGl = canvas.getContext('webgl2', { premultipliedAlpha: true });
|
const maybeGl = canvas.getContext('webgl', { premultipliedAlpha: true });
|
||||||
if (maybeGl == null) return;
|
if (maybeGl == null) return;
|
||||||
|
|
||||||
const gl = maybeGl;
|
const gl = maybeGl;
|
||||||
|
@ -42,16 +82,18 @@ onMounted(() => {
|
||||||
const positionBuffer = gl.createBuffer();
|
const positionBuffer = gl.createBuffer();
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
|
||||||
|
|
||||||
const shaderProgram = initShaderProgram(gl, `#version 300 es
|
const shaderProgram = initShaderProgram(gl, `
|
||||||
in vec2 position;
|
attribute vec2 vertex;
|
||||||
|
|
||||||
uniform vec2 u_scale;
|
uniform vec2 u_scale;
|
||||||
out vec2 in_uv;
|
|
||||||
|
varying vec2 v_pos;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = vec4(position, 0.0, 1.0);
|
gl_Position = vec4(vertex, 0.0, 1.0);
|
||||||
in_uv = position / u_scale;
|
v_pos = vertex / u_scale;
|
||||||
}
|
}
|
||||||
`, `#version 300 es
|
`, `
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
|
||||||
vec3 mod289(vec3 x) {
|
vec3 mod289(vec3 x) {
|
||||||
|
@ -101,7 +143,6 @@ onMounted(() => {
|
||||||
return 130.0 * dot(m, g);
|
return 130.0 * dot(m, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform float u_time;
|
uniform float u_time;
|
||||||
uniform vec2 u_resolution;
|
uniform vec2 u_resolution;
|
||||||
uniform float u_spread;
|
uniform float u_spread;
|
||||||
|
@ -109,7 +150,8 @@ onMounted(() => {
|
||||||
uniform float u_warp;
|
uniform float u_warp;
|
||||||
uniform float u_focus;
|
uniform float u_focus;
|
||||||
uniform float u_itensity;
|
uniform float u_itensity;
|
||||||
out vec4 out_color;
|
|
||||||
|
varying vec2 v_pos;
|
||||||
|
|
||||||
float circle( in vec2 _pos, in vec2 _origin, in float _radius ) {
|
float circle( in vec2 _pos, in vec2 _origin, in float _radius ) {
|
||||||
float SPREAD = 0.7 * u_spread;
|
float SPREAD = 0.7 * u_spread;
|
||||||
|
@ -140,13 +182,13 @@ onMounted(() => {
|
||||||
|
|
||||||
float ratio = u_resolution.x / u_resolution.y;
|
float ratio = u_resolution.x / u_resolution.y;
|
||||||
|
|
||||||
vec2 uv = vec2( in_uv.x, in_uv.y / ratio ) * 0.5 + 0.5;
|
vec2 uv = vec2( v_pos.x, v_pos.y / ratio ) * 0.5 + 0.5;
|
||||||
|
|
||||||
vec3 color = vec3( 0.0 );
|
vec3 color = vec3( 0.0 );
|
||||||
|
|
||||||
float greenMix = snoise( in_uv * 1.31 + u_time * 0.8 * 0.00017 ) * 0.5 + 0.5;
|
float greenMix = snoise( v_pos * 1.31 + u_time * 0.8 * 0.00017 ) * 0.5 + 0.5;
|
||||||
float purpleMix = snoise( in_uv * 1.26 + u_time * 0.8 * -0.0001 ) * 0.5 + 0.5;
|
float purpleMix = snoise( v_pos * 1.26 + u_time * 0.8 * -0.0001 ) * 0.5 + 0.5;
|
||||||
float orangeMix = snoise( in_uv * 1.34 + u_time * 0.8 * 0.00015 ) * 0.5 + 0.5;
|
float orangeMix = snoise( v_pos * 1.34 + u_time * 0.8 * 0.00015 ) * 0.5 + 0.5;
|
||||||
|
|
||||||
float alphaOne = 0.35 + 0.65 * pow( snoise( vec2( u_time * 0.00012, uv.x ) ) * 0.5 + 0.5, 1.2 );
|
float alphaOne = 0.35 + 0.65 * pow( snoise( vec2( u_time * 0.00012, uv.x ) ) * 0.5 + 0.5, 1.2 );
|
||||||
float alphaTwo = 0.35 + 0.65 * pow( snoise( vec2( ( u_time + 1561.0 ) * 0.00014, uv.x ) ) * 0.5 + 0.5, 1.2 );
|
float alphaTwo = 0.35 + 0.65 * pow( snoise( vec2( ( u_time + 1561.0 ) * 0.00014, uv.x ) ) * 0.5 + 0.5, 1.2 );
|
||||||
|
@ -156,10 +198,10 @@ onMounted(() => {
|
||||||
color += vec3( circle( uv, vec2( 0.90 + cos( u_time * 0.000166 ) * 0.06, 0.42 + sin( u_time * 0.000138 ) * 0.06 ), 0.18 ) ) * alphaTwo * ( green * greenMix + purple * purpleMix );
|
color += vec3( circle( uv, vec2( 0.90 + cos( u_time * 0.000166 ) * 0.06, 0.42 + sin( u_time * 0.000138 ) * 0.06 ), 0.18 ) ) * alphaTwo * ( green * greenMix + purple * purpleMix );
|
||||||
color += vec3( circle( uv, vec2( 0.19 + sin( u_time * 0.000112 ) * 0.06, 0.25 + sin( u_time * 0.000192 ) * 0.06 ), 0.09 ) ) * alphaThree * ( orange * orangeMix );
|
color += vec3( circle( uv, vec2( 0.19 + sin( u_time * 0.000112 ) * 0.06, 0.25 + sin( u_time * 0.000192 ) * 0.06 ), 0.09 ) ) * alphaThree * ( orange * orangeMix );
|
||||||
|
|
||||||
color *= u_itensity + 1.0 * pow( snoise( vec2( in_uv.y + u_time * 0.00013, in_uv.x + u_time * -0.00009 ) ) * 0.5 + 0.5, 2.0 );
|
color *= u_itensity + 1.0 * pow( snoise( vec2( v_pos.y + u_time * 0.00013, v_pos.x + u_time * -0.00009 ) ) * 0.5 + 0.5, 2.0 );
|
||||||
|
|
||||||
vec3 inverted = vec3( 1.0 ) - color;
|
vec3 inverted = vec3( 1.0 ) - color;
|
||||||
out_color = vec4(color, max(max(color.x, color.y), color.z));
|
gl_FragColor = vec4( color, max(max(color.x, color.y), color.z) );
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
if (shaderProgram == null) return;
|
if (shaderProgram == null) return;
|
||||||
|
@ -181,7 +223,7 @@ onMounted(() => {
|
||||||
gl.uniform1f(u_itensity, 0.5);
|
gl.uniform1f(u_itensity, 0.5);
|
||||||
gl.uniform2fv(u_scale, [props.scale, props.scale]);
|
gl.uniform2fv(u_scale, [props.scale, props.scale]);
|
||||||
|
|
||||||
const vertex = gl.getAttribLocation(shaderProgram, 'position');
|
const vertex = gl.getAttribLocation(shaderProgram, 'vertex');
|
||||||
gl.enableVertexAttribArray(vertex);
|
gl.enableVertexAttribArray(vertex);
|
||||||
gl.vertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0);
|
gl.vertexAttribPointer(vertex, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
|
|
|
@ -530,14 +530,6 @@ defineExpose({
|
||||||
--eachSize: 50px;
|
--eachSize: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.s4 {
|
|
||||||
--eachSize: 55px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.s5 {
|
|
||||||
--eachSize: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.w1 {
|
&.w1 {
|
||||||
width: calc((var(--eachSize) * 5) + (#{$pad} * 2));
|
width: calc((var(--eachSize) * 5) + (#{$pad} * 2));
|
||||||
--columns: 1fr 1fr 1fr 1fr 1fr;
|
--columns: 1fr 1fr 1fr 1fr 1fr;
|
||||||
|
|
|
@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.previewContainer">
|
<div :class="$style.previewContainer">
|
||||||
<div class="_acrylic" :class="$style.previewTitle">{{ i18n.ts.preview }}</div>
|
<div class="_acrylic" :class="$style.previewTitle">{{ i18n.ts.preview }}</div>
|
||||||
<div class="_acrylic" :class="$style.editControls">
|
<div class="_acrylic" :class="$style.editControls">
|
||||||
<button class="_button" :class="[$style.previewControlsButton, penMode != null ? $style.active : null]" @click="showPenMenu"><i class="ti ti-pencil"></i></button>
|
<button class="_button" :class="[$style.previewControlsButton, fillSquare ? $style.active : null]" @click="fillSquare = true"><i class="ti ti-pencil"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="_acrylic" :class="$style.previewControls">
|
<div class="_acrylic" :class="$style.previewControls">
|
||||||
<button class="_button" :class="[$style.previewControlsButton, !enabled ? $style.active : null]" @click="enabled = false">Before</button>
|
<button class="_button" :class="[$style.previewControlsButton, !enabled ? $style.active : null]" @click="enabled = false">Before</button>
|
||||||
|
@ -216,29 +216,10 @@ watch(enabled, () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const penMode = ref<'fill' | 'blur' | 'pixelate' | null>(null);
|
const fillSquare = ref(false);
|
||||||
|
|
||||||
function showPenMenu(ev: MouseEvent) {
|
|
||||||
os.popupMenu([{
|
|
||||||
text: i18n.ts._imageEffector._fxs.fill,
|
|
||||||
action: () => {
|
|
||||||
penMode.value = 'fill';
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: i18n.ts._imageEffector._fxs.blur,
|
|
||||||
action: () => {
|
|
||||||
penMode.value = 'blur';
|
|
||||||
},
|
|
||||||
}, {
|
|
||||||
text: i18n.ts._imageEffector._fxs.pixelate,
|
|
||||||
action: () => {
|
|
||||||
penMode.value = 'pixelate';
|
|
||||||
},
|
|
||||||
}], ev.currentTarget ?? ev.target);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onImagePointerdown(ev: PointerEvent) {
|
function onImagePointerdown(ev: PointerEvent) {
|
||||||
if (canvasEl.value == null || imageBitmap == null || penMode.value == null) return;
|
if (canvasEl.value == null || imageBitmap == null || !fillSquare.value) return;
|
||||||
|
|
||||||
const AW = canvasEl.value.clientWidth;
|
const AW = canvasEl.value.clientWidth;
|
||||||
const AH = canvasEl.value.clientHeight;
|
const AH = canvasEl.value.clientHeight;
|
||||||
|
@ -269,10 +250,9 @@ function onImagePointerdown(ev: PointerEvent) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const id = genId();
|
const id = genId();
|
||||||
if (penMode.value === 'fill') {
|
|
||||||
layers.push({
|
layers.push({
|
||||||
id,
|
id,
|
||||||
fxId: 'fill',
|
fxId: 'fillSquare',
|
||||||
params: {
|
params: {
|
||||||
offsetX: 0,
|
offsetX: 0,
|
||||||
offsetY: 0,
|
offsetY: 0,
|
||||||
|
@ -283,33 +263,6 @@ function onImagePointerdown(ev: PointerEvent) {
|
||||||
color: [1, 1, 1],
|
color: [1, 1, 1],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (penMode.value === 'blur') {
|
|
||||||
layers.push({
|
|
||||||
id,
|
|
||||||
fxId: 'blur',
|
|
||||||
params: {
|
|
||||||
offsetX: 0,
|
|
||||||
offsetY: 0,
|
|
||||||
scaleX: 0.1,
|
|
||||||
scaleY: 0.1,
|
|
||||||
angle: 0,
|
|
||||||
radius: 3,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (penMode.value === 'pixelate') {
|
|
||||||
layers.push({
|
|
||||||
id,
|
|
||||||
fxId: 'pixelate',
|
|
||||||
params: {
|
|
||||||
offsetX: 0,
|
|
||||||
offsetY: 0,
|
|
||||||
scaleX: 0.1,
|
|
||||||
scaleY: 0.1,
|
|
||||||
angle: 0,
|
|
||||||
strength: 0.2,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_move(ev.offsetX, ev.offsetY);
|
_move(ev.offsetX, ev.offsetY);
|
||||||
|
|
||||||
|
@ -349,7 +302,7 @@ function onImagePointerdown(ev: PointerEvent) {
|
||||||
canvasEl.value?.removeEventListener('pointercancel', up);
|
canvasEl.value?.removeEventListener('pointercancel', up);
|
||||||
canvasEl.value?.releasePointerCapture(ev.pointerId);
|
canvasEl.value?.releasePointerCapture(ev.pointerId);
|
||||||
|
|
||||||
penMode.value = null;
|
fillSquare.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
canvasEl.value.addEventListener('pointermove', move);
|
canvasEl.value.addEventListener('pointermove', move);
|
||||||
|
|
|
@ -15,32 +15,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
@esc="cancel()"
|
@esc="cancel()"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
{{ i18n.ts.draftsAndScheduledNotes }} ({{ currentDraftsCount }}/{{ $i?.policies.noteDraftLimit }})
|
{{ i18n.ts.drafts }} ({{ currentDraftsCount }}/{{ $i?.policies.noteDraftLimit }})
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MkStickyContainer>
|
|
||||||
<template #header>
|
|
||||||
<MkTabs
|
|
||||||
v-model:tab="tab"
|
|
||||||
centered
|
|
||||||
:class="$style.tabs"
|
|
||||||
:tabs="[
|
|
||||||
{
|
|
||||||
key: 'drafts',
|
|
||||||
title: i18n.ts.drafts,
|
|
||||||
icon: 'ti ti-pencil-question',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'scheduled',
|
|
||||||
title: i18n.ts.scheduled,
|
|
||||||
icon: 'ti ti-calendar-clock',
|
|
||||||
},
|
|
||||||
]"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div class="_spacer">
|
<div class="_spacer">
|
||||||
<MkPagination :key="tab" :paginator="tab === 'scheduled' ? scheduledPaginator : draftsPaginator" withControl>
|
<MkPagination :paginator="paginator" withControl>
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<MkResult type="empty" :text="i18n.ts._drafts.noDrafts"/>
|
<MkResult type="empty" :text="i18n.ts._drafts.noDrafts"/>
|
||||||
</template>
|
</template>
|
||||||
|
@ -54,13 +32,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="[$style.draft]"
|
:class="[$style.draft]"
|
||||||
>
|
>
|
||||||
<div :class="$style.draftBody" class="_gaps_s">
|
<div :class="$style.draftBody" class="_gaps_s">
|
||||||
<MkInfo v-if="draft.scheduledAt != null && draft.isActuallyScheduled">
|
|
||||||
<I18n :src="i18n.ts.scheduledToPostOnX" tag="span">
|
|
||||||
<template #x>
|
|
||||||
<MkTime :time="draft.scheduledAt" :mode="'detail'" style="font-weight: bold;"/>
|
|
||||||
</template>
|
|
||||||
</I18n>
|
|
||||||
</MkInfo>
|
|
||||||
<div :class="$style.draftInfo">
|
<div :class="$style.draftInfo">
|
||||||
<div :class="$style.draftMeta">
|
<div :class="$style.draftMeta">
|
||||||
<div v-if="draft.reply" class="_nowrap">
|
<div v-if="draft.reply" class="_nowrap">
|
||||||
|
@ -114,33 +85,14 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkTime :time="draft.createdAt" :class="$style.draftCreatedAt" mode="detail" colored/>
|
<MkTime :time="draft.createdAt" :class="$style.draftCreatedAt" mode="detail" colored/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div :class="$style.draftActions" class="_buttons">
|
<div :class="$style.draftActions" class="_buttons">
|
||||||
<template v-if="draft.scheduledAt != null && draft.isActuallyScheduled">
|
|
||||||
<MkButton
|
<MkButton
|
||||||
:class="$style.itemButton"
|
|
||||||
small
|
|
||||||
@click="cancelSchedule(draft)"
|
|
||||||
>
|
|
||||||
<i class="ti ti-calendar-x"></i> {{ i18n.ts._drafts.cancelSchedule }}
|
|
||||||
</MkButton>
|
|
||||||
<!-- TODO
|
|
||||||
<MkButton
|
|
||||||
:class="$style.itemButton"
|
|
||||||
small
|
|
||||||
@click="reSchedule(draft)"
|
|
||||||
>
|
|
||||||
<i class="ti ti-calendar-time"></i> {{ i18n.ts._drafts.reSchedule }}
|
|
||||||
</MkButton>
|
|
||||||
-->
|
|
||||||
</template>
|
|
||||||
<MkButton
|
|
||||||
v-else
|
|
||||||
:class="$style.itemButton"
|
:class="$style.itemButton"
|
||||||
small
|
small
|
||||||
@click="restoreDraft(draft)"
|
@click="restoreDraft(draft)"
|
||||||
>
|
>
|
||||||
<i class="ti ti-corner-up-left"></i> {{ i18n.ts._drafts.restore }}
|
<i class="ti ti-corner-up-left"></i>
|
||||||
|
{{ i18n.ts._drafts.restore }}
|
||||||
</MkButton>
|
</MkButton>
|
||||||
<MkButton
|
<MkButton
|
||||||
v-tooltip="i18n.ts._drafts.delete"
|
v-tooltip="i18n.ts._drafts.delete"
|
||||||
|
@ -148,7 +100,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
small
|
small
|
||||||
:iconOnly="true"
|
:iconOnly="true"
|
||||||
:class="$style.itemButton"
|
:class="$style.itemButton"
|
||||||
style="margin-left: auto;"
|
|
||||||
@click="deleteDraft(draft)"
|
@click="deleteDraft(draft)"
|
||||||
>
|
>
|
||||||
<i class="ti ti-trash"></i>
|
<i class="ti ti-trash"></i>
|
||||||
|
@ -159,7 +110,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
</MkStickyContainer>
|
|
||||||
</MkModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -175,12 +125,6 @@ import * as os from '@/os.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { misskeyApi } from '@/utility/misskey-api';
|
import { misskeyApi } from '@/utility/misskey-api';
|
||||||
import { Paginator } from '@/utility/paginator.js';
|
import { Paginator } from '@/utility/paginator.js';
|
||||||
import MkTabs from '@/components/MkTabs.vue';
|
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
|
||||||
|
|
||||||
const props = defineProps<{
|
|
||||||
scheduled?: boolean;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'restore', draft: Misskey.entities.NoteDraft): void;
|
(ev: 'restore', draft: Misskey.entities.NoteDraft): void;
|
||||||
|
@ -188,20 +132,8 @@ const emit = defineEmits<{
|
||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const tab = ref<'drafts' | 'scheduled'>(props.scheduled ? 'scheduled' : 'drafts');
|
const paginator = markRaw(new Paginator('notes/drafts/list', {
|
||||||
|
|
||||||
const draftsPaginator = markRaw(new Paginator('notes/drafts/list', {
|
|
||||||
limit: 10,
|
limit: 10,
|
||||||
params: {
|
|
||||||
scheduled: false,
|
|
||||||
},
|
|
||||||
}));
|
|
||||||
|
|
||||||
const scheduledPaginator = markRaw(new Paginator('notes/drafts/list', {
|
|
||||||
limit: 10,
|
|
||||||
params: {
|
|
||||||
scheduled: true,
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const currentDraftsCount = ref(0);
|
const currentDraftsCount = ref(0);
|
||||||
|
@ -230,17 +162,7 @@ async function deleteDraft(draft: Misskey.entities.NoteDraft) {
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
os.apiWithDialog('notes/drafts/delete', { draftId: draft.id }).then(() => {
|
os.apiWithDialog('notes/drafts/delete', { draftId: draft.id }).then(() => {
|
||||||
draftsPaginator.reload();
|
paginator.reload();
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function cancelSchedule(draft: Misskey.entities.NoteDraft) {
|
|
||||||
os.apiWithDialog('notes/drafts/update', {
|
|
||||||
draftId: draft.id,
|
|
||||||
isActuallyScheduled: false,
|
|
||||||
scheduledAt: null,
|
|
||||||
}).then(() => {
|
|
||||||
scheduledPaginator.reload();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -298,11 +220,4 @@ async function cancelSchedule(draft: Misskey.entities.NoteDraft) {
|
||||||
padding-top: 16px;
|
padding-top: 16px;
|
||||||
border-top: solid 1px var(--MI_THEME-divider);
|
border-top: solid 1px var(--MI_THEME-divider);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs {
|
|
||||||
background: color(from var(--MI_THEME-bg) srgb r g b / 0.75);
|
|
||||||
-webkit-backdrop-filter: var(--MI-blur, blur(15px));
|
|
||||||
backdrop-filter: var(--MI-blur, blur(15px));
|
|
||||||
border-bottom: solid 0.5px var(--MI_THEME-divider);
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.root">
|
<div :class="$style.root">
|
||||||
<div :class="$style.head">
|
<div :class="$style.head">
|
||||||
<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
|
<MkAvatar v-if="['pollEnded', 'note'].includes(notification.type) && 'note' in notification" :class="$style.icon" :user="notification.note.user" link preview/>
|
||||||
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login', 'createToken', 'scheduledNotePosted', 'scheduledNotePostFailed'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
<MkAvatar v-else-if="['roleAssigned', 'achievementEarned', 'exportCompleted', 'login', 'createToken'].includes(notification.type)" :class="$style.icon" :user="$i" link preview/>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped' && notification.note.reactionAcceptance === 'likeOnly'" :class="[$style.icon, $style.icon_reactionGroupHeart]"><i class="ti ti-heart" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'reaction:grouped'" :class="[$style.icon, $style.icon_reactionGroup]"><i class="ti ti-plus" style="line-height: 1;"></i></div>
|
||||||
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
<div v-else-if="notification.type === 'renote:grouped'" :class="[$style.icon, $style.icon_renoteGroup]"><i class="ti ti-repeat" style="line-height: 1;"></i></div>
|
||||||
|
@ -23,8 +23,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
[$style.t_mention]: notification.type === 'mention',
|
[$style.t_mention]: notification.type === 'mention',
|
||||||
[$style.t_quote]: notification.type === 'quote',
|
[$style.t_quote]: notification.type === 'quote',
|
||||||
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
[$style.t_pollEnded]: notification.type === 'pollEnded',
|
||||||
[$style.t_scheduledNotePosted]: notification.type === 'scheduledNotePosted',
|
|
||||||
[$style.t_scheduledNotePostFailed]: notification.type === 'scheduledNotePostFailed',
|
|
||||||
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
[$style.t_achievementEarned]: notification.type === 'achievementEarned',
|
||||||
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
[$style.t_exportCompleted]: notification.type === 'exportCompleted',
|
||||||
[$style.t_login]: notification.type === 'login',
|
[$style.t_login]: notification.type === 'login',
|
||||||
|
@ -41,8 +39,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
|
<i v-else-if="notification.type === 'mention'" class="ti ti-at"></i>
|
||||||
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
<i v-else-if="notification.type === 'quote'" class="ti ti-quote"></i>
|
||||||
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
<i v-else-if="notification.type === 'pollEnded'" class="ti ti-chart-arrows"></i>
|
||||||
<i v-else-if="notification.type === 'scheduledNotePosted'" class="ti ti-send"></i>
|
|
||||||
<i v-else-if="notification.type === 'scheduledNotePostFailed'" class="ti ti-alert-triangle"></i>
|
|
||||||
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
<i v-else-if="notification.type === 'achievementEarned'" class="ti ti-medal"></i>
|
||||||
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
<i v-else-if="notification.type === 'exportCompleted'" class="ti ti-archive"></i>
|
||||||
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
<i v-else-if="notification.type === 'login'" class="ti ti-login-2"></i>
|
||||||
|
@ -64,8 +60,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.tail">
|
<div :class="$style.tail">
|
||||||
<header :class="$style.header">
|
<header :class="$style.header">
|
||||||
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
|
<span v-if="notification.type === 'pollEnded'">{{ i18n.ts._notification.pollEnded }}</span>
|
||||||
<span v-else-if="notification.type === 'scheduledNotePosted'">{{ i18n.ts._notification.scheduledNotePosted }}</span>
|
|
||||||
<span v-else-if="notification.type === 'scheduledNotePostFailed'">{{ i18n.ts._notification.scheduledNotePostFailed }}</span>
|
|
||||||
<span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span>
|
<span v-else-if="notification.type === 'note'">{{ i18n.ts._notification.newNote }}: <MkUserName :user="notification.note.user"/></span>
|
||||||
<span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span>
|
<span v-else-if="notification.type === 'roleAssigned'">{{ i18n.ts._notification.roleAssigned }}</span>
|
||||||
<span v-else-if="notification.type === 'chatRoomInvitationReceived'">{{ i18n.ts._notification.chatRoomInvitationReceived }}</span>
|
<span v-else-if="notification.type === 'chatRoomInvitationReceived'">{{ i18n.ts._notification.chatRoomInvitationReceived }}</span>
|
||||||
|
@ -109,11 +103,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
||||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkA v-else-if="notification.type === 'scheduledNotePosted'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
|
||||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
|
||||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
|
||||||
</MkA>
|
|
||||||
<div v-else-if="notification.type === 'roleAssigned'" :class="$style.text">
|
<div v-else-if="notification.type === 'roleAssigned'" :class="$style.text">
|
||||||
{{ notification.role.name }}
|
{{ notification.role.name }}
|
||||||
</div>
|
</div>
|
||||||
|
@ -349,16 +338,6 @@ function getActualReactedUsersCount(notification: Misskey.entities.Notification)
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.t_scheduledNotePosted {
|
|
||||||
background: var(--eventOther);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.t_scheduledNotePostFailed {
|
|
||||||
background: var(--eventOther);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.t_achievementEarned {
|
.t_achievementEarned {
|
||||||
background: var(--eventAchievement);
|
background: var(--eventAchievement);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
|
@ -15,9 +15,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div :class="$style.headerLeft">
|
<div :class="$style.headerLeft">
|
||||||
<button v-if="!fixed" :class="$style.cancel" class="_button" @click="cancel"><i class="ti ti-x"></i></button>
|
<button v-if="!fixed" :class="$style.cancel" class="_button" @click="cancel"><i class="ti ti-x"></i></button>
|
||||||
<button v-click-anime v-tooltip="i18n.ts.switchAccount" :class="$style.account" class="_button" @click="openAccountMenu">
|
<button v-click-anime v-tooltip="i18n.ts.switchAccount" :class="$style.account" class="_button" @click="openAccountMenu">
|
||||||
<img :class="$style.avatar" :src="(postAccount ?? $i).avatarUrl" style="border-radius: 100%;"/>
|
<MkAvatar :user="postAccount ?? $i" :class="$style.avatar"/>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="$i.policies.noteDraftLimit > 0" v-tooltip="(postAccount != null && postAccount.id !== $i.id) ? null : i18n.ts.draftsAndScheduledNotes" class="_button" :class="$style.draftButton" :disabled="postAccount != null && postAccount.id !== $i.id" @click="showDraftMenu"><i class="ti ti-list"></i></button>
|
<button v-if="$i.policies.noteDraftLimit > 0" v-tooltip="(postAccount != null && postAccount.id !== $i.id) ? null : i18n.ts.draft" class="_button" :class="$style.draftButton" :disabled="postAccount != null && postAccount.id !== $i.id" @click="showDraftMenu"><i class="ti ti-pencil-minus"></i></button>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.headerRight">
|
<div :class="$style.headerRight">
|
||||||
<template v-if="!(targetChannel != null && fixed)">
|
<template v-if="!(targetChannel != null && fixed)">
|
||||||
|
@ -43,7 +43,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<template v-if="posted"></template>
|
<template v-if="posted"></template>
|
||||||
<template v-else-if="posting"><MkEllipsis/></template>
|
<template v-else-if="posting"><MkEllipsis/></template>
|
||||||
<template v-else>{{ submitText }}</template>
|
<template v-else>{{ submitText }}</template>
|
||||||
<i style="margin-left: 6px;" :class="submitIcon"></i>
|
<i style="margin-left: 6px;" :class="posted ? 'ti ti-check' : replyTargetNote ? 'ti ti-arrow-back-up' : renoteTargetNote ? 'ti ti-quote' : 'ti ti-send'"></i>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,13 +61,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button class="_buttonPrimary" style="padding: 4px; border-radius: 8px;" @click="addVisibleUser"><i class="ti ti-plus ti-fw"></i></button>
|
<button class="_buttonPrimary" style="padding: 4px; border-radius: 8px;" @click="addVisibleUser"><i class="ti ti-plus ti-fw"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<MkInfo v-if="scheduledAt != null" :class="$style.scheduledAt">
|
|
||||||
<I18n :src="i18n.ts.scheduleToPostOnX" tag="span">
|
|
||||||
<template #x>
|
|
||||||
<MkTime :time="scheduledAt" :mode="'detail'" style="font-weight: bold;"/>
|
|
||||||
</template>
|
|
||||||
</I18n> - <button class="_textButton" @click="cancelSchedule()">{{ i18n.ts.cancel }}</button>
|
|
||||||
</MkInfo>
|
|
||||||
<MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
|
<MkInfo v-if="hasNotSpecifiedMentions" warn :class="$style.hasNotSpecifiedMentions">{{ i18n.ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ i18n.ts.add }}</button></MkInfo>
|
||||||
<div v-show="useCw" :class="$style.cwOuter">
|
<div v-show="useCw" :class="$style.cwOuter">
|
||||||
<input ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown" @keyup="onKeyup" @compositionend="onCompositionEnd">
|
<input ref="cwInputEl" v-model="cw" :class="$style.cw" :placeholder="i18n.ts.annotation" @keydown="onKeydown" @keyup="onKeyup" @compositionend="onCompositionEnd">
|
||||||
|
@ -112,7 +105,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed, useTemplateRef, onUnmounted } from 'vue';
|
import { inject, watch, nextTick, onMounted, defineAsyncComponent, provide, shallowRef, ref, computed, useTemplateRef } from 'vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import insertTextAtCursor from 'insert-text-at-cursor';
|
import insertTextAtCursor from 'insert-text-at-cursor';
|
||||||
|
@ -206,7 +199,6 @@ if (props.initialVisibleUsers) {
|
||||||
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
|
props.initialVisibleUsers.forEach(u => pushVisibleUser(u));
|
||||||
}
|
}
|
||||||
const reactionAcceptance = ref(store.s.reactionAcceptance);
|
const reactionAcceptance = ref(store.s.reactionAcceptance);
|
||||||
const scheduledAt = ref<number | null>(null);
|
|
||||||
const draghover = ref(false);
|
const draghover = ref(false);
|
||||||
const quoteId = ref<string | null>(null);
|
const quoteId = ref<string | null>(null);
|
||||||
const hasNotSpecifiedMentions = ref(false);
|
const hasNotSpecifiedMentions = ref(false);
|
||||||
|
@ -226,10 +218,6 @@ const uploader = useUploader({
|
||||||
multiple: true,
|
multiple: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
uploader.dispose();
|
|
||||||
});
|
|
||||||
|
|
||||||
uploader.events.on('itemUploaded', ctx => {
|
uploader.events.on('itemUploaded', ctx => {
|
||||||
files.value.push(ctx.item.uploaded!);
|
files.value.push(ctx.item.uploaded!);
|
||||||
uploader.removeItem(ctx.item);
|
uploader.removeItem(ctx.item);
|
||||||
|
@ -270,19 +258,13 @@ const placeholder = computed((): string => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const submitText = computed((): string => {
|
const submitText = computed((): string => {
|
||||||
return scheduledAt.value != null
|
return renoteTargetNote.value
|
||||||
? i18n.ts.schedule
|
|
||||||
: renoteTargetNote.value
|
|
||||||
? i18n.ts.quote
|
? i18n.ts.quote
|
||||||
: replyTargetNote.value
|
: replyTargetNote.value
|
||||||
? i18n.ts.reply
|
? i18n.ts.reply
|
||||||
: i18n.ts.note;
|
: i18n.ts.note;
|
||||||
});
|
});
|
||||||
|
|
||||||
const submitIcon = computed((): string => {
|
|
||||||
return posted.value ? 'ti ti-check' : scheduledAt.value != null ? 'ti ti-calendar-time' : replyTargetNote.value ? 'ti ti-arrow-back-up' : renoteTargetNote.value ? 'ti ti-quote' : 'ti ti-send';
|
|
||||||
});
|
|
||||||
|
|
||||||
const textLength = computed((): number => {
|
const textLength = computed((): number => {
|
||||||
return (text.value + imeText.value).length;
|
return (text.value + imeText.value).length;
|
||||||
});
|
});
|
||||||
|
@ -428,7 +410,6 @@ function watchForDraft() {
|
||||||
watch(localOnly, () => saveDraft());
|
watch(localOnly, () => saveDraft());
|
||||||
watch(quoteId, () => saveDraft());
|
watch(quoteId, () => saveDraft());
|
||||||
watch(reactionAcceptance, () => saveDraft());
|
watch(reactionAcceptance, () => saveDraft());
|
||||||
watch(scheduledAt, () => saveDraft());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkMissingMention() {
|
function checkMissingMention() {
|
||||||
|
@ -620,13 +601,7 @@ function showOtherSettings() {
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleReactionAcceptance();
|
toggleReactionAcceptance();
|
||||||
},
|
},
|
||||||
}, ...($i.policies.scheduledNoteLimit > 0 ? [{
|
}, { type: 'divider' }, {
|
||||||
icon: 'ti ti-calendar-time',
|
|
||||||
text: i18n.ts.schedulePost + '...',
|
|
||||||
action: () => {
|
|
||||||
schedule();
|
|
||||||
},
|
|
||||||
}] : []), { type: 'divider' }, {
|
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
icon: 'ti ti-eye',
|
icon: 'ti ti-eye',
|
||||||
text: i18n.ts.preview,
|
text: i18n.ts.preview,
|
||||||
|
@ -675,7 +650,6 @@ function clear() {
|
||||||
files.value = [];
|
files.value = [];
|
||||||
poll.value = null;
|
poll.value = null;
|
||||||
quoteId.value = null;
|
quoteId.value = null;
|
||||||
scheduledAt.value = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onKeydown(ev: KeyboardEvent) {
|
function onKeydown(ev: KeyboardEvent) {
|
||||||
|
@ -831,7 +805,6 @@ function saveDraft() {
|
||||||
...( visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
...( visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
||||||
quoteId: quoteId.value,
|
quoteId: quoteId.value,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
scheduledAt: scheduledAt.value,
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -846,9 +819,7 @@ function deleteDraft() {
|
||||||
miLocalStorage.setItem('drafts', JSON.stringify(draftData));
|
miLocalStorage.setItem('drafts', JSON.stringify(draftData));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveServerDraft(options: {
|
async function saveServerDraft(clearLocal = false) {
|
||||||
isActuallyScheduled?: boolean;
|
|
||||||
} = {}) {
|
|
||||||
return await os.apiWithDialog(serverDraftId.value == null ? 'notes/drafts/create' : 'notes/drafts/update', {
|
return await os.apiWithDialog(serverDraftId.value == null ? 'notes/drafts/create' : 'notes/drafts/update', {
|
||||||
...(serverDraftId.value == null ? {} : { draftId: serverDraftId.value }),
|
...(serverDraftId.value == null ? {} : { draftId: serverDraftId.value }),
|
||||||
text: text.value,
|
text: text.value,
|
||||||
|
@ -856,15 +827,19 @@ async function saveServerDraft(options: {
|
||||||
visibility: visibility.value,
|
visibility: visibility.value,
|
||||||
localOnly: localOnly.value,
|
localOnly: localOnly.value,
|
||||||
hashtag: hashtags.value,
|
hashtag: hashtags.value,
|
||||||
fileIds: files.value.map(f => f.id),
|
...(files.value.length > 0 ? { fileIds: files.value.map(f => f.id) } : {}),
|
||||||
poll: poll.value,
|
poll: poll.value,
|
||||||
visibleUserIds: visibleUsers.value.map(x => x.id),
|
...(visibleUsers.value.length > 0 ? { visibleUserIds: visibleUsers.value.map(x => x.id) } : {}),
|
||||||
renoteId: renoteTargetNote.value ? renoteTargetNote.value.id : quoteId.value ? quoteId.value : null,
|
renoteId: renoteTargetNote.value ? renoteTargetNote.value.id : quoteId.value ? quoteId.value : undefined,
|
||||||
replyId: replyTargetNote.value ? replyTargetNote.value.id : null,
|
replyId: replyTargetNote.value ? replyTargetNote.value.id : undefined,
|
||||||
channelId: targetChannel.value ? targetChannel.value.id : null,
|
channelId: targetChannel.value ? targetChannel.value.id : undefined,
|
||||||
reactionAcceptance: reactionAcceptance.value,
|
reactionAcceptance: reactionAcceptance.value,
|
||||||
scheduledAt: scheduledAt.value,
|
}).then(() => {
|
||||||
isActuallyScheduled: options.isActuallyScheduled ?? false,
|
if (clearLocal) {
|
||||||
|
clear();
|
||||||
|
deleteDraft();
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,21 +874,6 @@ async function post(ev?: MouseEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scheduledAt.value != null) {
|
|
||||||
if (uploader.items.value.some(x => x.uploaded == null)) {
|
|
||||||
await uploadFiles();
|
|
||||||
|
|
||||||
// アップロード失敗したものがあったら中止
|
|
||||||
if (uploader.items.value.some(x => x.uploaded == null)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await postAsScheduled();
|
|
||||||
clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (props.mock) return;
|
if (props.mock) return;
|
||||||
|
|
||||||
if (visibility.value === 'public' && (
|
if (visibility.value === 'public' && (
|
||||||
|
@ -1085,14 +1045,6 @@ async function post(ev?: MouseEvent) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postAsScheduled() {
|
|
||||||
if (props.mock) return;
|
|
||||||
|
|
||||||
await saveServerDraft({
|
|
||||||
isActuallyScheduled: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
emit('cancel');
|
emit('cancel');
|
||||||
}
|
}
|
||||||
|
@ -1187,10 +1139,8 @@ function showPerUploadItemMenuViaContextmenu(item: UploaderItem, ev: MouseEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
function showDraftMenu(ev: MouseEvent) {
|
function showDraftMenu(ev: MouseEvent) {
|
||||||
function showDraftsDialog(scheduled: boolean) {
|
function showDraftsDialog() {
|
||||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNoteDraftsDialog.vue')), {
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNoteDraftsDialog.vue')), {}, {
|
||||||
scheduled,
|
|
||||||
}, {
|
|
||||||
restore: async (draft: Misskey.entities.NoteDraft) => {
|
restore: async (draft: Misskey.entities.NoteDraft) => {
|
||||||
text.value = draft.text ?? '';
|
text.value = draft.text ?? '';
|
||||||
useCw.value = draft.cw != null;
|
useCw.value = draft.cw != null;
|
||||||
|
@ -1221,7 +1171,6 @@ function showDraftMenu(ev: MouseEvent) {
|
||||||
renoteTargetNote.value = draft.renote;
|
renoteTargetNote.value = draft.renote;
|
||||||
replyTargetNote.value = draft.reply;
|
replyTargetNote.value = draft.reply;
|
||||||
reactionAcceptance.value = draft.reactionAcceptance;
|
reactionAcceptance.value = draft.reactionAcceptance;
|
||||||
scheduledAt.value = draft.scheduledAt ?? null;
|
|
||||||
if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
|
if (draft.channel) targetChannel.value = draft.channel as unknown as Misskey.entities.Channel;
|
||||||
|
|
||||||
visibleUsers.value = [];
|
visibleUsers.value = [];
|
||||||
|
@ -1262,32 +1211,11 @@ function showDraftMenu(ev: MouseEvent) {
|
||||||
text: i18n.ts._drafts.listDrafts,
|
text: i18n.ts._drafts.listDrafts,
|
||||||
icon: 'ti ti-cloud-download',
|
icon: 'ti ti-cloud-download',
|
||||||
action: () => {
|
action: () => {
|
||||||
showDraftsDialog(false);
|
showDraftsDialog();
|
||||||
},
|
|
||||||
}, { type: 'divider' }, {
|
|
||||||
type: 'button',
|
|
||||||
text: i18n.ts._drafts.listScheduledNotes,
|
|
||||||
icon: 'ti ti-clock-down',
|
|
||||||
action: () => {
|
|
||||||
showDraftsDialog(true);
|
|
||||||
},
|
},
|
||||||
}], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
|
}], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function schedule() {
|
|
||||||
const { canceled, result } = await os.inputDatetime({
|
|
||||||
title: i18n.ts.schedulePost,
|
|
||||||
});
|
|
||||||
if (canceled) return;
|
|
||||||
if (result.getTime() <= Date.now()) return;
|
|
||||||
|
|
||||||
scheduledAt.value = result.getTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancelSchedule() {
|
|
||||||
scheduledAt.value = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.autofocus) {
|
if (props.autofocus) {
|
||||||
focus();
|
focus();
|
||||||
|
@ -1323,7 +1251,6 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
quoteId.value = draft.data.quoteId;
|
quoteId.value = draft.data.quoteId;
|
||||||
reactionAcceptance.value = draft.data.reactionAcceptance;
|
reactionAcceptance.value = draft.data.reactionAcceptance;
|
||||||
scheduledAt.value = draft.data.scheduledAt ?? null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1373,7 +1300,6 @@ async function canClose() {
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
clear,
|
clear,
|
||||||
abortUploader: () => uploader.abortAll(),
|
|
||||||
canClose,
|
canClose,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -1588,10 +1514,6 @@ html[data-color-scheme=light] .preview {
|
||||||
margin: 0 20px 16px 20px;
|
margin: 0 20px 16px 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scheduledAt {
|
|
||||||
margin: 0 20px 16px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cw,
|
.cw,
|
||||||
.hashtags,
|
.hashtags,
|
||||||
.text {
|
.text {
|
||||||
|
|
|
@ -54,7 +54,6 @@ function onPosted() {
|
||||||
async function _close() {
|
async function _close() {
|
||||||
const canClose = await form.value?.canClose();
|
const canClose = await form.value?.canClose();
|
||||||
if (!canClose) return;
|
if (!canClose) return;
|
||||||
form.value?.abortUploader();
|
|
||||||
modal.value?.close();
|
modal.value?.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
v-panel
|
v-panel
|
||||||
:class="[$style.item, { [$style.itemWaiting]: item.preprocessing, [$style.itemCompleted]: item.uploaded, [$style.itemFailed]: item.uploadFailed }]"
|
:class="[$style.item, { [$style.itemWaiting]: item.preprocessing, [$style.itemCompleted]: item.uploaded, [$style.itemFailed]: item.uploadFailed }]"
|
||||||
:style="{
|
:style="{ '--p': item.progress != null ? `${item.progress.value / item.progress.max * 100}%` : '0%' }"
|
||||||
'--p': item.progress != null ? `${item.progress.value / item.progress.max * 100}%` : '0%',
|
|
||||||
'--pp': item.preprocessProgress != null ? `${item.preprocessProgress * 100}%` : '100%',
|
|
||||||
}"
|
|
||||||
@contextmenu.prevent.stop="onContextmenu(item, $event)"
|
@contextmenu.prevent.stop="onContextmenu(item, $event)"
|
||||||
>
|
>
|
||||||
<div :class="$style.itemInner">
|
<div :class="$style.itemInner">
|
||||||
|
@ -22,15 +19,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.itemThumbnail" :style="{ backgroundImage: `url(${ item.thumbnail })` }" @click="onThumbnailClick(item, $event)"></div>
|
<div :class="$style.itemThumbnail" :style="{ backgroundImage: `url(${ item.thumbnail })` }" @click="onThumbnailClick(item, $event)"></div>
|
||||||
<div :class="$style.itemBody">
|
<div :class="$style.itemBody">
|
||||||
<div>
|
<div><i v-if="item.isSensitive" style="color: var(--MI_THEME-warn); margin-right: 0.5em;" class="ti ti-eye-exclamation"></i><MkCondensedLine :minScale="2 / 3">{{ item.name }}</MkCondensedLine></div>
|
||||||
<i v-if="item.isSensitive" style="color: var(--MI_THEME-warn); margin-right: 0.5em;" class="ti ti-eye-exclamation"></i>
|
|
||||||
<MkCondensedLine :minScale="2 / 3">{{ item.name }}</MkCondensedLine>
|
|
||||||
</div>
|
|
||||||
<div :class="$style.itemInfo">
|
<div :class="$style.itemInfo">
|
||||||
<span>{{ item.file.type }}</span>
|
<span>{{ item.file.type }}</span>
|
||||||
<span v-if="item.compressedSize">({{ i18n.tsx._uploader.compressedToX({ x: bytes(item.compressedSize) }) }} = {{ i18n.tsx._uploader.savedXPercent({ x: Math.round((1 - item.compressedSize / item.file.size) * 100) }) }})</span>
|
<span v-if="item.compressedSize">({{ i18n.tsx._uploader.compressedToX({ x: bytes(item.compressedSize) }) }} = {{ i18n.tsx._uploader.savedXPercent({ x: Math.round((1 - item.compressedSize / item.file.size) * 100) }) }})</span>
|
||||||
<span v-else>{{ bytes(item.file.size) }}</span>
|
<span v-else>{{ bytes(item.file.size) }}</span>
|
||||||
<span v-if="item.preprocessing">{{ i18n.ts.preprocessing }}<MkLoading inline em style="margin-left: 0.5em;"/></span>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -104,7 +97,7 @@ function onThumbnailClick(item: UploaderItem, ev: MouseEvent) {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: var(--pp, 100%);
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: linear-gradient(-45deg, transparent 25%, var(--c) 25%,var(--c) 50%, transparent 50%, transparent 75%, var(--c) 75%, var(--c));
|
background: linear-gradient(-45deg, transparent 25%, var(--c) 25%,var(--c) 50%, transparent 50%, transparent 75%, var(--c) 75%, var(--c));
|
||||||
background-size: 25px 25px;
|
background-size: 25px 25px;
|
||||||
|
|
|
@ -43,12 +43,6 @@ const IMAGE_EDITING_SUPPORTED_TYPES = [
|
||||||
'image/webp',
|
'image/webp',
|
||||||
];
|
];
|
||||||
|
|
||||||
const VIDEO_COMPRESSION_SUPPORTED_TYPES = [ // TODO
|
|
||||||
'video/mp4',
|
|
||||||
'video/quicktime',
|
|
||||||
'video/x-matroska',
|
|
||||||
];
|
|
||||||
|
|
||||||
const WATERMARK_SUPPORTED_TYPES = IMAGE_EDITING_SUPPORTED_TYPES;
|
const WATERMARK_SUPPORTED_TYPES = IMAGE_EDITING_SUPPORTED_TYPES;
|
||||||
|
|
||||||
const IMAGE_PREPROCESS_NEEDED_TYPES = [
|
const IMAGE_PREPROCESS_NEEDED_TYPES = [
|
||||||
|
@ -57,10 +51,6 @@ const IMAGE_PREPROCESS_NEEDED_TYPES = [
|
||||||
...IMAGE_EDITING_SUPPORTED_TYPES,
|
...IMAGE_EDITING_SUPPORTED_TYPES,
|
||||||
];
|
];
|
||||||
|
|
||||||
const VIDEO_PREPROCESS_NEEDED_TYPES = [
|
|
||||||
...VIDEO_COMPRESSION_SUPPORTED_TYPES,
|
|
||||||
];
|
|
||||||
|
|
||||||
const mimeTypeMap = {
|
const mimeTypeMap = {
|
||||||
'image/webp': 'webp',
|
'image/webp': 'webp',
|
||||||
'image/jpeg': 'jpg',
|
'image/jpeg': 'jpg',
|
||||||
|
@ -74,7 +64,6 @@ export type UploaderItem = {
|
||||||
progress: { max: number; value: number } | null;
|
progress: { max: number; value: number } | null;
|
||||||
thumbnail: string | null;
|
thumbnail: string | null;
|
||||||
preprocessing: boolean;
|
preprocessing: boolean;
|
||||||
preprocessProgress: number | null;
|
|
||||||
uploading: boolean;
|
uploading: boolean;
|
||||||
uploaded: Misskey.entities.DriveFile | null;
|
uploaded: Misskey.entities.DriveFile | null;
|
||||||
uploadFailed: boolean;
|
uploadFailed: boolean;
|
||||||
|
@ -87,7 +76,6 @@ export type UploaderItem = {
|
||||||
isSensitive?: boolean;
|
isSensitive?: boolean;
|
||||||
caption?: string | null;
|
caption?: string | null;
|
||||||
abort?: (() => void) | null;
|
abort?: (() => void) | null;
|
||||||
abortPreprocess?: (() => void) | null;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function getCompressionSettings(level: 0 | 1 | 2 | 3) {
|
function getCompressionSettings(level: 0 | 1 | 2 | 3) {
|
||||||
|
@ -141,12 +129,11 @@ export function useUploader(options: {
|
||||||
progress: null,
|
progress: null,
|
||||||
thumbnail: THUMBNAIL_SUPPORTED_TYPES.includes(file.type) ? window.URL.createObjectURL(file) : null,
|
thumbnail: THUMBNAIL_SUPPORTED_TYPES.includes(file.type) ? window.URL.createObjectURL(file) : null,
|
||||||
preprocessing: false,
|
preprocessing: false,
|
||||||
preprocessProgress: null,
|
|
||||||
uploading: false,
|
uploading: false,
|
||||||
aborted: false,
|
aborted: false,
|
||||||
uploaded: null,
|
uploaded: null,
|
||||||
uploadFailed: false,
|
uploadFailed: false,
|
||||||
compressionLevel: IMAGE_COMPRESSION_SUPPORTED_TYPES.includes(file.type) ? prefer.s.defaultImageCompressionLevel : VIDEO_COMPRESSION_SUPPORTED_TYPES.includes(file.type) ? prefer.s.defaultVideoCompressionLevel : 0,
|
compressionLevel: prefer.s.defaultImageCompressionLevel,
|
||||||
watermarkPresetId: uploaderFeatures.value.watermark && $i.policies.watermarkAvailable ? prefer.s.defaultWatermarkPresetId : null,
|
watermarkPresetId: uploaderFeatures.value.watermark && $i.policies.watermarkAvailable ? prefer.s.defaultWatermarkPresetId : null,
|
||||||
file: markRaw(file),
|
file: markRaw(file),
|
||||||
});
|
});
|
||||||
|
@ -331,7 +318,7 @@ export function useUploader(options: {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(IMAGE_COMPRESSION_SUPPORTED_TYPES.includes(item.file.type) || VIDEO_COMPRESSION_SUPPORTED_TYPES.includes(item.file.type)) &&
|
IMAGE_COMPRESSION_SUPPORTED_TYPES.includes(item.file.type) &&
|
||||||
!item.preprocessing &&
|
!item.preprocessing &&
|
||||||
!item.uploading &&
|
!item.uploading &&
|
||||||
!item.uploaded
|
!item.uploaded
|
||||||
|
@ -404,19 +391,6 @@ export function useUploader(options: {
|
||||||
removeItem(item);
|
removeItem(item);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
} else if (item.preprocessing && item.abortPreprocess != null) {
|
|
||||||
menu.push({
|
|
||||||
type: 'divider',
|
|
||||||
}, {
|
|
||||||
icon: 'ti ti-player-stop',
|
|
||||||
text: i18n.ts.abort,
|
|
||||||
danger: true,
|
|
||||||
action: () => {
|
|
||||||
if (item.abortPreprocess != null) {
|
|
||||||
item.abortPreprocess();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} else if (item.uploading) {
|
} else if (item.uploading) {
|
||||||
menu.push({
|
menu.push({
|
||||||
type: 'divider',
|
type: 'divider',
|
||||||
|
@ -500,10 +474,6 @@ export function useUploader(options: {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.abortPreprocess != null) {
|
|
||||||
item.abortPreprocess();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.abort != null) {
|
if (item.abort != null) {
|
||||||
item.abort();
|
item.abort();
|
||||||
}
|
}
|
||||||
|
@ -514,30 +484,18 @@ export function useUploader(options: {
|
||||||
|
|
||||||
async function preprocess(item: UploaderItem): Promise<void> {
|
async function preprocess(item: UploaderItem): Promise<void> {
|
||||||
item.preprocessing = true;
|
item.preprocessing = true;
|
||||||
item.preprocessProgress = null;
|
|
||||||
|
|
||||||
if (IMAGE_PREPROCESS_NEEDED_TYPES.includes(item.file.type)) {
|
|
||||||
try {
|
try {
|
||||||
|
if (IMAGE_PREPROCESS_NEEDED_TYPES.includes(item.file.type)) {
|
||||||
await preprocessForImage(item);
|
await preprocessForImage(item);
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to preprocess image', err);
|
console.error('Failed to preprocess image', err);
|
||||||
|
|
||||||
// nop
|
// nop
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (VIDEO_PREPROCESS_NEEDED_TYPES.includes(item.file.type)) {
|
|
||||||
try {
|
|
||||||
await preprocessForVideo(item);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('Failed to preprocess video', err);
|
|
||||||
|
|
||||||
// nop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item.preprocessing = false;
|
item.preprocessing = false;
|
||||||
item.preprocessProgress = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function preprocessForImage(item: UploaderItem): Promise<void> {
|
async function preprocessForImage(item: UploaderItem): Promise<void> {
|
||||||
|
@ -606,74 +564,10 @@ export function useUploader(options: {
|
||||||
item.preprocessedFile = markRaw(preprocessedFile);
|
item.preprocessedFile = markRaw(preprocessedFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function preprocessForVideo(item: UploaderItem): Promise<void> {
|
onUnmounted(() => {
|
||||||
let preprocessedFile: Blob | File = item.file;
|
|
||||||
|
|
||||||
const needsCompress = item.compressionLevel !== 0 && VIDEO_COMPRESSION_SUPPORTED_TYPES.includes(preprocessedFile.type);
|
|
||||||
|
|
||||||
if (needsCompress) {
|
|
||||||
const mediabunny = await import('mediabunny');
|
|
||||||
|
|
||||||
const source = new mediabunny.BlobSource(preprocessedFile);
|
|
||||||
|
|
||||||
const input = new mediabunny.Input({
|
|
||||||
source,
|
|
||||||
formats: mediabunny.ALL_FORMATS,
|
|
||||||
});
|
|
||||||
|
|
||||||
const output = new mediabunny.Output({
|
|
||||||
target: new mediabunny.BufferTarget(),
|
|
||||||
format: new mediabunny.Mp4OutputFormat(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentConversion = await mediabunny.Conversion.init({
|
|
||||||
input,
|
|
||||||
output,
|
|
||||||
video: {
|
|
||||||
//width: 320, // Height will be deduced automatically to retain aspect ratio
|
|
||||||
bitrate: item.compressionLevel === 1 ? mediabunny.QUALITY_VERY_HIGH : item.compressionLevel === 2 ? mediabunny.QUALITY_MEDIUM : mediabunny.QUALITY_VERY_LOW,
|
|
||||||
},
|
|
||||||
audio: {
|
|
||||||
bitrate: item.compressionLevel === 1 ? mediabunny.QUALITY_VERY_HIGH : item.compressionLevel === 2 ? mediabunny.QUALITY_MEDIUM : mediabunny.QUALITY_VERY_LOW,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
currentConversion.onProgress = newProgress => item.preprocessProgress = newProgress;
|
|
||||||
|
|
||||||
item.abortPreprocess = () => {
|
|
||||||
item.abortPreprocess = null;
|
|
||||||
currentConversion.cancel();
|
|
||||||
item.preprocessing = false;
|
|
||||||
item.preprocessProgress = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
await currentConversion.execute();
|
|
||||||
|
|
||||||
item.abortPreprocess = null;
|
|
||||||
|
|
||||||
preprocessedFile = new Blob([output.target.buffer!], { type: output.format.mimeType });
|
|
||||||
item.compressedSize = output.target.buffer!.byteLength;
|
|
||||||
item.uploadName = `${item.name}.mp4`;
|
|
||||||
} else {
|
|
||||||
item.compressedSize = null;
|
|
||||||
item.uploadName = item.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.thumbnail != null) URL.revokeObjectURL(item.thumbnail);
|
|
||||||
item.thumbnail = THUMBNAIL_SUPPORTED_TYPES.includes(preprocessedFile.type) ? window.URL.createObjectURL(preprocessedFile) : null;
|
|
||||||
item.preprocessedFile = markRaw(preprocessedFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
function dispose() {
|
|
||||||
for (const item of items.value) {
|
for (const item of items.value) {
|
||||||
if (item.thumbnail != null) URL.revokeObjectURL(item.thumbnail);
|
if (item.thumbnail != null) URL.revokeObjectURL(item.thumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
abortAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
|
||||||
dispose();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -681,7 +575,6 @@ export function useUploader(options: {
|
||||||
addFiles,
|
addFiles,
|
||||||
removeItem,
|
removeItem,
|
||||||
abortAll,
|
abortAll,
|
||||||
dispose,
|
|
||||||
upload,
|
upload,
|
||||||
getMenu,
|
getMenu,
|
||||||
uploading: computed(() => items.value.some(item => item.uploading)),
|
uploading: computed(() => items.value.some(item => item.uploading)),
|
||||||
|
|
|
@ -23,15 +23,6 @@ export function setDragData<T extends keyof DragDataMap>(
|
||||||
event.dataTransfer.setData(`misskey/${type}`.toLowerCase(), JSON.stringify(data));
|
event.dataTransfer.setData(`misskey/${type}`.toLowerCase(), JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPlainDragData(
|
|
||||||
event: DragEvent,
|
|
||||||
data: string,
|
|
||||||
) {
|
|
||||||
if (event.dataTransfer == null) return;
|
|
||||||
|
|
||||||
event.dataTransfer.setData('text/plain', data);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getDragData<T extends keyof DragDataMap>(
|
export function getDragData<T extends keyof DragDataMap>(
|
||||||
event: DragEvent,
|
event: DragEvent,
|
||||||
type: T,
|
type: T,
|
||||||
|
@ -44,17 +35,6 @@ export function getDragData<T extends keyof DragDataMap>(
|
||||||
return JSON.parse(data);
|
return JSON.parse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPlainDragData(
|
|
||||||
event: DragEvent,
|
|
||||||
): string | null {
|
|
||||||
if (event.dataTransfer == null) return null;
|
|
||||||
|
|
||||||
const data = event.dataTransfer.getData('text/plain');
|
|
||||||
if (data == null || data === '') return null;
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkDragDataType(
|
export function checkDragDataType(
|
||||||
event: DragEvent,
|
event: DragEvent,
|
||||||
types: (keyof DragDataMap)[],
|
types: (keyof DragDataMap)[],
|
||||||
|
|
|
@ -76,7 +76,7 @@ export const apiWithDialog = (<E extends keyof Misskey.Endpoints>(
|
||||||
} else if (err.code === 'ROLE_PERMISSION_DENIED') {
|
} else if (err.code === 'ROLE_PERMISSION_DENIED') {
|
||||||
title = i18n.ts.permissionDeniedError;
|
title = i18n.ts.permissionDeniedError;
|
||||||
text = i18n.ts.permissionDeniedErrorDescription;
|
text = i18n.ts.permissionDeniedErrorDescription;
|
||||||
} else if (err.code.startsWith('TOO_MANY')) { // TODO: バックエンドに kind: client/contentsLimitExceeded みたいな感じで送るように統一してもらってそれで判定する
|
} else if (err.code.startsWith('TOO_MANY')) {
|
||||||
title = i18n.ts.youCannotCreateAnymore;
|
title = i18n.ts.youCannotCreateAnymore;
|
||||||
text = `${i18n.ts.error}: ${err.id}`;
|
text = `${i18n.ts.error}: ${err.id}`;
|
||||||
} else if (err.message.startsWith('Unexpected token')) {
|
} else if (err.message.startsWith('Unexpected token')) {
|
||||||
|
@ -460,7 +460,7 @@ export function inputNumber(props: {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function inputDatetime(props: {
|
export function inputDate(props: {
|
||||||
title?: string;
|
title?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
placeholder?: string | null;
|
placeholder?: string | null;
|
||||||
|
@ -475,13 +475,13 @@ export function inputDatetime(props: {
|
||||||
title: props.title,
|
title: props.title,
|
||||||
text: props.text,
|
text: props.text,
|
||||||
input: {
|
input: {
|
||||||
type: 'datetime-local',
|
type: 'date',
|
||||||
placeholder: props.placeholder,
|
placeholder: props.placeholder,
|
||||||
default: props.default ?? null,
|
default: props.default ?? null,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
done: result => {
|
done: result => {
|
||||||
resolve(result != null && result.result != null ? { result: new Date(result.result), canceled: false } : { result: undefined, canceled: true });
|
resolve(result ? { result: new Date(result.result), canceled: false } : { result: undefined, canceled: true });
|
||||||
},
|
},
|
||||||
closed: () => dispose(),
|
closed: () => dispose(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -802,25 +802,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.scheduledNoteLimit, 'scheduledNoteLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.scheduledNoteLimit }}</template>
|
|
||||||
<template #suffix>
|
|
||||||
<span v-if="role.policies.scheduledNoteLimit.useDefault" :class="$style.useDefaultLabel">{{ i18n.ts._role.useBaseValue }}</span>
|
|
||||||
<span v-else>{{ role.policies.scheduledNoteLimit.value }}</span>
|
|
||||||
<span :class="$style.priorityIndicator"><i :class="getPriorityIcon(role.policies.scheduledNoteLimit)"></i></span>
|
|
||||||
</template>
|
|
||||||
<div class="_gaps">
|
|
||||||
<MkSwitch v-model="role.policies.scheduledNoteLimit.useDefault" :readonly="readonly">
|
|
||||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
|
||||||
</MkSwitch>
|
|
||||||
<MkInput v-model="role.policies.scheduledNoteLimit.value" :disabled="role.policies.scheduledNoteLimit.useDefault" type="number" :readonly="readonly">
|
|
||||||
</MkInput>
|
|
||||||
<MkRange v-model="role.policies.scheduledNoteLimit.priority" :min="0" :max="2" :step="1" easing :textConverter="(v) => v === 0 ? i18n.ts._role._priority.low : v === 1 ? i18n.ts._role._priority.middle : v === 2 ? i18n.ts._role._priority.high : ''">
|
|
||||||
<template #label>{{ i18n.ts._role.priority }}</template>
|
|
||||||
</MkRange>
|
|
||||||
</div>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.watermarkAvailable, 'watermarkAvailable'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.watermarkAvailable, 'watermarkAvailable'])">
|
||||||
<template #label>{{ i18n.ts._role._options.watermarkAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.watermarkAvailable }}</template>
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
|
@ -850,7 +831,6 @@ import { watch, ref, computed } from 'vue';
|
||||||
import { throttle } from 'throttle-debounce';
|
import { throttle } from 'throttle-debounce';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import RolesEditorFormula from './RolesEditorFormula.vue';
|
import RolesEditorFormula from './RolesEditorFormula.vue';
|
||||||
import type { MkSelectItem, GetMkSelectValueTypesFromDef } from '@/components/MkSelect.vue';
|
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkColorInput from '@/components/MkColorInput.vue';
|
import MkColorInput from '@/components/MkColorInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
@ -862,6 +842,7 @@ import FormSlot from '@/components/form/slot.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { deepClone } from '@/utility/clone.js';
|
import { deepClone } from '@/utility/clone.js';
|
||||||
|
import type { MkSelectItem, GetMkSelectValueTypesFromDef } from '@/components/MkSelect.vue';
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(ev: 'update:modelValue', v: any): void;
|
(ev: 'update:modelValue', v: any): void;
|
||||||
|
|
|
@ -304,13 +304,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.scheduledNoteLimit, 'scheduledNoteLimit'])">
|
|
||||||
<template #label>{{ i18n.ts._role._options.scheduledNoteLimit }}</template>
|
|
||||||
<template #suffix>{{ policies.scheduledNoteLimit }}</template>
|
|
||||||
<MkInput v-model="policies.scheduledNoteLimit" type="number" :min="0">
|
|
||||||
</MkInput>
|
|
||||||
</MkFolder>
|
|
||||||
|
|
||||||
<MkFolder v-if="matchQuery([i18n.ts._role._options.watermarkAvailable, 'watermarkAvailable'])">
|
<MkFolder v-if="matchQuery([i18n.ts._role._options.watermarkAvailable, 'watermarkAvailable'])">
|
||||||
<template #label>{{ i18n.ts._role._options.watermarkAvailable }}</template>
|
<template #label>{{ i18n.ts._role._options.watermarkAvailable }}</template>
|
||||||
<template #suffix>{{ policies.watermarkAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
<template #suffix>{{ policies.watermarkAvailable ? i18n.ts.yes : i18n.ts.no }}</template>
|
||||||
|
|
|
@ -129,37 +129,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSelect
|
<MkSelect
|
||||||
v-model="defaultImageCompressionLevel" :items="[
|
v-model="defaultImageCompressionLevel" :items="[
|
||||||
{ label: i18n.ts.none, value: 0 },
|
{ label: i18n.ts.none, value: 0 },
|
||||||
{ label: `${i18n.ts.low} (${i18n.ts._compression._quality.high}; ${i18n.ts._compression._size.large})`, value: 1 },
|
{ label: i18n.ts.low, value: 1 },
|
||||||
{ label: `${i18n.ts.medium} (${i18n.ts._compression._quality.medium}; ${i18n.ts._compression._size.medium})`, value: 2 },
|
{ label: i18n.ts.medium, value: 2 },
|
||||||
{ label: `${i18n.ts.high} (${i18n.ts._compression._quality.low}; ${i18n.ts._compression._size.small})`, value: 3 },
|
{ label: i18n.ts.high, value: 3 },
|
||||||
]"
|
]"
|
||||||
>
|
>
|
||||||
<template #label><SearchLabel>{{ i18n.ts.defaultCompressionLevel }}</SearchLabel></template>
|
<template #label><SearchLabel>{{ i18n.ts.defaultImageCompressionLevel }}</SearchLabel></template>
|
||||||
<template #caption><div v-html="i18n.ts.defaultCompressionLevel_description"></div></template>
|
<template #caption><div v-html="i18n.ts.defaultImageCompressionLevel_description"></div></template>
|
||||||
</MkSelect>
|
|
||||||
</MkPreferenceContainer>
|
|
||||||
</SearchMarker>
|
|
||||||
</div>
|
|
||||||
</FormSection>
|
|
||||||
</SearchMarker>
|
|
||||||
|
|
||||||
<SearchMarker :keywords="['video']">
|
|
||||||
<FormSection>
|
|
||||||
<template #label><SearchLabel>{{ i18n.ts.video }}</SearchLabel></template>
|
|
||||||
|
|
||||||
<div class="_gaps_m">
|
|
||||||
<SearchMarker :keywords="['default', 'video', 'compression']">
|
|
||||||
<MkPreferenceContainer k="defaultVideoCompressionLevel">
|
|
||||||
<MkSelect
|
|
||||||
v-model="defaultVideoCompressionLevel" :items="[
|
|
||||||
{ label: i18n.ts.none, value: 0 },
|
|
||||||
{ label: `${i18n.ts.low} (${i18n.ts._compression._quality.high}; ${i18n.ts._compression._size.large})`, value: 1 },
|
|
||||||
{ label: `${i18n.ts.medium} (${i18n.ts._compression._quality.medium}; ${i18n.ts._compression._size.medium})`, value: 2 },
|
|
||||||
{ label: `${i18n.ts.high} (${i18n.ts._compression._quality.low}; ${i18n.ts._compression._size.small})`, value: 3 },
|
|
||||||
]"
|
|
||||||
>
|
|
||||||
<template #label><SearchLabel>{{ i18n.ts.defaultCompressionLevel }}</SearchLabel></template>
|
|
||||||
<template #caption><div v-html="i18n.ts.defaultCompressionLevel_description"></div></template>
|
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
</MkPreferenceContainer>
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
@ -220,7 +196,6 @@ const meterStyle = computed(() => {
|
||||||
const keepOriginalFilename = prefer.model('keepOriginalFilename');
|
const keepOriginalFilename = prefer.model('keepOriginalFilename');
|
||||||
const defaultWatermarkPresetId = prefer.model('defaultWatermarkPresetId');
|
const defaultWatermarkPresetId = prefer.model('defaultWatermarkPresetId');
|
||||||
const defaultImageCompressionLevel = prefer.model('defaultImageCompressionLevel');
|
const defaultImageCompressionLevel = prefer.model('defaultImageCompressionLevel');
|
||||||
const defaultVideoCompressionLevel = prefer.model('defaultVideoCompressionLevel');
|
|
||||||
|
|
||||||
const watermarkPresetsSyncEnabled = ref(prefer.isSyncEnabled('watermarkPresets'));
|
const watermarkPresetsSyncEnabled = ref(prefer.isSyncEnabled('watermarkPresets'));
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<option :value="1">{{ i18n.ts.small }}</option>
|
<option :value="1">{{ i18n.ts.small }}</option>
|
||||||
<option :value="2">{{ i18n.ts.medium }}</option>
|
<option :value="2">{{ i18n.ts.medium }}</option>
|
||||||
<option :value="3">{{ i18n.ts.large }}</option>
|
<option :value="3">{{ i18n.ts.large }}</option>
|
||||||
<option :value="4">{{ i18n.ts.large }}+</option>
|
|
||||||
<option :value="5">{{ i18n.ts.large }}++</option>
|
|
||||||
</MkRadios>
|
</MkRadios>
|
||||||
</MkPreferenceContainer>
|
</MkPreferenceContainer>
|
||||||
</SearchMarker>
|
</SearchMarker>
|
||||||
|
@ -97,13 +95,11 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<SearchMarker :keywords="['emoji', 'picker', 'style']">
|
<SearchMarker :keywords="['emoji', 'picker', 'style']">
|
||||||
<MkPreferenceContainer k="emojiPickerStyle">
|
<MkPreferenceContainer k="emojiPickerStyle">
|
||||||
<MkSelect
|
<MkSelect v-model="emojiPickerStyle" :items="[
|
||||||
v-model="emojiPickerStyle" :items="[
|
|
||||||
{ label: i18n.ts.auto, value: 'auto' },
|
{ label: i18n.ts.auto, value: 'auto' },
|
||||||
{ label: i18n.ts.popup, value: 'popup' },
|
{ label: i18n.ts.popup, value: 'popup' },
|
||||||
{ label: i18n.ts.drawer, value: 'drawer' },
|
{ label: i18n.ts.drawer, value: 'drawer' },
|
||||||
]"
|
]">
|
||||||
>
|
|
||||||
<template #label><SearchLabel>{{ i18n.ts.style }}</SearchLabel></template>
|
<template #label><SearchLabel>{{ i18n.ts.style }}</SearchLabel></template>
|
||||||
<template #caption>{{ i18n.ts.needReloadToApply }}</template>
|
<template #caption>{{ i18n.ts.needReloadToApply }}</template>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
|
@ -120,13 +116,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, watch } from 'vue';
|
import { computed, ref, watch } from 'vue';
|
||||||
import XPalette from './emoji-palette.palette.vue';
|
|
||||||
import type { MkSelectItem } from '@/components/MkSelect.vue';
|
|
||||||
import { genId } from '@/utility/id.js';
|
import { genId } from '@/utility/id.js';
|
||||||
|
import XPalette from './emoji-palette.palette.vue';
|
||||||
import MkRadios from '@/components/MkRadios.vue';
|
import MkRadios from '@/components/MkRadios.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
|
import type { MkSelectItem } from '@/components/MkSelect.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
|
|
|
@ -5,11 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SearchMarker path="/settings/theme" :label="i18n.ts.theme" :keywords="['theme']" icon="ti ti-palette">
|
<SearchMarker path="/settings/theme" :label="i18n.ts.theme" :keywords="['theme']" icon="ti ti-palette">
|
||||||
<div
|
<div class="_gaps_m">
|
||||||
class="_gaps_m"
|
|
||||||
@dragover.prevent.stop="onDragover"
|
|
||||||
@drop.prevent.stop="onDrop"
|
|
||||||
>
|
|
||||||
<div v-adaptive-border class="rfqxtzch _panel">
|
<div v-adaptive-border class="rfqxtzch _panel">
|
||||||
<div class="toggle">
|
<div class="toggle">
|
||||||
<div class="toggleWrapper">
|
<div class="toggleWrapper">
|
||||||
|
@ -62,7 +58,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="$style.themeRadio"
|
:class="$style.themeRadio"
|
||||||
:value="instanceLightTheme.id"
|
:value="instanceLightTheme.id"
|
||||||
/>
|
/>
|
||||||
<label :for="`themeRadio_${instanceLightTheme.id}`" :class="$style.themeItemRoot" class="_button" draggable="true" @dragstart="onThemeDragstart($event, instanceLightTheme)" @contextmenu.prevent.stop="onThemeContextmenu(instanceLightTheme, $event)">
|
<label :for="`themeRadio_${instanceLightTheme.id}`" :class="$style.themeItemRoot" class="_button" @contextmenu.prevent.stop="onThemeContextmenu(instanceLightTheme, $event)">
|
||||||
<MkThemePreview :theme="instanceLightTheme" :class="$style.themeItemPreview"/>
|
<MkThemePreview :theme="instanceLightTheme" :class="$style.themeItemPreview"/>
|
||||||
<div :class="$style.themeItemCaption">{{ instanceLightTheme.name }}</div>
|
<div :class="$style.themeItemCaption">{{ instanceLightTheme.name }}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -82,7 +78,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="$style.themeRadio"
|
:class="$style.themeRadio"
|
||||||
:value="theme.id"
|
:value="theme.id"
|
||||||
/>
|
/>
|
||||||
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" draggable="true" @dragstart="onThemeDragstart($event, theme)" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
||||||
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
||||||
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -102,7 +98,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="$style.themeRadio"
|
:class="$style.themeRadio"
|
||||||
:value="theme.id"
|
:value="theme.id"
|
||||||
/>
|
/>
|
||||||
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" draggable="true" @dragstart="onThemeDragstart($event, theme)" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
||||||
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
||||||
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -133,7 +129,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="$style.themeRadio"
|
:class="$style.themeRadio"
|
||||||
:value="instanceDarkTheme.id"
|
:value="instanceDarkTheme.id"
|
||||||
/>
|
/>
|
||||||
<label :for="`themeRadio_${instanceDarkTheme.id}`" :class="$style.themeItemRoot" class="_button" draggable="true" @dragstart="onThemeDragstart($event, instanceDarkTheme)" @contextmenu.prevent.stop="onThemeContextmenu(instanceDarkTheme, $event)">
|
<label :for="`themeRadio_${instanceDarkTheme.id}`" :class="$style.themeItemRoot" class="_button" @contextmenu.prevent.stop="onThemeContextmenu(instanceDarkTheme, $event)">
|
||||||
<MkThemePreview :theme="instanceDarkTheme" :class="$style.themeItemPreview"/>
|
<MkThemePreview :theme="instanceDarkTheme" :class="$style.themeItemPreview"/>
|
||||||
<div :class="$style.themeItemCaption">{{ instanceDarkTheme.name }}</div>
|
<div :class="$style.themeItemCaption">{{ instanceDarkTheme.name }}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -153,7 +149,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="$style.themeRadio"
|
:class="$style.themeRadio"
|
||||||
:value="theme.id"
|
:value="theme.id"
|
||||||
/>
|
/>
|
||||||
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" draggable="true" @dragstart="onThemeDragstart($event, theme)" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
||||||
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
||||||
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -173,7 +169,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:class="$style.themeRadio"
|
:class="$style.themeRadio"
|
||||||
:value="theme.id"
|
:value="theme.id"
|
||||||
/>
|
/>
|
||||||
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" draggable="true" @dragstart="onThemeDragstart($event, theme)" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
<label :for="`themeRadio_${theme.id}`" :class="$style.themeItemRoot" class="_button" @contextmenu.prevent.stop="onThemeContextmenu(theme, $event)">
|
||||||
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
<MkThemePreview :theme="theme" :class="$style.themeItemPreview"/>
|
||||||
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
<div :class="$style.themeItemCaption">{{ theme.name }}</div>
|
||||||
</label>
|
</label>
|
||||||
|
@ -218,7 +214,7 @@ import FormLink from '@/components/form/link.vue';
|
||||||
import MkFolder from '@/components/MkFolder.vue';
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
import MkThemePreview from '@/components/MkThemePreview.vue';
|
import MkThemePreview from '@/components/MkThemePreview.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { getBuiltinThemesRef, getThemesRef, installTheme, parseThemeCode, removeTheme } from '@/theme.js';
|
import { getBuiltinThemesRef, getThemesRef, removeTheme } from '@/theme.js';
|
||||||
import { isDeviceDarkmode } from '@/utility/is-device-darkmode.js';
|
import { isDeviceDarkmode } from '@/utility/is-device-darkmode.js';
|
||||||
import { store } from '@/store.js';
|
import { store } from '@/store.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
@ -227,7 +223,6 @@ import { uniqueBy } from '@/utility/array.js';
|
||||||
import { definePage } from '@/page.js';
|
import { definePage } from '@/page.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
|
||||||
import { checkDragDataType, getDragData, getPlainDragData, setDragData, setPlainDragData } from '@/drag-and-drop.js';
|
|
||||||
|
|
||||||
const installedThemes = getThemesRef();
|
const installedThemes = getThemesRef();
|
||||||
const builtinThemes = getBuiltinThemesRef();
|
const builtinThemes = getBuiltinThemesRef();
|
||||||
|
@ -326,38 +321,6 @@ function onThemeContextmenu(theme: Theme, ev: MouseEvent) {
|
||||||
}], ev);
|
}], ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onThemeDragstart(ev: DragEvent, theme: Theme) {
|
|
||||||
if (!ev.dataTransfer) return;
|
|
||||||
|
|
||||||
ev.dataTransfer.effectAllowed = 'copy';
|
|
||||||
setPlainDragData(ev, JSON5.stringify(theme, null, '\t'));
|
|
||||||
}
|
|
||||||
|
|
||||||
function onDragover(ev: DragEvent) {
|
|
||||||
if (!ev.dataTransfer) return;
|
|
||||||
|
|
||||||
if (ev.dataTransfer.types[0] === 'text/plain') {
|
|
||||||
ev.dataTransfer.dropEffect = 'copy';
|
|
||||||
} else {
|
|
||||||
ev.dataTransfer.dropEffect = 'none';
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function onDrop(ev: DragEvent) {
|
|
||||||
if (!ev.dataTransfer) return;
|
|
||||||
|
|
||||||
const code = getPlainDragData(ev);
|
|
||||||
if (code != null) {
|
|
||||||
try {
|
|
||||||
await installTheme(code);
|
|
||||||
} catch (err) {
|
|
||||||
// nop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerActions = computed(() => []);
|
const headerActions = computed(() => []);
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
|
@ -439,9 +439,6 @@ export const PREF_DEF = definePreferences({
|
||||||
defaultImageCompressionLevel: {
|
defaultImageCompressionLevel: {
|
||||||
default: 2 as 0 | 1 | 2 | 3,
|
default: 2 as 0 | 1 | 2 | 3,
|
||||||
},
|
},
|
||||||
defaultVideoCompressionLevel: {
|
|
||||||
default: 2 as 0 | 1 | 2 | 3,
|
|
||||||
},
|
|
||||||
|
|
||||||
'sound.masterVolume': {
|
'sound.masterVolume': {
|
||||||
default: 0.5,
|
default: 0.5,
|
||||||
|
|
|
@ -230,16 +230,11 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router
|
||||||
icon: 'ti ti-search',
|
icon: 'ti ti-search',
|
||||||
text: i18n.ts.searchThisUsersNotes,
|
text: i18n.ts.searchThisUsersNotes,
|
||||||
action: () => {
|
action: () => {
|
||||||
const query = {
|
|
||||||
username: user.username,
|
|
||||||
} as { username: string, host?: string };
|
|
||||||
|
|
||||||
if (user.host !== null) {
|
|
||||||
query.host = user.host;
|
|
||||||
}
|
|
||||||
|
|
||||||
router.push('/search', {
|
router.push('/search', {
|
||||||
query
|
query: {
|
||||||
|
username: user.username,
|
||||||
|
host: user.host ?? undefined,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,9 +18,7 @@ import { FX_stripe } from './fxs/stripe.js';
|
||||||
import { FX_threshold } from './fxs/threshold.js';
|
import { FX_threshold } from './fxs/threshold.js';
|
||||||
import { FX_zoomLines } from './fxs/zoomLines.js';
|
import { FX_zoomLines } from './fxs/zoomLines.js';
|
||||||
import { FX_blockNoise } from './fxs/blockNoise.js';
|
import { FX_blockNoise } from './fxs/blockNoise.js';
|
||||||
import { FX_fill } from './fxs/fill.js';
|
import { FX_fillSquare } from './fxs/fillSquare.js';
|
||||||
import { FX_blur } from './fxs/blur.js';
|
|
||||||
import { FX_pixelate } from './fxs/pixelate.js';
|
|
||||||
import type { ImageEffectorFx } from './ImageEffector.js';
|
import type { ImageEffectorFx } from './ImageEffector.js';
|
||||||
|
|
||||||
export const FXS = [
|
export const FXS = [
|
||||||
|
@ -39,7 +37,5 @@ export const FXS = [
|
||||||
FX_chromaticAberration,
|
FX_chromaticAberration,
|
||||||
FX_tearing,
|
FX_tearing,
|
||||||
FX_blockNoise,
|
FX_blockNoise,
|
||||||
FX_fill,
|
FX_fillSquare,
|
||||||
FX_blur,
|
|
||||||
FX_pixelate,
|
|
||||||
] as const satisfies ImageEffectorFx<string, any>[];
|
] as const satisfies ImageEffectorFx<string, any>[];
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
const float PI = 3.141592653589793;
|
|
||||||
const float TWO_PI = 6.283185307179586;
|
|
||||||
const float HALF_PI = 1.5707963267948966;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform vec2 u_offset;
|
|
||||||
uniform vec2 u_scale;
|
|
||||||
uniform bool u_ellipse;
|
|
||||||
uniform float u_angle;
|
|
||||||
uniform float u_radius;
|
|
||||||
uniform int u_samples;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
float angle = -(u_angle * PI);
|
|
||||||
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
|
|
||||||
vec2 rotatedUV = vec2(
|
|
||||||
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
|
||||||
) + u_offset;
|
|
||||||
|
|
||||||
bool isInside = false;
|
|
||||||
if (u_ellipse) {
|
|
||||||
vec2 norm = (rotatedUV - u_offset) / u_scale;
|
|
||||||
isInside = dot(norm, norm) <= 1.0;
|
|
||||||
} else {
|
|
||||||
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isInside) {
|
|
||||||
out_color = texture(in_texture, in_uv);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec4 result = vec4(0.0);
|
|
||||||
float totalSamples = 0.0;
|
|
||||||
|
|
||||||
// Make blur radius resolution-independent by using a percentage of image size
|
|
||||||
// This ensures consistent visual blur regardless of image resolution
|
|
||||||
float referenceSize = min(in_resolution.x, in_resolution.y);
|
|
||||||
float normalizedRadius = u_radius / 100.0; // Convert radius to percentage (0-15 -> 0-0.15)
|
|
||||||
vec2 blurOffset = vec2(normalizedRadius) / in_resolution * referenceSize;
|
|
||||||
|
|
||||||
// Calculate how many samples to take in each direction
|
|
||||||
// This determines the grid density, not the blur extent
|
|
||||||
int sampleRadius = int(sqrt(float(u_samples)) / 2.0);
|
|
||||||
|
|
||||||
// Sample in a grid pattern within the specified radius
|
|
||||||
for (int x = -sampleRadius; x <= sampleRadius; x++) {
|
|
||||||
for (int y = -sampleRadius; y <= sampleRadius; y++) {
|
|
||||||
// Normalize the grid position to [-1, 1] range
|
|
||||||
float normalizedX = float(x) / float(sampleRadius);
|
|
||||||
float normalizedY = float(y) / float(sampleRadius);
|
|
||||||
|
|
||||||
// Scale by radius to get the actual sampling offset
|
|
||||||
vec2 offset = vec2(normalizedX, normalizedY) * blurOffset;
|
|
||||||
vec2 sampleUV = in_uv + offset;
|
|
||||||
|
|
||||||
// Only sample if within texture bounds
|
|
||||||
if (sampleUV.x >= 0.0 && sampleUV.x <= 1.0 && sampleUV.y >= 0.0 && sampleUV.y <= 1.0) {
|
|
||||||
result += texture(in_texture, sampleUV);
|
|
||||||
totalSamples += 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_blur = defineImageEffectorFx({
|
|
||||||
id: 'blur',
|
|
||||||
name: i18n.ts._imageEffector._fxs.blur,
|
|
||||||
shader,
|
|
||||||
uniforms: ['offset', 'scale', 'ellipse', 'angle', 'radius', 'samples'] as const,
|
|
||||||
params: {
|
|
||||||
offsetX: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.offset + ' X',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.0,
|
|
||||||
min: -1.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
offsetY: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.offset + ' Y',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.0,
|
|
||||||
min: -1.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
scaleX: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.scale + ' W',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.5,
|
|
||||||
min: 0.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
scaleY: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.scale + ' H',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.5,
|
|
||||||
min: 0.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
ellipse: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.circle,
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
angle: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.angle,
|
|
||||||
type: 'number',
|
|
||||||
default: 0,
|
|
||||||
min: -1.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 90) + '°',
|
|
||||||
},
|
|
||||||
radius: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.strength,
|
|
||||||
type: 'number',
|
|
||||||
default: 3.0,
|
|
||||||
min: 0.0,
|
|
||||||
max: 10.0,
|
|
||||||
step: 0.5,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
main: ({ gl, u, params }) => {
|
|
||||||
gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
|
|
||||||
gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
|
|
||||||
gl.uniform1i(u.ellipse, params.ellipse ? 1 : 0);
|
|
||||||
gl.uniform1f(u.angle, params.angle / 2);
|
|
||||||
gl.uniform1f(u.radius, params.radius);
|
|
||||||
gl.uniform1i(u.samples, 256);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -18,7 +18,6 @@ uniform sampler2D in_texture;
|
||||||
uniform vec2 in_resolution;
|
uniform vec2 in_resolution;
|
||||||
uniform vec2 u_offset;
|
uniform vec2 u_offset;
|
||||||
uniform vec2 u_scale;
|
uniform vec2 u_scale;
|
||||||
uniform bool u_ellipse;
|
|
||||||
uniform float u_angle;
|
uniform float u_angle;
|
||||||
uniform vec3 u_color;
|
uniform vec3 u_color;
|
||||||
uniform float u_opacity;
|
uniform float u_opacity;
|
||||||
|
@ -36,13 +35,7 @@ void main() {
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
||||||
) + u_offset;
|
) + u_offset;
|
||||||
|
|
||||||
bool isInside = false;
|
bool isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
|
||||||
if (u_ellipse) {
|
|
||||||
vec2 norm = (rotatedUV - u_offset) / u_scale;
|
|
||||||
isInside = dot(norm, norm) <= 1.0;
|
|
||||||
} else {
|
|
||||||
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
out_color = isInside ? vec4(
|
out_color = isInside ? vec4(
|
||||||
mix(in_color.r, u_color.r, u_opacity),
|
mix(in_color.r, u_color.r, u_opacity),
|
||||||
|
@ -53,11 +46,11 @@ void main() {
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const FX_fill = defineImageEffectorFx({
|
export const FX_fillSquare = defineImageEffectorFx({
|
||||||
id: 'fill',
|
id: 'fillSquare',
|
||||||
name: i18n.ts._imageEffector._fxs.fill,
|
name: i18n.ts._imageEffector._fxs.fillSquare,
|
||||||
shader,
|
shader,
|
||||||
uniforms: ['offset', 'scale', 'ellipse', 'angle', 'color', 'opacity'] as const,
|
uniforms: ['offset', 'scale', 'angle', 'color', 'opacity'] as const,
|
||||||
params: {
|
params: {
|
||||||
offsetX: {
|
offsetX: {
|
||||||
label: i18n.ts._imageEffector._fxProps.offset + ' X',
|
label: i18n.ts._imageEffector._fxProps.offset + ' X',
|
||||||
|
@ -78,7 +71,7 @@ export const FX_fill = defineImageEffectorFx({
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
toViewValue: v => Math.round(v * 100) + '%',
|
||||||
},
|
},
|
||||||
scaleX: {
|
scaleX: {
|
||||||
label: i18n.ts._imageEffector._fxProps.scale + ' W',
|
label: i18n.ts._imageEffector._fxProps.scale + ' X',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
default: 0.5,
|
default: 0.5,
|
||||||
min: 0.0,
|
min: 0.0,
|
||||||
|
@ -87,7 +80,7 @@ export const FX_fill = defineImageEffectorFx({
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
toViewValue: v => Math.round(v * 100) + '%',
|
||||||
},
|
},
|
||||||
scaleY: {
|
scaleY: {
|
||||||
label: i18n.ts._imageEffector._fxProps.scale + ' H',
|
label: i18n.ts._imageEffector._fxProps.scale + ' Y',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
default: 0.5,
|
default: 0.5,
|
||||||
min: 0.0,
|
min: 0.0,
|
||||||
|
@ -95,11 +88,6 @@ export const FX_fill = defineImageEffectorFx({
|
||||||
step: 0.01,
|
step: 0.01,
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
toViewValue: v => Math.round(v * 100) + '%',
|
||||||
},
|
},
|
||||||
ellipse: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.circle,
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
angle: {
|
angle: {
|
||||||
label: i18n.ts._imageEffector._fxProps.angle,
|
label: i18n.ts._imageEffector._fxProps.angle,
|
||||||
type: 'number',
|
type: 'number',
|
||||||
|
@ -127,7 +115,6 @@ export const FX_fill = defineImageEffectorFx({
|
||||||
main: ({ gl, u, params }) => {
|
main: ({ gl, u, params }) => {
|
||||||
gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
|
gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
|
||||||
gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
|
gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
|
||||||
gl.uniform1i(u.ellipse, params.ellipse ? 1 : 0);
|
|
||||||
gl.uniform1f(u.angle, params.angle / 2);
|
gl.uniform1f(u.angle, params.angle / 2);
|
||||||
gl.uniform3f(u.color, params.color[0], params.color[1], params.color[2]);
|
gl.uniform3f(u.color, params.color[0], params.color[1], params.color[2]);
|
||||||
gl.uniform1f(u.opacity, params.opacity);
|
gl.uniform1f(u.opacity, params.opacity);
|
|
@ -1,147 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { defineImageEffectorFx } from '../ImageEffector.js';
|
|
||||||
import { i18n } from '@/i18n.js';
|
|
||||||
|
|
||||||
const shader = `#version 300 es
|
|
||||||
precision mediump float;
|
|
||||||
|
|
||||||
const float PI = 3.141592653589793;
|
|
||||||
const float TWO_PI = 6.283185307179586;
|
|
||||||
const float HALF_PI = 1.5707963267948966;
|
|
||||||
|
|
||||||
in vec2 in_uv;
|
|
||||||
uniform sampler2D in_texture;
|
|
||||||
uniform vec2 in_resolution;
|
|
||||||
uniform vec2 u_offset;
|
|
||||||
uniform vec2 u_scale;
|
|
||||||
uniform bool u_ellipse;
|
|
||||||
uniform float u_angle;
|
|
||||||
uniform int u_samples;
|
|
||||||
uniform float u_strength;
|
|
||||||
out vec4 out_color;
|
|
||||||
|
|
||||||
// TODO: pixelateの中心を画像中心ではなく範囲の中心にする
|
|
||||||
// TODO: 画像のアスペクト比に関わらず各画素は正方形にする
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
if (u_strength <= 0.0) {
|
|
||||||
out_color = texture(in_texture, in_uv);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float angle = -(u_angle * PI);
|
|
||||||
vec2 centeredUv = in_uv - vec2(0.5, 0.5) - u_offset;
|
|
||||||
vec2 rotatedUV = vec2(
|
|
||||||
centeredUv.x * cos(angle) - centeredUv.y * sin(angle),
|
|
||||||
centeredUv.x * sin(angle) + centeredUv.y * cos(angle)
|
|
||||||
) + u_offset;
|
|
||||||
|
|
||||||
bool isInside = false;
|
|
||||||
if (u_ellipse) {
|
|
||||||
vec2 norm = (rotatedUV - u_offset) / u_scale;
|
|
||||||
isInside = dot(norm, norm) <= 1.0;
|
|
||||||
} else {
|
|
||||||
isInside = rotatedUV.x > u_offset.x - u_scale.x && rotatedUV.x < u_offset.x + u_scale.x && rotatedUV.y > u_offset.y - u_scale.y && rotatedUV.y < u_offset.y + u_scale.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isInside) {
|
|
||||||
out_color = texture(in_texture, in_uv);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float dx = u_strength / 1.0;
|
|
||||||
float dy = u_strength / 1.0;
|
|
||||||
vec2 new_uv = vec2(
|
|
||||||
(dx * (floor((in_uv.x - 0.5 - (dx / 2.0)) / dx) + 0.5)),
|
|
||||||
(dy * (floor((in_uv.y - 0.5 - (dy / 2.0)) / dy) + 0.5))
|
|
||||||
) + vec2(0.5 + (dx / 2.0), 0.5 + (dy / 2.0));
|
|
||||||
|
|
||||||
vec4 result = vec4(0.0);
|
|
||||||
float totalSamples = 0.0;
|
|
||||||
|
|
||||||
// TODO: より多くのサンプリング
|
|
||||||
result += texture(in_texture, new_uv);
|
|
||||||
totalSamples += 1.0;
|
|
||||||
|
|
||||||
out_color = totalSamples > 0.0 ? result / totalSamples : texture(in_texture, in_uv);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const FX_pixelate = defineImageEffectorFx({
|
|
||||||
id: 'pixelate',
|
|
||||||
name: i18n.ts._imageEffector._fxs.pixelate,
|
|
||||||
shader,
|
|
||||||
uniforms: ['offset', 'scale', 'ellipse', 'angle', 'strength', 'samples'] as const,
|
|
||||||
params: {
|
|
||||||
offsetX: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.offset + ' X',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.0,
|
|
||||||
min: -1.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
offsetY: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.offset + ' Y',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.0,
|
|
||||||
min: -1.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
scaleX: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.scale + ' W',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.5,
|
|
||||||
min: 0.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
scaleY: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.scale + ' H',
|
|
||||||
type: 'number',
|
|
||||||
default: 0.5,
|
|
||||||
min: 0.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 100) + '%',
|
|
||||||
},
|
|
||||||
ellipse: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.circle,
|
|
||||||
type: 'boolean',
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
angle: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.angle,
|
|
||||||
type: 'number',
|
|
||||||
default: 0,
|
|
||||||
min: -1.0,
|
|
||||||
max: 1.0,
|
|
||||||
step: 0.01,
|
|
||||||
toViewValue: v => Math.round(v * 90) + '°',
|
|
||||||
},
|
|
||||||
strength: {
|
|
||||||
label: i18n.ts._imageEffector._fxProps.strength,
|
|
||||||
type: 'number',
|
|
||||||
default: 0.2,
|
|
||||||
min: 0.0,
|
|
||||||
max: 0.5,
|
|
||||||
step: 0.01,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
main: ({ gl, u, params }) => {
|
|
||||||
gl.uniform2f(u.offset, params.offsetX / 2, params.offsetY / 2);
|
|
||||||
gl.uniform2f(u.scale, params.scaleX / 2, params.scaleY / 2);
|
|
||||||
gl.uniform1i(u.ellipse, params.ellipse ? 1 : 0);
|
|
||||||
gl.uniform1f(u.angle, params.angle / 2);
|
|
||||||
gl.uniform1f(u.strength, params.strength * params.strength);
|
|
||||||
gl.uniform1i(u.samples, 256);
|
|
||||||
},
|
|
||||||
});
|
|
|
@ -34,7 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
activity: {
|
activity: {
|
||||||
total: number;
|
total: number;
|
||||||
|
@ -94,10 +94,6 @@ function render() {
|
||||||
pointsTotal.value = activity.map((d, i) => `${(i * zoom.value) + pos.value},${(1 - (d.total / peak)) * viewBoxY.value}`).join(' ');
|
pointsTotal.value = activity.map((d, i) => `${(i * zoom.value) + pos.value},${(1 - (d.total / peak)) * viewBoxY.value}`).join(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
render();
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
@ -85,8 +85,6 @@ export function toBase62(n: number): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfig(): UserConfig {
|
export function getConfig(): UserConfig {
|
||||||
const localesHash = toBase62(hash(JSON.stringify(locales)));
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
base: '/vite/',
|
base: '/vite/',
|
||||||
|
|
||||||
|
@ -190,9 +188,9 @@ export function getConfig(): UserConfig {
|
||||||
// dependencies of i18n.ts
|
// dependencies of i18n.ts
|
||||||
'config': ['@@/js/config.js'],
|
'config': ['@@/js/config.js'],
|
||||||
},
|
},
|
||||||
entryFileNames: `scripts/${localesHash}-[hash:8].js`,
|
entryFileNames: 'scripts/[hash:8].js',
|
||||||
chunkFileNames: `scripts/${localesHash}-[hash:8].js`,
|
chunkFileNames: 'scripts/[hash:8].js',
|
||||||
assetFileNames: `assets/${localesHash}-[hash:8][extname]`,
|
assetFileNames: 'assets/[hash:8][extname]',
|
||||||
paths(id) {
|
paths(id) {
|
||||||
for (const p of externalPackages) {
|
for (const p of externalPackages) {
|
||||||
if (p.match.test(id)) {
|
if (p.match.test(id)) {
|
||||||
|
|
|
@ -3226,7 +3226,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", "pollEnded", "scheduledNotePosted", "scheduledNotePostFailed", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
|
export const notificationTypes: readonly ["note", "follow", "mention", "reply", "renote", "quote", "reaction", "pollEnded", "receiveFollowRequest", "followRequestAccepted", "groupInvited", "app", "roleAssigned", "chatRoomInvitationReceived", "achievementEarned", "exportCompleted", "test", "login", "createToken"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export function nyaize(text: string): string;
|
export function nyaize(text: string): string;
|
||||||
|
@ -3339,7 +3339,7 @@ type QueueStats = {
|
||||||
type QueueStatsLog = QueueStats[];
|
type QueueStatsLog = QueueStats[];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const queueTypes: readonly ["system", "endedPollNotification", "postScheduledNote", "deliver", "inbox", "db", "relationship", "objectStorage", "userWebhookDeliver", "systemWebhookDeliver"];
|
export const queueTypes: readonly ["system", "endedPollNotification", "deliver", "inbox", "db", "relationship", "objectStorage", "userWebhookDeliver", "systemWebhookDeliver"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RenoteMuteCreateRequest = operations['renote-mute___create']['requestBody']['content']['application/json'];
|
type RenoteMuteCreateRequest = operations['renote-mute___create']['requestBody']['content']['application/json'];
|
||||||
|
@ -3441,7 +3441,7 @@ type RoleLite = components['schemas']['RoleLite'];
|
||||||
type RolePolicies = components['schemas']['RolePolicies'];
|
type RolePolicies = components['schemas']['RolePolicies'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
export const rolePolicies: readonly ["gtlAvailable", "ltlAvailable", "canPublicNote", "mentionLimit", "canInvite", "inviteLimit", "inviteLimitCycle", "inviteExpirationTime", "canManageCustomEmojis", "canManageAvatarDecorations", "canSearchNotes", "canSearchUsers", "canUseTranslator", "canHideAds", "driveCapacityMb", "maxFileSizeMb", "alwaysMarkNsfw", "canUpdateBioMedia", "pinLimit", "antennaLimit", "wordMuteLimit", "webhookLimit", "clipLimit", "noteEachClipsLimit", "userListLimit", "userEachUserListsLimit", "rateLimitFactor", "avatarDecorationLimit", "canImportAntennas", "canImportBlocking", "canImportFollowing", "canImportMuting", "canImportUserLists", "chatAvailability", "uploadableFileTypes", "noteDraftLimit", "scheduledNoteLimit", "watermarkAvailable"];
|
export const rolePolicies: readonly ["gtlAvailable", "ltlAvailable", "canPublicNote", "mentionLimit", "canInvite", "inviteLimit", "inviteLimitCycle", "inviteExpirationTime", "canManageCustomEmojis", "canManageAvatarDecorations", "canSearchNotes", "canSearchUsers", "canUseTranslator", "canHideAds", "driveCapacityMb", "maxFileSizeMb", "alwaysMarkNsfw", "canUpdateBioMedia", "pinLimit", "antennaLimit", "wordMuteLimit", "webhookLimit", "clipLimit", "noteEachClipsLimit", "userListLimit", "userEachUserListsLimit", "rateLimitFactor", "avatarDecorationLimit", "canImportAntennas", "canImportBlocking", "canImportFollowing", "canImportMuting", "canImportUserLists", "chatAvailability", "uploadableFileTypes", "noteDraftLimit", "watermarkAvailable"];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
type RolesListResponse = operations['roles___list']['responses']['200']['content']['application/json'];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"name": "misskey-js",
|
"name": "misskey-js",
|
||||||
"version": "2025.9.1-alpha.2",
|
"version": "2025.9.1-alpha.0",
|
||||||
"description": "Misskey SDK for JavaScript",
|
"description": "Misskey SDK for JavaScript",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"main": "./built/index.js",
|
"main": "./built/index.js",
|
||||||
|
|
|
@ -4159,24 +4159,6 @@ export type components = {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
scheduledNotePosted?: {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
|
||||||
} | {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'list';
|
|
||||||
/** Format: misskey:id */
|
|
||||||
userListId: string;
|
|
||||||
};
|
|
||||||
scheduledNotePostFailed?: {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
|
||||||
} | {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'list';
|
|
||||||
/** Format: misskey:id */
|
|
||||||
userListId: string;
|
|
||||||
};
|
|
||||||
receiveFollowRequest?: {
|
receiveFollowRequest?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
@ -4424,31 +4406,42 @@ export type components = {
|
||||||
/** Format: date-time */
|
/** Format: date-time */
|
||||||
createdAt: string;
|
createdAt: string;
|
||||||
text: string | null;
|
text: string | null;
|
||||||
cw: string | null;
|
cw?: string | null;
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
userId: string;
|
userId: string;
|
||||||
user: components['schemas']['UserLite'];
|
user: components['schemas']['UserLite'];
|
||||||
/** Format: id */
|
/**
|
||||||
replyId: string | null;
|
* Format: id
|
||||||
/** Format: id */
|
* @example xxxxxxxxxx
|
||||||
renoteId: string | null;
|
*/
|
||||||
|
replyId?: string | null;
|
||||||
|
/**
|
||||||
|
* Format: id
|
||||||
|
* @example xxxxxxxxxx
|
||||||
|
*/
|
||||||
|
renoteId?: string | null;
|
||||||
|
/** @description The reply target note contents if exists. If the reply target has been deleted since the draft was created, this will be null while replyId is not null. */
|
||||||
reply?: components['schemas']['Note'] | null;
|
reply?: components['schemas']['Note'] | null;
|
||||||
|
/** @description The renote target note contents if exists. If the renote target has been deleted since the draft was created, this will be null while renoteId is not null. */
|
||||||
renote?: components['schemas']['Note'] | null;
|
renote?: components['schemas']['Note'] | null;
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
visibility: 'public' | 'home' | 'followers' | 'specified';
|
visibility: 'public' | 'home' | 'followers' | 'specified';
|
||||||
visibleUserIds: string[];
|
visibleUserIds?: string[];
|
||||||
fileIds: string[];
|
fileIds?: string[];
|
||||||
files?: components['schemas']['DriveFile'][];
|
files?: components['schemas']['DriveFile'][];
|
||||||
hashtag: string | null;
|
hashtag?: string;
|
||||||
poll: {
|
poll?: {
|
||||||
/** Format: date-time */
|
/** Format: date-time */
|
||||||
expiresAt?: string | null;
|
expiresAt?: string | null;
|
||||||
expiredAfter?: number | null;
|
expiredAfter?: number | null;
|
||||||
multiple: boolean;
|
multiple: boolean;
|
||||||
choices: string[];
|
choices: string[];
|
||||||
} | null;
|
} | null;
|
||||||
/** Format: id */
|
/**
|
||||||
channelId: string | null;
|
* Format: id
|
||||||
|
* @example xxxxxxxxxx
|
||||||
|
*/
|
||||||
|
channelId?: string | null;
|
||||||
channel?: {
|
channel?: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -4457,11 +4450,9 @@ export type components = {
|
||||||
allowRenoteToExternal: boolean;
|
allowRenoteToExternal: boolean;
|
||||||
userId: string | null;
|
userId: string | null;
|
||||||
} | null;
|
} | null;
|
||||||
localOnly: boolean;
|
localOnly?: boolean;
|
||||||
/** @enum {string|null} */
|
/** @enum {string|null} */
|
||||||
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
|
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
|
||||||
scheduledAt: number | null;
|
|
||||||
isActuallyScheduled: boolean;
|
|
||||||
};
|
};
|
||||||
NoteReaction: {
|
NoteReaction: {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
|
@ -4570,22 +4561,6 @@ export type components = {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
userId: string;
|
userId: string;
|
||||||
note: components['schemas']['Note'];
|
note: components['schemas']['Note'];
|
||||||
} | {
|
|
||||||
/** Format: id */
|
|
||||||
id: string;
|
|
||||||
/** Format: date-time */
|
|
||||||
createdAt: string;
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'scheduledNotePosted';
|
|
||||||
note: components['schemas']['Note'];
|
|
||||||
} | {
|
|
||||||
/** Format: id */
|
|
||||||
id: string;
|
|
||||||
/** Format: date-time */
|
|
||||||
createdAt: string;
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'scheduledNotePostFailed';
|
|
||||||
noteDraft: components['schemas']['NoteDraft'];
|
|
||||||
} | {
|
} | {
|
||||||
/** Format: id */
|
/** Format: id */
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -5278,7 +5253,6 @@ export type components = {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
chatAvailability: 'available' | 'readonly' | 'unavailable';
|
||||||
noteDraftLimit: number;
|
noteDraftLimit: number;
|
||||||
scheduledNoteLimit: number;
|
|
||||||
watermarkAvailable: boolean;
|
watermarkAvailable: boolean;
|
||||||
};
|
};
|
||||||
ReversiGameLite: {
|
ReversiGameLite: {
|
||||||
|
@ -9579,7 +9553,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
state: '*' | 'completed' | 'wait' | 'active' | 'paused' | 'prioritized' | 'delayed' | 'failed';
|
state: '*' | 'completed' | 'wait' | 'active' | 'paused' | 'prioritized' | 'delayed' | 'failed';
|
||||||
};
|
};
|
||||||
|
@ -9766,7 +9740,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
state: ('active' | 'wait' | 'delayed' | 'completed' | 'failed' | 'paused')[];
|
state: ('active' | 'wait' | 'delayed' | 'completed' | 'failed' | 'paused')[];
|
||||||
search?: string;
|
search?: string;
|
||||||
};
|
};
|
||||||
|
@ -9834,7 +9808,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9897,7 +9871,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9910,7 +9884,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
name: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
name: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
qualifiedName: string;
|
qualifiedName: string;
|
||||||
counts: {
|
counts: {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
|
@ -10000,7 +9974,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
name: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
name: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
counts: {
|
counts: {
|
||||||
[key: string]: number;
|
[key: string]: number;
|
||||||
};
|
};
|
||||||
|
@ -10064,7 +10038,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10128,7 +10102,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10192,7 +10166,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -10259,7 +10233,7 @@ export interface operations {
|
||||||
content: {
|
content: {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
queue: 'system' | 'endedPollNotification' | 'postScheduledNote' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
queue: 'system' | 'endedPollNotification' | 'deliver' | 'inbox' | 'db' | 'relationship' | 'objectStorage' | 'userWebhookDeliver' | 'systemWebhookDeliver';
|
||||||
jobId: string;
|
jobId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -11679,24 +11653,6 @@ export interface operations {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
scheduledNotePosted?: {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
|
||||||
} | {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'list';
|
|
||||||
/** Format: misskey:id */
|
|
||||||
userListId: string;
|
|
||||||
};
|
|
||||||
scheduledNotePostFailed?: {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
|
||||||
} | {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'list';
|
|
||||||
/** Format: misskey:id */
|
|
||||||
userListId: string;
|
|
||||||
};
|
|
||||||
receiveFollowRequest?: {
|
receiveFollowRequest?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
@ -25998,8 +25954,8 @@ export interface operations {
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
markAsRead?: boolean;
|
markAsRead?: boolean;
|
||||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -26083,8 +26039,8 @@ export interface operations {
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
markAsRead?: boolean;
|
markAsRead?: boolean;
|
||||||
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
includeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'scheduledNotePosted' | 'scheduledNotePostFailed' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
excludeTypes?: ('note' | 'follow' | 'mention' | 'reply' | 'renote' | 'quote' | 'reaction' | 'pollEnded' | 'receiveFollowRequest' | 'followRequestAccepted' | 'roleAssigned' | 'chatRoomInvitationReceived' | 'achievementEarned' | 'exportCompleted' | 'login' | 'createToken' | 'app' | 'test' | 'pollVote' | 'groupInvited')[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -27358,24 +27314,6 @@ export interface operations {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
userListId: string;
|
userListId: string;
|
||||||
};
|
};
|
||||||
scheduledNotePosted?: {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
|
||||||
} | {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'list';
|
|
||||||
/** Format: misskey:id */
|
|
||||||
userListId: string;
|
|
||||||
};
|
|
||||||
scheduledNotePostFailed?: {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
|
||||||
} | {
|
|
||||||
/** @enum {string} */
|
|
||||||
type: 'list';
|
|
||||||
/** Format: misskey:id */
|
|
||||||
userListId: string;
|
|
||||||
};
|
|
||||||
receiveFollowRequest?: {
|
receiveFollowRequest?: {
|
||||||
/** @enum {string} */
|
/** @enum {string} */
|
||||||
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
type: 'all' | 'following' | 'follower' | 'mutualFollow' | 'followingOrFollower' | 'never';
|
||||||
|
@ -29205,34 +29143,31 @@ export interface operations {
|
||||||
* @default public
|
* @default public
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
visibility: 'public' | 'home' | 'followers' | 'specified';
|
visibility?: 'public' | 'home' | 'followers' | 'specified';
|
||||||
visibleUserIds: string[];
|
visibleUserIds?: string[];
|
||||||
cw: string | null;
|
cw?: string | null;
|
||||||
hashtag: string | null;
|
hashtag?: string | null;
|
||||||
/** @default false */
|
/** @default false */
|
||||||
localOnly: boolean;
|
localOnly?: boolean;
|
||||||
/**
|
/**
|
||||||
* @default null
|
* @default null
|
||||||
* @enum {string|null}
|
* @enum {string|null}
|
||||||
*/
|
*/
|
||||||
reactionAcceptance: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
|
reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
replyId: string | null;
|
replyId?: string | null;
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
renoteId: string | null;
|
renoteId?: string | null;
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
channelId: string | null;
|
channelId?: string | null;
|
||||||
text: string | null;
|
text?: string | null;
|
||||||
fileIds: string[];
|
fileIds?: string[];
|
||||||
poll: {
|
poll?: {
|
||||||
choices: string[];
|
choices: string[];
|
||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
expiresAt?: number | null;
|
expiresAt?: number | null;
|
||||||
expiredAfter?: number | null;
|
expiredAfter?: number | null;
|
||||||
} | null;
|
} | null;
|
||||||
scheduledAt: number | null;
|
|
||||||
/** @default false */
|
|
||||||
isActuallyScheduled: boolean;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -29379,7 +29314,6 @@ export interface operations {
|
||||||
untilId?: string;
|
untilId?: string;
|
||||||
sinceDate?: number;
|
sinceDate?: number;
|
||||||
untilDate?: number;
|
untilDate?: number;
|
||||||
scheduled?: boolean | null;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -29446,13 +29380,20 @@ export interface operations {
|
||||||
'application/json': {
|
'application/json': {
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
draftId: string;
|
draftId: string;
|
||||||
/** @enum {string} */
|
/**
|
||||||
|
* @default public
|
||||||
|
* @enum {string}
|
||||||
|
*/
|
||||||
visibility?: 'public' | 'home' | 'followers' | 'specified';
|
visibility?: 'public' | 'home' | 'followers' | 'specified';
|
||||||
visibleUserIds?: string[];
|
visibleUserIds?: string[];
|
||||||
cw?: string | null;
|
cw?: string | null;
|
||||||
hashtag?: string | null;
|
hashtag?: string | null;
|
||||||
|
/** @default false */
|
||||||
localOnly?: boolean;
|
localOnly?: boolean;
|
||||||
/** @enum {string|null} */
|
/**
|
||||||
|
* @default null
|
||||||
|
* @enum {string|null}
|
||||||
|
*/
|
||||||
reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
|
reactionAcceptance?: null | 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote';
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
replyId?: string | null;
|
replyId?: string | null;
|
||||||
|
@ -29468,8 +29409,6 @@ export interface operations {
|
||||||
expiresAt?: number | null;
|
expiresAt?: number | null;
|
||||||
expiredAfter?: number | null;
|
expiredAfter?: number | null;
|
||||||
} | null;
|
} | null;
|
||||||
scheduledAt?: number | null;
|
|
||||||
isActuallyScheduled?: boolean;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,8 +26,6 @@ export const notificationTypes = [
|
||||||
'quote',
|
'quote',
|
||||||
'reaction',
|
'reaction',
|
||||||
'pollEnded',
|
'pollEnded',
|
||||||
'scheduledNotePosted',
|
|
||||||
'scheduledNotePostFailed',
|
|
||||||
'receiveFollowRequest',
|
'receiveFollowRequest',
|
||||||
'followRequestAccepted',
|
'followRequestAccepted',
|
||||||
'groupInvited',
|
'groupInvited',
|
||||||
|
@ -229,14 +227,12 @@ export const rolePolicies = [
|
||||||
'chatAvailability',
|
'chatAvailability',
|
||||||
'uploadableFileTypes',
|
'uploadableFileTypes',
|
||||||
'noteDraftLimit',
|
'noteDraftLimit',
|
||||||
'scheduledNoteLimit',
|
|
||||||
'watermarkAvailable',
|
'watermarkAvailable',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const queueTypes = [
|
export const queueTypes = [
|
||||||
'system',
|
'system',
|
||||||
'endedPollNotification',
|
'endedPollNotification',
|
||||||
'postScheduledNote',
|
|
||||||
'deliver',
|
'deliver',
|
||||||
'inbox',
|
'inbox',
|
||||||
'db',
|
'db',
|
||||||
|
|
106
pnpm-lock.yaml
106
pnpm-lock.yaml
|
@ -83,8 +83,8 @@ importers:
|
||||||
specifier: 2.0.0
|
specifier: 2.0.0
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
pnpm:
|
pnpm:
|
||||||
specifier: 10.16.0
|
specifier: 10.15.1
|
||||||
version: 10.16.0
|
version: 10.15.1
|
||||||
start-server-and-test:
|
start-server-and-test:
|
||||||
specifier: 2.1.0
|
specifier: 2.1.0
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
|
@ -829,9 +829,6 @@ importers:
|
||||||
matter-js:
|
matter-js:
|
||||||
specifier: 0.20.0
|
specifier: 0.20.0
|
||||||
version: 0.20.0
|
version: 0.20.0
|
||||||
mediabunny:
|
|
||||||
specifier: 1.15.1
|
|
||||||
version: 1.15.1
|
|
||||||
mfm-js:
|
mfm-js:
|
||||||
specifier: 0.25.0
|
specifier: 0.25.0
|
||||||
version: 0.25.0
|
version: 0.25.0
|
||||||
|
@ -2443,163 +2440,138 @@ packages:
|
||||||
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
|
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm64@1.1.0':
|
'@img/sharp-libvips-linux-arm64@1.1.0':
|
||||||
resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
|
resolution: {integrity: sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm@1.0.5':
|
'@img/sharp-libvips-linux-arm@1.0.5':
|
||||||
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
|
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm@1.1.0':
|
'@img/sharp-libvips-linux-arm@1.1.0':
|
||||||
resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
|
resolution: {integrity: sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-ppc64@1.1.0':
|
'@img/sharp-libvips-linux-ppc64@1.1.0':
|
||||||
resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
|
resolution: {integrity: sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-s390x@1.0.4':
|
'@img/sharp-libvips-linux-s390x@1.0.4':
|
||||||
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
|
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-s390x@1.1.0':
|
'@img/sharp-libvips-linux-s390x@1.1.0':
|
||||||
resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
|
resolution: {integrity: sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-x64@1.0.4':
|
'@img/sharp-libvips-linux-x64@1.0.4':
|
||||||
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
|
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-x64@1.1.0':
|
'@img/sharp-libvips-linux-x64@1.1.0':
|
||||||
resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
|
resolution: {integrity: sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
||||||
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
|
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64@1.1.0':
|
'@img/sharp-libvips-linuxmusl-arm64@1.1.0':
|
||||||
resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
|
resolution: {integrity: sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
||||||
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
|
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64@1.1.0':
|
'@img/sharp-libvips-linuxmusl-x64@1.1.0':
|
||||||
resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
|
resolution: {integrity: sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm64@0.33.5':
|
'@img/sharp-linux-arm64@0.33.5':
|
||||||
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
|
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm64@0.34.2':
|
'@img/sharp-linux-arm64@0.34.2':
|
||||||
resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==}
|
resolution: {integrity: sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm@0.33.5':
|
'@img/sharp-linux-arm@0.33.5':
|
||||||
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
|
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-arm@0.34.2':
|
'@img/sharp-linux-arm@0.34.2':
|
||||||
resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==}
|
resolution: {integrity: sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-s390x@0.33.5':
|
'@img/sharp-linux-s390x@0.33.5':
|
||||||
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
|
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-s390x@0.34.2':
|
'@img/sharp-linux-s390x@0.34.2':
|
||||||
resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==}
|
resolution: {integrity: sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-x64@0.33.5':
|
'@img/sharp-linux-x64@0.33.5':
|
||||||
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
|
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linux-x64@0.34.2':
|
'@img/sharp-linux-x64@0.34.2':
|
||||||
resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==}
|
resolution: {integrity: sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-arm64@0.33.5':
|
'@img/sharp-linuxmusl-arm64@0.33.5':
|
||||||
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
|
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-arm64@0.34.2':
|
'@img/sharp-linuxmusl-arm64@0.34.2':
|
||||||
resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==}
|
resolution: {integrity: sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-x64@0.33.5':
|
'@img/sharp-linuxmusl-x64@0.33.5':
|
||||||
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
|
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-x64@0.34.2':
|
'@img/sharp-linuxmusl-x64@0.34.2':
|
||||||
resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==}
|
resolution: {integrity: sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@img/sharp-wasm32@0.33.5':
|
'@img/sharp-wasm32@0.33.5':
|
||||||
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
|
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
|
||||||
|
@ -2921,35 +2893,30 @@ packages:
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/canvas-linux-arm64-musl@0.1.79':
|
'@napi-rs/canvas-linux-arm64-musl@0.1.79':
|
||||||
resolution: {integrity: sha512-KsrsR3+6uXv70W/1/kY0yRK4/bbdJgA1Vuxw4KyfSc6mjl1DMoYXDAjpBT/5w7AXy6cGG44jm3upvvt/y/dPfg==}
|
resolution: {integrity: sha512-KsrsR3+6uXv70W/1/kY0yRK4/bbdJgA1Vuxw4KyfSc6mjl1DMoYXDAjpBT/5w7AXy6cGG44jm3upvvt/y/dPfg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@napi-rs/canvas-linux-riscv64-gnu@0.1.79':
|
'@napi-rs/canvas-linux-riscv64-gnu@0.1.79':
|
||||||
resolution: {integrity: sha512-EXaENnSJD6au6z4aKN2PpU9eVNWUsRI2cApm8gCa0WSRMaiYXZsFkXQmhB+Vz2pXahOS8BN2Zd8S1IeML/LCtg==}
|
resolution: {integrity: sha512-EXaENnSJD6au6z4aKN2PpU9eVNWUsRI2cApm8gCa0WSRMaiYXZsFkXQmhB+Vz2pXahOS8BN2Zd8S1IeML/LCtg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/canvas-linux-x64-gnu@0.1.79':
|
'@napi-rs/canvas-linux-x64-gnu@0.1.79':
|
||||||
resolution: {integrity: sha512-3xZhHlE9e3cd9D7Comy6/TTSs/8PUGXEXymIwYQrA1QxHojAlAOFlVai4rffzXd0bHylZu+/wD76LodvYqF1Yw==}
|
resolution: {integrity: sha512-3xZhHlE9e3cd9D7Comy6/TTSs/8PUGXEXymIwYQrA1QxHojAlAOFlVai4rffzXd0bHylZu+/wD76LodvYqF1Yw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@napi-rs/canvas-linux-x64-musl@0.1.79':
|
'@napi-rs/canvas-linux-x64-musl@0.1.79':
|
||||||
resolution: {integrity: sha512-4yv550uCjIEoTFgrpxYZK67nFlDMCQa3LAheM2QrO+B8w1p5w04usIQSCHqHe6aPWlbLQCIqfVcew6/7Q4KuHg==}
|
resolution: {integrity: sha512-4yv550uCjIEoTFgrpxYZK67nFlDMCQa3LAheM2QrO+B8w1p5w04usIQSCHqHe6aPWlbLQCIqfVcew6/7Q4KuHg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@napi-rs/canvas-win32-x64-msvc@0.1.79':
|
'@napi-rs/canvas-win32-x64-msvc@0.1.79':
|
||||||
resolution: {integrity: sha512-sD5qP2njBRnhNlTNFJDdpeCN6aR3qVamLySTwhX3ec8sdfeT/chf/x2dw2UXoIGMoVaVk/y2ifwxBj/h2a2jug==}
|
resolution: {integrity: sha512-sD5qP2njBRnhNlTNFJDdpeCN6aR3qVamLySTwhX3ec8sdfeT/chf/x2dw2UXoIGMoVaVk/y2ifwxBj/h2a2jug==}
|
||||||
|
@ -3304,42 +3271,36 @@ packages:
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm-musl@2.5.0':
|
'@parcel/watcher-linux-arm-musl@2.5.0':
|
||||||
resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
|
resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-glibc@2.5.0':
|
'@parcel/watcher-linux-arm64-glibc@2.5.0':
|
||||||
resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
|
resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-arm64-musl@2.5.0':
|
'@parcel/watcher-linux-arm64-musl@2.5.0':
|
||||||
resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
|
resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-glibc@2.5.0':
|
'@parcel/watcher-linux-x64-glibc@2.5.0':
|
||||||
resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
|
resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@parcel/watcher-linux-x64-musl@2.5.0':
|
'@parcel/watcher-linux-x64-musl@2.5.0':
|
||||||
resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
|
resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@parcel/watcher-win32-arm64@2.5.0':
|
'@parcel/watcher-win32-arm64@2.5.0':
|
||||||
resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
|
resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==}
|
||||||
|
@ -3509,133 +3470,111 @@ packages:
|
||||||
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
|
resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-gnueabihf@4.50.1':
|
'@rollup/rollup-linux-arm-gnueabihf@4.50.1':
|
||||||
resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==}
|
resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
|
'@rollup/rollup-linux-arm-musleabihf@4.46.2':
|
||||||
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
|
resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm-musleabihf@4.50.1':
|
'@rollup/rollup-linux-arm-musleabihf@4.50.1':
|
||||||
resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==}
|
resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.46.2':
|
'@rollup/rollup-linux-arm64-gnu@4.46.2':
|
||||||
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
|
resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-gnu@4.50.1':
|
'@rollup/rollup-linux-arm64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==}
|
resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.46.2':
|
'@rollup/rollup-linux-arm64-musl@4.46.2':
|
||||||
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
|
resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-arm64-musl@4.50.1':
|
'@rollup/rollup-linux-arm64-musl@4.50.1':
|
||||||
resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==}
|
resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
|
'@rollup/rollup-linux-loongarch64-gnu@4.46.2':
|
||||||
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
|
resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-loongarch64-gnu@4.50.1':
|
'@rollup/rollup-linux-loongarch64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==}
|
resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
|
'@rollup/rollup-linux-ppc64-gnu@4.46.2':
|
||||||
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
|
resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-ppc64-gnu@4.50.1':
|
'@rollup/rollup-linux-ppc64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==}
|
resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
|
'@rollup/rollup-linux-riscv64-gnu@4.46.2':
|
||||||
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
|
resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-gnu@4.50.1':
|
'@rollup/rollup-linux-riscv64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==}
|
resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.46.2':
|
'@rollup/rollup-linux-riscv64-musl@4.46.2':
|
||||||
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
|
resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-riscv64-musl@4.50.1':
|
'@rollup/rollup-linux-riscv64-musl@4.50.1':
|
||||||
resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==}
|
resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.46.2':
|
'@rollup/rollup-linux-s390x-gnu@4.46.2':
|
||||||
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
|
resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-s390x-gnu@4.50.1':
|
'@rollup/rollup-linux-s390x-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==}
|
resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.46.2':
|
'@rollup/rollup-linux-x64-gnu@4.46.2':
|
||||||
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
|
resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-gnu@4.50.1':
|
'@rollup/rollup-linux-x64-gnu@4.50.1':
|
||||||
resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==}
|
resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.46.2':
|
'@rollup/rollup-linux-x64-musl@4.46.2':
|
||||||
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
|
resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-linux-x64-musl@4.50.1':
|
'@rollup/rollup-linux-x64-musl@4.50.1':
|
||||||
resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==}
|
resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@rollup/rollup-openharmony-arm64@4.50.1':
|
'@rollup/rollup-openharmony-arm64@4.50.1':
|
||||||
resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==}
|
resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==}
|
||||||
|
@ -4369,28 +4308,24 @@ packages:
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@swc/core-linux-arm64-musl@1.13.5':
|
'@swc/core-linux-arm64-musl@1.13.5':
|
||||||
resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==}
|
resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@swc/core-linux-x64-gnu@1.13.5':
|
'@swc/core-linux-x64-gnu@1.13.5':
|
||||||
resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==}
|
resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
'@swc/core-linux-x64-musl@1.13.5':
|
'@swc/core-linux-x64-musl@1.13.5':
|
||||||
resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==}
|
resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
'@swc/core-win32-arm64-msvc@1.13.5':
|
'@swc/core-win32-arm64-msvc@1.13.5':
|
||||||
resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==}
|
resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==}
|
||||||
|
@ -4614,12 +4549,6 @@ packages:
|
||||||
'@types/doctrine@0.0.9':
|
'@types/doctrine@0.0.9':
|
||||||
resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==}
|
resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==}
|
||||||
|
|
||||||
'@types/dom-mediacapture-transform@0.1.11':
|
|
||||||
resolution: {integrity: sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==}
|
|
||||||
|
|
||||||
'@types/dom-webcodecs@0.1.13':
|
|
||||||
resolution: {integrity: sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==}
|
|
||||||
|
|
||||||
'@types/eslint@7.29.0':
|
'@types/eslint@7.29.0':
|
||||||
resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==}
|
resolution: {integrity: sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==}
|
||||||
|
|
||||||
|
@ -8211,9 +8140,6 @@ packages:
|
||||||
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
mediabunny@1.15.1:
|
|
||||||
resolution: {integrity: sha512-+eRTVzd3E4LuGYZzPSQcPzuGdAIljohSlzYTX358XsfLM2qH1lQIBYa+erx7wzVcGQLRNjdV7x7ZS0EpK04DfA==}
|
|
||||||
|
|
||||||
meilisearch@0.52.0:
|
meilisearch@0.52.0:
|
||||||
resolution: {integrity: sha512-RqPsB4a78sXf/ATB7PIVvKCG7yf0y1M+uCj8Z9Wku44WmCy3iz0C1PHjVV5xphQolo09CdhdyFoRxHQSJkOdpg==}
|
resolution: {integrity: sha512-RqPsB4a78sXf/ATB7PIVvKCG7yf0y1M+uCj8Z9Wku44WmCy3iz0C1PHjVV5xphQolo09CdhdyFoRxHQSJkOdpg==}
|
||||||
|
|
||||||
|
@ -9084,8 +9010,8 @@ packages:
|
||||||
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==}
|
||||||
engines: {node: '>=10.13.0'}
|
engines: {node: '>=10.13.0'}
|
||||||
|
|
||||||
pnpm@10.16.0:
|
pnpm@10.15.1:
|
||||||
resolution: {integrity: sha512-gGbnsDQhe3AKmk27OgBQYdZBuhMKiZFSE6ELPKSRnBnAN77IBmr9xVm4ljX9uAaxbqZz8kaPuyiqv6E8U+P3aQ==}
|
resolution: {integrity: sha512-NOU4wym1VTAUyo6PRTWZf5YYCh0PYUM5NXRJk1NQ2STiL4YUaCGRJk7DPRRirCFWGv+X9rsYBlNRwWLH6PbeZw==}
|
||||||
engines: {node: '>=18.12'}
|
engines: {node: '>=18.12'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
@ -9988,28 +9914,24 @@ packages:
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
slacc-linux-arm64-musl@0.0.10:
|
slacc-linux-arm64-musl@0.0.10:
|
||||||
resolution: {integrity: sha512-3lUX7752f6Okn54aONioaA+9M5TvifqXBAart+u2lNXEdWmmh003cVSU2Vcwg7nJ9lLHtju2DkDmKKfJjFuShA==}
|
resolution: {integrity: sha512-3lUX7752f6Okn54aONioaA+9M5TvifqXBAart+u2lNXEdWmmh003cVSU2Vcwg7nJ9lLHtju2DkDmKKfJjFuShA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [musl]
|
|
||||||
|
|
||||||
slacc-linux-x64-gnu@0.0.10:
|
slacc-linux-x64-gnu@0.0.10:
|
||||||
resolution: {integrity: sha512-BxxvylF9zlOLRLCpiyMvKTIUpdLlpetNBJ+DSMDh5+Ggq+AmQz2NUGawmcBJw58F8nMCj9TpWLlGNWc2AuY+JQ==}
|
resolution: {integrity: sha512-BxxvylF9zlOLRLCpiyMvKTIUpdLlpetNBJ+DSMDh5+Ggq+AmQz2NUGawmcBJw58F8nMCj9TpWLlGNWc2AuY+JQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
slacc-linux-x64-musl@0.0.10:
|
slacc-linux-x64-musl@0.0.10:
|
||||||
resolution: {integrity: sha512-TYJi8LOtJiTFcZvka4du7bMjF9Bz1RHRwyLnScr5E5yjjgoLRrsvgSu7bxp87xH+rgJ3CdEwE3w3Ux8EiewHpA==}
|
resolution: {integrity: sha512-TYJi8LOtJiTFcZvka4du7bMjF9Bz1RHRwyLnScr5E5yjjgoLRrsvgSu7bxp87xH+rgJ3CdEwE3w3Ux8EiewHpA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
libc: [glibc]
|
|
||||||
|
|
||||||
slacc-win32-arm64-msvc@0.0.10:
|
slacc-win32-arm64-msvc@0.0.10:
|
||||||
resolution: {integrity: sha512-1CHPLiDB4exzFyT5ndtJDsRRhBxNg8mGz6I6eJEMjelGkJR2KZPT9LZuby/1bS/bcVOr7zuJvGNfbEGBeHRwPQ==}
|
resolution: {integrity: sha512-1CHPLiDB4exzFyT5ndtJDsRRhBxNg8mGz6I6eJEMjelGkJR2KZPT9LZuby/1bS/bcVOr7zuJvGNfbEGBeHRwPQ==}
|
||||||
|
@ -11037,9 +10959,6 @@ packages:
|
||||||
vue-component-type-helpers@3.0.6:
|
vue-component-type-helpers@3.0.6:
|
||||||
resolution: {integrity: sha512-6CRM8X7EJqWCJOiKPvSLQG+hJPb/Oy2gyJx3pLjUEhY7PuaCthQu3e0zAGI1lqUBobrrk9IT0K8sG2GsCluxoQ==}
|
resolution: {integrity: sha512-6CRM8X7EJqWCJOiKPvSLQG+hJPb/Oy2gyJx3pLjUEhY7PuaCthQu3e0zAGI1lqUBobrrk9IT0K8sG2GsCluxoQ==}
|
||||||
|
|
||||||
vue-component-type-helpers@3.1.0-alpha.0:
|
|
||||||
resolution: {integrity: sha512-K1guwS1Oy0gNfBdIdIn8JMkUV+S38sriR1zf5dP+KkPS7/r5nHnPZUL74meY2CYlxYBH4qSQ+k7bpHfwiRvaMg==}
|
|
||||||
|
|
||||||
vue-demi@0.14.7:
|
vue-demi@0.14.7:
|
||||||
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
@ -14950,7 +14869,7 @@ snapshots:
|
||||||
storybook: 9.1.5(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(msw@2.11.1(@types/node@22.18.1)(typescript@5.9.2))(prettier@3.6.2)(utf-8-validate@6.0.5)(vite@7.1.5(@types/node@22.18.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5))
|
storybook: 9.1.5(@testing-library/dom@10.4.0)(bufferutil@4.0.9)(msw@2.11.1(@types/node@22.18.1)(typescript@5.9.2))(prettier@3.6.2)(utf-8-validate@6.0.5)(vite@7.1.5(@types/node@22.18.1)(sass@1.92.1)(terser@5.44.0)(tsx@4.20.5))
|
||||||
type-fest: 2.19.0
|
type-fest: 2.19.0
|
||||||
vue: 3.5.21(typescript@5.9.2)
|
vue: 3.5.21(typescript@5.9.2)
|
||||||
vue-component-type-helpers: 3.1.0-alpha.0
|
vue-component-type-helpers: 3.0.6
|
||||||
|
|
||||||
'@stylistic/eslint-plugin@2.13.0(eslint@9.35.0)(typescript@5.9.2)':
|
'@stylistic/eslint-plugin@2.13.0(eslint@9.35.0)(typescript@5.9.2)':
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -15302,12 +15221,6 @@ snapshots:
|
||||||
|
|
||||||
'@types/doctrine@0.0.9': {}
|
'@types/doctrine@0.0.9': {}
|
||||||
|
|
||||||
'@types/dom-mediacapture-transform@0.1.11':
|
|
||||||
dependencies:
|
|
||||||
'@types/dom-webcodecs': 0.1.13
|
|
||||||
|
|
||||||
'@types/dom-webcodecs@0.1.13': {}
|
|
||||||
|
|
||||||
'@types/eslint@7.29.0':
|
'@types/eslint@7.29.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/estree': 1.0.8
|
'@types/estree': 1.0.8
|
||||||
|
@ -19755,11 +19668,6 @@ snapshots:
|
||||||
|
|
||||||
media-typer@0.3.0: {}
|
media-typer@0.3.0: {}
|
||||||
|
|
||||||
mediabunny@1.15.1:
|
|
||||||
dependencies:
|
|
||||||
'@types/dom-mediacapture-transform': 0.1.11
|
|
||||||
'@types/dom-webcodecs': 0.1.13
|
|
||||||
|
|
||||||
meilisearch@0.52.0: {}
|
meilisearch@0.52.0: {}
|
||||||
|
|
||||||
memoizerific@1.11.3:
|
memoizerific@1.11.3:
|
||||||
|
@ -20729,7 +20637,7 @@ snapshots:
|
||||||
|
|
||||||
pngjs@5.0.0: {}
|
pngjs@5.0.0: {}
|
||||||
|
|
||||||
pnpm@10.16.0: {}
|
pnpm@10.15.1: {}
|
||||||
|
|
||||||
polished@4.2.2:
|
polished@4.2.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -22837,8 +22745,6 @@ snapshots:
|
||||||
|
|
||||||
vue-component-type-helpers@3.0.6: {}
|
vue-component-type-helpers@3.0.6: {}
|
||||||
|
|
||||||
vue-component-type-helpers@3.1.0-alpha.0: {}
|
|
||||||
|
|
||||||
vue-demi@0.14.7(vue@3.5.21(typescript@5.9.2)):
|
vue-demi@0.14.7(vue@3.5.21(typescript@5.9.2)):
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.5.21(typescript@5.9.2)
|
vue: 3.5.21(typescript@5.9.2)
|
||||||
|
|
|
@ -30,4 +30,3 @@ onlyBuiltDependencies:
|
||||||
- v-code-diff
|
- v-code-diff
|
||||||
- vue-demi
|
- vue-demi
|
||||||
ignorePatchFailures: false
|
ignorePatchFailures: false
|
||||||
minimumReleaseAge: 10080 # delay 7days to mitigate supply-chain attack
|
|
||||||
|
|
Loading…
Reference in New Issue