Merge remote-tracking branch 'refs/remotes/misskey-original/develop' into develop
# Conflicts: # packages/frontend/src/cache.ts # packages/frontend/src/pages/admin/index.vue # packages/frontend/src/pages/settings/general.vue # packages/frontend/src/pages/timeline.vue
This commit is contained in:
commit
07b4338eff
|
@ -136,6 +136,21 @@ redis:
|
||||||
|
|
||||||
id: 'aidx'
|
id: 'aidx'
|
||||||
|
|
||||||
|
# ┌────────────────┐
|
||||||
|
#───┘ Error tracking └──────────────────────────────────────────
|
||||||
|
|
||||||
|
# Sentry is available for error tracking.
|
||||||
|
# See the Sentry documentation for more details on options.
|
||||||
|
|
||||||
|
#sentryForBackend:
|
||||||
|
# enableNodeProfiling: true
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
#sentryForFrontend:
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
# ┌─────────────────────┐
|
# ┌─────────────────────┐
|
||||||
#───┘ Other configuration └─────────────────────────────────────
|
#───┘ Other configuration └─────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,21 @@ redis:
|
||||||
|
|
||||||
id: 'aidx'
|
id: 'aidx'
|
||||||
|
|
||||||
|
# ┌────────────────┐
|
||||||
|
#───┘ Error tracking └──────────────────────────────────────────
|
||||||
|
|
||||||
|
# Sentry is available for error tracking.
|
||||||
|
# See the Sentry documentation for more details on options.
|
||||||
|
|
||||||
|
#sentryForBackend:
|
||||||
|
# enableNodeProfiling: true
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
#sentryForFrontend:
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
# ┌─────────────────────┐
|
# ┌─────────────────────┐
|
||||||
#───┘ Other configuration └─────────────────────────────────────
|
#───┘ Other configuration └─────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,21 @@ redis:
|
||||||
|
|
||||||
id: 'aidx'
|
id: 'aidx'
|
||||||
|
|
||||||
|
# ┌────────────────┐
|
||||||
|
#───┘ Error tracking └──────────────────────────────────────────
|
||||||
|
|
||||||
|
# Sentry is available for error tracking.
|
||||||
|
# See the Sentry documentation for more details on options.
|
||||||
|
|
||||||
|
#sentryForBackend:
|
||||||
|
# enableNodeProfiling: true
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
#sentryForFrontend:
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
# ┌─────────────────────┐
|
# ┌─────────────────────┐
|
||||||
#───┘ Other configuration └─────────────────────────────────────
|
#───┘ Other configuration └─────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: [misskey-dev]
|
|
||||||
patreon: syuilo
|
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
# headがrelease/かつopenのPRを1つ取得
|
# headがrelease/かつopenのPRを1つ取得
|
||||||
- name: Get PR
|
- name: Get PR
|
||||||
run: |
|
run: |
|
||||||
echo "pr_number=$(gh pr list --limit 1 --head "${{ github.ref_name }}" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
|
echo "pr_number=$(gh pr list --limit 1 --head "$GITHUB_REF_NAME" --json number --jq '.[] | .number')" >> $GITHUB_OUTPUT
|
||||||
id: get_pr
|
id: get_pr
|
||||||
- name: Get target version
|
- name: Get target version
|
||||||
uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1
|
uses: misskey-dev/release-manager-actions/.github/actions/get-target-version@v1
|
||||||
|
@ -37,4 +37,7 @@ jobs:
|
||||||
# PRのnotesを更新
|
# PRのnotesを更新
|
||||||
- name: Update PR
|
- name: Update PR
|
||||||
run: |
|
run: |
|
||||||
gh pr edit ${{ steps.get_pr.outputs.pr_number }} --body "${{ steps.changelog.outputs.changelog }}"
|
gh pr edit "$PR_NUMBER" --body "$CHANGELOG"
|
||||||
|
env:
|
||||||
|
CHANGELOG: ${{ steps.changelog.outputs.changelog }}
|
||||||
|
PR_NUMBER: ${{ steps.get_pr.outputs.pr_number }}
|
||||||
|
|
|
@ -22,9 +22,11 @@ jobs:
|
||||||
# PR情報を取得
|
# PR情報を取得
|
||||||
- name: Get PR
|
- name: Get PR
|
||||||
run: |
|
run: |
|
||||||
pr_json=$(gh pr view ${{ github.event.pull_request.number }} --json isDraft,headRefName)
|
pr_json=$(gh pr view "$PR_NUMBER" --json isDraft,headRefName)
|
||||||
echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
|
echo "ref=$(echo $pr_json | jq -r '.headRefName')" >> $GITHUB_OUTPUT
|
||||||
id: get_pr
|
id: get_pr
|
||||||
|
env:
|
||||||
|
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||||
release:
|
release:
|
||||||
uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
|
uses: misskey-dev/release-manager-actions/.github/workflows/create-prerelease.yml@v1
|
||||||
needs: check
|
needs: check
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
- 管理者向け権限 `read:admin:show-users` は `read:admin:show-user` に統合されました。必要に応じてAPIトークンを再発行してください。
|
- 管理者向け権限 `read:admin:show-users` は `read:admin:show-user` に統合されました。必要に応じてAPIトークンを再発行してください。
|
||||||
|
|
||||||
### General
|
### General
|
||||||
|
- Feat: エラートラッキングにSentryを使用できるようになりました
|
||||||
- Enhance: URLプレビューの有効化・無効化を設定できるように #13569
|
- Enhance: URLプレビューの有効化・無効化を設定できるように #13569
|
||||||
- Enhance: アンテナでBotによるノートを除外できるように
|
- Enhance: アンテナでBotによるノートを除外できるように
|
||||||
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
|
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/545)
|
||||||
|
@ -25,6 +26,8 @@
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Feat: アップロードするファイルの名前をランダム文字列にできるように
|
- Feat: アップロードするファイルの名前をランダム文字列にできるように
|
||||||
|
- Feat: 個別のお知らせにリンクで飛べるように
|
||||||
|
(Based on https://github.com/MisskeyIO/misskey/pull/639)
|
||||||
- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
|
- Enhance: 自分のノートの添付ファイルから直接ファイルの詳細ページに飛べるように
|
||||||
- Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
|
- Enhance: 広告がMisskeyと同一ドメインの場合はRouterで遷移するように
|
||||||
- Enhance: リアクション・いいねの総数を表示するように
|
- Enhance: リアクション・いいねの総数を表示するように
|
||||||
|
@ -47,6 +50,9 @@
|
||||||
- Enhance: AiScriptを0.18.0にバージョンアップ
|
- Enhance: AiScriptを0.18.0にバージョンアップ
|
||||||
- Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
|
- Enhance: 通常のノートでも、お気に入りに登録したチャンネルにリノートできるように
|
||||||
- Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
|
- Enhance: 長いテキストをペーストした際にテキストファイルとして添付するかどうかを選択できるように
|
||||||
|
- Enhance: 新着ノートをサウンドで通知する機能をdeck UIに追加しました
|
||||||
|
- Enhance: コントロールパネルのクイックアクションからファイルを照会できるように
|
||||||
|
- Enhance: コントロールパネルのクイックアクションから通常の照会を行えるように
|
||||||
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
|
- Fix: 一部のページ内リンクが正しく動作しない問題を修正
|
||||||
- Fix: 周年の実績が閏年を考慮しない問題を修正
|
- Fix: 周年の実績が閏年を考慮しない問題を修正
|
||||||
- Fix: ローカルURLのプレビューポップアップが左上に表示される
|
- Fix: ローカルURLのプレビューポップアップが左上に表示される
|
||||||
|
@ -92,6 +98,8 @@
|
||||||
- Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
|
- Fix: `/i/notifications`に `includeTypes`か`excludeTypes`を指定しているとき、通知が存在するのに空配列を返すことがある問題を修正
|
||||||
- Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正
|
- Fix: 複数idを指定する`users/show`が関係ないユーザを返すことがある問題を修正
|
||||||
- Fix: `/tags` と `/user-tags` が検索エンジンにインデックスされないように
|
- Fix: `/tags` と `/user-tags` が検索エンジンにインデックスされないように
|
||||||
|
- Fix: もともとセンシティブではないと連合されていたファイルがセンシティブとして連合された場合にセンシティブとしてそのファイルを扱うように
|
||||||
|
- センシティブとして連合したファイルは非センシティブとして連合されてもセンシティブとして扱われます
|
||||||
|
|
||||||
## 2024.3.1
|
## 2024.3.1
|
||||||
|
|
||||||
|
|
|
@ -152,6 +152,22 @@ redis:
|
||||||
# ID SETTINGS AFTER THAT!
|
# ID SETTINGS AFTER THAT!
|
||||||
|
|
||||||
id: "aidx"
|
id: "aidx"
|
||||||
|
|
||||||
|
# ┌────────────────┐
|
||||||
|
#───┘ Error tracking └──────────────────────────────────────────
|
||||||
|
|
||||||
|
# Sentry is available for error tracking.
|
||||||
|
# See the Sentry documentation for more details on options.
|
||||||
|
|
||||||
|
#sentryForBackend:
|
||||||
|
# enableNodeProfiling: true
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
|
#sentryForFrontend:
|
||||||
|
# options:
|
||||||
|
# dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0'
|
||||||
|
|
||||||
# ┌─────────────────────┐
|
# ┌─────────────────────┐
|
||||||
#───┘ Other configuration └─────────────────────────────────────
|
#───┘ Other configuration └─────────────────────────────────────
|
||||||
|
|
||||||
|
|
|
@ -1016,6 +1016,8 @@ sourceCode: "الشفرة المصدرية"
|
||||||
flip: "اقلب"
|
flip: "اقلب"
|
||||||
lastNDays: "آخر {n} أيام"
|
lastNDays: "آخر {n} أيام"
|
||||||
surrender: "ألغِ"
|
surrender: "ألغِ"
|
||||||
|
_delivery:
|
||||||
|
stop: "مُعلّق"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "نجح إنشاء حسابك!"
|
accountCreated: "نجح إنشاء حسابك!"
|
||||||
letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
|
letsStartAccountSetup: "إذا كنت جديدًا لنعدّ حسابك الشخصي."
|
||||||
|
|
|
@ -857,6 +857,10 @@ replies: "জবাব"
|
||||||
renotes: "রিনোট"
|
renotes: "রিনোট"
|
||||||
sourceCode: "সোর্স কোড"
|
sourceCode: "সোর্স কোড"
|
||||||
flip: "উল্টান"
|
flip: "উল্টান"
|
||||||
|
_delivery:
|
||||||
|
stop: "স্থগিত করা হয়েছে"
|
||||||
|
_type:
|
||||||
|
none: "প্রকাশ করা হচ্ছে"
|
||||||
_role:
|
_role:
|
||||||
priority: "অগ্রাধিকার"
|
priority: "অগ্রাধিকার"
|
||||||
_priority:
|
_priority:
|
||||||
|
|
|
@ -1224,6 +1224,10 @@ gameRetry: "Torna a provar"
|
||||||
notUsePleaseLeaveBlank: "Si no voleu usar-ho, deixeu-ho en blanc"
|
notUsePleaseLeaveBlank: "Si no voleu usar-ho, deixeu-ho en blanc"
|
||||||
useTotp: "Usa una contrasenya d'un sol ús"
|
useTotp: "Usa una contrasenya d'un sol ús"
|
||||||
useBackupCode: "Usa un codi de recuperació"
|
useBackupCode: "Usa un codi de recuperació"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspés"
|
||||||
|
_type:
|
||||||
|
none: "S'està publicant"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Com es juga"
|
howToPlay: "Com es juga"
|
||||||
_howToPlay:
|
_howToPlay:
|
||||||
|
@ -2001,7 +2005,6 @@ _permissions:
|
||||||
"read:admin:server-info": "Veure informació del servidor"
|
"read:admin:server-info": "Veure informació del servidor"
|
||||||
"read:admin:show-moderation-log": "Veure registre de moderació "
|
"read:admin:show-moderation-log": "Veure registre de moderació "
|
||||||
"read:admin:show-user": "Veure informació privada de l'usuari "
|
"read:admin:show-user": "Veure informació privada de l'usuari "
|
||||||
"read:admin:show-users": "Veure informació privada de l'usuari "
|
|
||||||
"write:admin:suspend-user": "Suspendre usuari"
|
"write:admin:suspend-user": "Suspendre usuari"
|
||||||
"write:admin:unset-user-avatar": "Esborrar avatar d'usuari "
|
"write:admin:unset-user-avatar": "Esborrar avatar d'usuari "
|
||||||
"write:admin:unset-user-banner": "Esborrar bàner de l'usuari "
|
"write:admin:unset-user-banner": "Esborrar bàner de l'usuari "
|
||||||
|
|
|
@ -1099,6 +1099,10 @@ sourceCode: "Zdrojový kód"
|
||||||
flip: "Otočit"
|
flip: "Otočit"
|
||||||
lastNDays: "Posledních {n} dnů"
|
lastNDays: "Posledních {n} dnů"
|
||||||
surrender: "Zrušit"
|
surrender: "Zrušit"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspendováno"
|
||||||
|
_type:
|
||||||
|
none: "Publikuji"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "Váš účet byl úspěšně vytvořen!"
|
accountCreated: "Váš účet byl úspěšně vytvořen!"
|
||||||
letsStartAccountSetup: "Pro začátek si nastavte svůj profil."
|
letsStartAccountSetup: "Pro začátek si nastavte svůj profil."
|
||||||
|
|
|
@ -1,2 +1,4 @@
|
||||||
---
|
---
|
||||||
_lang_: "Dansk"
|
_lang_: "Dansk"
|
||||||
|
headlineMisskey: ""
|
||||||
|
introMisskey: "ようこそ!Misskeyは、オープンソースの分散型マイクロブログサービスです。\n「ノート」を作成して、いま起こっていることを共有したり、あなたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素早く反応を追加することもできます👍\n新しい世界を探検しよう🚀"
|
||||||
|
|
|
@ -1185,6 +1185,10 @@ addMfmFunction: "MFM hinzufügen"
|
||||||
sfx: "Soundeffekte"
|
sfx: "Soundeffekte"
|
||||||
lastNDays: "Letzten {n} Tage"
|
lastNDays: "Letzten {n} Tage"
|
||||||
surrender: "Abbrechen"
|
surrender: "Abbrechen"
|
||||||
|
_delivery:
|
||||||
|
stop: "Gesperrt"
|
||||||
|
_type:
|
||||||
|
none: "Wird veröffentlicht"
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "Nur für existierende Nutzer"
|
forExistingUsers: "Nur für existierende Nutzer"
|
||||||
forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
|
forExistingUsersDescription: "Ist diese Option aktiviert, wird diese Ankündigung nur Nutzern angezeigt, die zum Zeitpunkt der Ankündigung bereits registriert sind. Ist sie deaktiviert, wird sie auch Nutzern, die sich nach dessen Veröffentlichung registrieren, angezeigt."
|
||||||
|
|
|
@ -110,11 +110,14 @@ enterEmoji: "Enter an emoji"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
unrenote: "Remove renote"
|
unrenote: "Remove renote"
|
||||||
renoted: "Renoted."
|
renoted: "Renoted."
|
||||||
|
renotedToX: "Renote from {name} users。"
|
||||||
cantRenote: "This post can't be renoted."
|
cantRenote: "This post can't be renoted."
|
||||||
cantReRenote: "A renote can't be renoted."
|
cantReRenote: "A renote can't be renoted."
|
||||||
quote: "Quote"
|
quote: "Quote"
|
||||||
inChannelRenote: "Channel-only Renote"
|
inChannelRenote: "Channel-only Renote"
|
||||||
inChannelQuote: "Channel-only Quote"
|
inChannelQuote: "Channel-only Quote"
|
||||||
|
renoteToChannel: "Renote to channel"
|
||||||
|
renoteToOtherChannel: "Renote to other channel"
|
||||||
pinnedNote: "Pinned note"
|
pinnedNote: "Pinned note"
|
||||||
pinned: "Pin to profile"
|
pinned: "Pin to profile"
|
||||||
you: "You"
|
you: "You"
|
||||||
|
@ -474,6 +477,7 @@ retype: "Enter again"
|
||||||
noteOf: "Note by {user}"
|
noteOf: "Note by {user}"
|
||||||
quoteAttached: "Quote"
|
quoteAttached: "Quote"
|
||||||
quoteQuestion: "Append as quote?"
|
quoteQuestion: "Append as quote?"
|
||||||
|
attachAsFileQuestion: "The text in clipboard is long. Would you want to attach it as text file?"
|
||||||
noMessagesYet: "No messages yet"
|
noMessagesYet: "No messages yet"
|
||||||
newMessageExists: "There are new messages"
|
newMessageExists: "There are new messages"
|
||||||
onlyOneFileCanBeAttached: "You can only attach one file to a message"
|
onlyOneFileCanBeAttached: "You can only attach one file to a message"
|
||||||
|
@ -1244,6 +1248,15 @@ keepOriginalFilenameDescription: "If you turn off this setting, files names will
|
||||||
noDescription: "There is not the explanation"
|
noDescription: "There is not the explanation"
|
||||||
alwaysConfirmFollow: "Always confirm when following"
|
alwaysConfirmFollow: "Always confirm when following"
|
||||||
inquiry: "Contact"
|
inquiry: "Contact"
|
||||||
|
_delivery:
|
||||||
|
status: "Delivery status"
|
||||||
|
stop: "Suspended"
|
||||||
|
resume: "Delivery resume"
|
||||||
|
_type:
|
||||||
|
none: "Publishing"
|
||||||
|
manuallySuspended: "Manually suspended"
|
||||||
|
goneSuspended: "Server is suspended due to server deletion"
|
||||||
|
autoSuspendedForNotResponding: "Server is suspended due to no responding"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "How to play"
|
howToPlay: "How to play"
|
||||||
hold: "Hold"
|
hold: "Hold"
|
||||||
|
@ -2054,7 +2067,6 @@ _permissions:
|
||||||
"read:admin:server-info": "View server info"
|
"read:admin:server-info": "View server info"
|
||||||
"read:admin:show-moderation-log": "View moderation log"
|
"read:admin:show-moderation-log": "View moderation log"
|
||||||
"read:admin:show-user": "View private user info"
|
"read:admin:show-user": "View private user info"
|
||||||
"read:admin:show-users": "View private user info"
|
|
||||||
"write:admin:suspend-user": "Suspend user"
|
"write:admin:suspend-user": "Suspend user"
|
||||||
"write:admin:unset-user-avatar": "Remove user avatar"
|
"write:admin:unset-user-avatar": "Remove user avatar"
|
||||||
"write:admin:unset-user-banner": "Remove user banner"
|
"write:admin:unset-user-banner": "Remove user banner"
|
||||||
|
|
|
@ -1233,6 +1233,10 @@ useNativeUIForVideoAudioPlayer: "Usar la interfaz del navegador cuando se reprod
|
||||||
keepOriginalFilename: "Mantener el nombre original del archivo"
|
keepOriginalFilename: "Mantener el nombre original del archivo"
|
||||||
noDescription: "No hay descripción"
|
noDescription: "No hay descripción"
|
||||||
alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
|
alwaysConfirmFollow: "Confirmar siempre cuando se sigue a alguien"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspendido"
|
||||||
|
_type:
|
||||||
|
none: "Publicando"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Cómo jugar"
|
howToPlay: "Cómo jugar"
|
||||||
hold: "Mantener"
|
hold: "Mantener"
|
||||||
|
@ -2029,7 +2033,6 @@ _permissions:
|
||||||
"read:admin:server-info": "Ver información del servidor"
|
"read:admin:server-info": "Ver información del servidor"
|
||||||
"read:admin:show-moderation-log": "Ver log de moderación"
|
"read:admin:show-moderation-log": "Ver log de moderación"
|
||||||
"read:admin:show-user": "Ver información privada de usuario"
|
"read:admin:show-user": "Ver información privada de usuario"
|
||||||
"read:admin:show-users": "Ver información privada de usuario"
|
|
||||||
"write:admin:suspend-user": "Suspender cuentas de usuario"
|
"write:admin:suspend-user": "Suspender cuentas de usuario"
|
||||||
"write:admin:unset-user-avatar": "Quitar avatares de usuario"
|
"write:admin:unset-user-avatar": "Quitar avatares de usuario"
|
||||||
"write:admin:unset-user-banner": "Quitar banner de usuarios"
|
"write:admin:unset-user-banner": "Quitar banner de usuarios"
|
||||||
|
|
|
@ -1224,6 +1224,10 @@ enableHorizontalSwipe: "Glisser pour changer d'onglet"
|
||||||
loading: "Chargement en cours"
|
loading: "Chargement en cours"
|
||||||
surrender: "Annuler"
|
surrender: "Annuler"
|
||||||
gameRetry: "Réessayer"
|
gameRetry: "Réessayer"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspendu·e"
|
||||||
|
_type:
|
||||||
|
none: "Publié"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Comment jouer"
|
howToPlay: "Comment jouer"
|
||||||
hold: "Réserver"
|
hold: "Réserver"
|
||||||
|
|
|
@ -108,11 +108,14 @@ enterEmoji: "Masukkan emoji"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
unrenote: "Hapus renote"
|
unrenote: "Hapus renote"
|
||||||
renoted: "Telah direnote"
|
renoted: "Telah direnote"
|
||||||
|
renotedToX: "{name} telah merenote"
|
||||||
cantRenote: "Postingan ini tidak dapat direnote"
|
cantRenote: "Postingan ini tidak dapat direnote"
|
||||||
cantReRenote: "Renote tidak dapat direnote"
|
cantReRenote: "Renote tidak dapat direnote"
|
||||||
quote: "Kutip"
|
quote: "Kutip"
|
||||||
inChannelRenote: "Hanya renote dalam kanal"
|
inChannelRenote: "Hanya renote dalam kanal"
|
||||||
inChannelQuote: "Hanya kutip dalam kanal"
|
inChannelQuote: "Hanya kutip dalam kanal"
|
||||||
|
renoteToChannel: "Renote ke kanal"
|
||||||
|
renoteToOtherChannel: "Renote ke kanal lainnya"
|
||||||
pinnedNote: "Catatan yang disematkan"
|
pinnedNote: "Catatan yang disematkan"
|
||||||
pinned: "Sematkan ke profil"
|
pinned: "Sematkan ke profil"
|
||||||
you: "Kamu"
|
you: "Kamu"
|
||||||
|
@ -468,6 +471,7 @@ retype: "Masukkan ulang"
|
||||||
noteOf: "Catatan milik {user}"
|
noteOf: "Catatan milik {user}"
|
||||||
quoteAttached: "Dikutip"
|
quoteAttached: "Dikutip"
|
||||||
quoteQuestion: "Apakah kamu ingin menambahkan kutipan?"
|
quoteQuestion: "Apakah kamu ingin menambahkan kutipan?"
|
||||||
|
attachAsFileQuestion: "Teks dalam papan klip terlalu panjang. Apakah kamu ingin melampirkannya sebagai berkas teks?"
|
||||||
noMessagesYet: "Tidak ada pesan"
|
noMessagesYet: "Tidak ada pesan"
|
||||||
newMessageExists: "Kamu mendapatkan pesan baru"
|
newMessageExists: "Kamu mendapatkan pesan baru"
|
||||||
onlyOneFileCanBeAttached: "Kamu hanya dapat melampirkan satu berkas ke dalam pesan"
|
onlyOneFileCanBeAttached: "Kamu hanya dapat melampirkan satu berkas ke dalam pesan"
|
||||||
|
@ -1235,6 +1239,15 @@ keepOriginalFilenameDescription: "Apabila pengaturan ini dimatikan, nama berkas
|
||||||
noDescription: "Tidak ada deskripsi"
|
noDescription: "Tidak ada deskripsi"
|
||||||
alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
|
alwaysConfirmFollow: "Selalu konfirmasi ketika mengikuti"
|
||||||
inquiry: "Hubungi kami"
|
inquiry: "Hubungi kami"
|
||||||
|
_delivery:
|
||||||
|
status: "Status pengiriman"
|
||||||
|
stop: "Ditangguhkan"
|
||||||
|
resume: "Lanjutkan pengiriman"
|
||||||
|
_type:
|
||||||
|
none: "Sedang menyiarkan langsung"
|
||||||
|
manuallySuspended: "Ditangguhkan manual"
|
||||||
|
goneSuspended: "Sedang ditangguhkan untuk penghapusan peladen"
|
||||||
|
autoSuspendedForNotResponding: "Sedang ditangguhkan karena peladen tidak menjawab"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Cara bermain"
|
howToPlay: "Cara bermain"
|
||||||
hold: "Tahan"
|
hold: "Tahan"
|
||||||
|
@ -2032,7 +2045,6 @@ _permissions:
|
||||||
"read:admin:server-info": "Lihat informasi peladen"
|
"read:admin:server-info": "Lihat informasi peladen"
|
||||||
"read:admin:show-moderation-log": "Lihat log moderasi"
|
"read:admin:show-moderation-log": "Lihat log moderasi"
|
||||||
"read:admin:show-user": "Lihat informasi pengguna privat"
|
"read:admin:show-user": "Lihat informasi pengguna privat"
|
||||||
"read:admin:show-users": "Lihat informasi pengguna privat"
|
|
||||||
"write:admin:suspend-user": "Tangguhkan pengguna"
|
"write:admin:suspend-user": "Tangguhkan pengguna"
|
||||||
"write:admin:unset-user-avatar": "Hapus avatar pengguna"
|
"write:admin:unset-user-avatar": "Hapus avatar pengguna"
|
||||||
"write:admin:unset-user-banner": "Hapus banner pengguna"
|
"write:admin:unset-user-banner": "Hapus banner pengguna"
|
||||||
|
|
|
@ -1416,6 +1416,10 @@ export interface Locale extends ILocale {
|
||||||
* フォルダーを選択
|
* フォルダーを選択
|
||||||
*/
|
*/
|
||||||
"selectFolders": string;
|
"selectFolders": string;
|
||||||
|
/**
|
||||||
|
* ファイルが選択されていません
|
||||||
|
*/
|
||||||
|
"fileNotSelected": string;
|
||||||
/**
|
/**
|
||||||
* ファイル名を変更
|
* ファイル名を変更
|
||||||
*/
|
*/
|
||||||
|
@ -4329,9 +4333,13 @@ export interface Locale extends ILocale {
|
||||||
*/
|
*/
|
||||||
"thisPostMayBeAnnoyingIgnore": string;
|
"thisPostMayBeAnnoyingIgnore": string;
|
||||||
/**
|
/**
|
||||||
* 見たことのあるリノートを省略して表示
|
* リノートのスマート省略
|
||||||
*/
|
*/
|
||||||
"collapseRenotes": string;
|
"collapseRenotes": string;
|
||||||
|
/**
|
||||||
|
* リアクションやリノートをしたことがあるノートをたたんで表示します。
|
||||||
|
*/
|
||||||
|
"collapseRenotesDescription": string;
|
||||||
/**
|
/**
|
||||||
* サーバー内部エラー
|
* サーバー内部エラー
|
||||||
*/
|
*/
|
||||||
|
@ -9549,6 +9557,10 @@ export interface Locale extends ILocale {
|
||||||
* カラムを追加
|
* カラムを追加
|
||||||
*/
|
*/
|
||||||
"addColumn": string;
|
"addColumn": string;
|
||||||
|
/**
|
||||||
|
* 新着ノート通知の設定
|
||||||
|
*/
|
||||||
|
"newNoteNotificationSettings": string;
|
||||||
/**
|
/**
|
||||||
* カラムの設定
|
* カラムの設定
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1233,6 +1233,10 @@ useNativeUIForVideoAudioPlayer: "Riprodurre audio/video usando le funzionalità
|
||||||
keepOriginalFilename: "Mantieni il nome file originale"
|
keepOriginalFilename: "Mantieni il nome file originale"
|
||||||
keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
|
keepOriginalFilenameDescription: "Disattivandola, i file verranno caricati usando nomi casuali."
|
||||||
noDescription: "Manca la descrizione"
|
noDescription: "Manca la descrizione"
|
||||||
|
_delivery:
|
||||||
|
stop: "Sospensione"
|
||||||
|
_type:
|
||||||
|
none: "Pubblicazione"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "Come giocare"
|
howToPlay: "Come giocare"
|
||||||
hold: "Tieni"
|
hold: "Tieni"
|
||||||
|
@ -2025,7 +2029,6 @@ _permissions:
|
||||||
"read:admin:server-info": "Vedere le informazioni sul server"
|
"read:admin:server-info": "Vedere le informazioni sul server"
|
||||||
"read:admin:show-moderation-log": "Vedere lo storico di moderazione"
|
"read:admin:show-moderation-log": "Vedere lo storico di moderazione"
|
||||||
"read:admin:show-user": "Vedere le informazioni private degli account utente"
|
"read:admin:show-user": "Vedere le informazioni private degli account utente"
|
||||||
"read:admin:show-users": "Vedere le informazioni private degli account utente"
|
|
||||||
"write:admin:suspend-user": "Sospendere i profili"
|
"write:admin:suspend-user": "Sospendere i profili"
|
||||||
"write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili"
|
"write:admin:unset-user-avatar": "Rimuovere la foto profilo dai profili"
|
||||||
"write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili"
|
"write:admin:unset-user-banner": "Rimuovere l'immagine testata dai profili"
|
||||||
|
|
|
@ -351,6 +351,7 @@ selectFile: "ファイルを選択"
|
||||||
selectFiles: "ファイルを選択"
|
selectFiles: "ファイルを選択"
|
||||||
selectFolder: "フォルダーを選択"
|
selectFolder: "フォルダーを選択"
|
||||||
selectFolders: "フォルダーを選択"
|
selectFolders: "フォルダーを選択"
|
||||||
|
fileNotSelected: "ファイルが選択されていません"
|
||||||
renameFile: "ファイル名を変更"
|
renameFile: "ファイル名を変更"
|
||||||
folderName: "フォルダー名"
|
folderName: "フォルダー名"
|
||||||
createFolder: "フォルダーを作成"
|
createFolder: "フォルダーを作成"
|
||||||
|
@ -1079,7 +1080,8 @@ thisPostMayBeAnnoying: "この投稿は迷惑になる可能性があります
|
||||||
thisPostMayBeAnnoyingHome: "ホームに投稿"
|
thisPostMayBeAnnoyingHome: "ホームに投稿"
|
||||||
thisPostMayBeAnnoyingCancel: "やめる"
|
thisPostMayBeAnnoyingCancel: "やめる"
|
||||||
thisPostMayBeAnnoyingIgnore: "このまま投稿"
|
thisPostMayBeAnnoyingIgnore: "このまま投稿"
|
||||||
collapseRenotes: "見たことのあるリノートを省略して表示"
|
collapseRenotes: "リノートのスマート省略"
|
||||||
|
collapseRenotesDescription: "リアクションやリノートをしたことがあるノートをたたんで表示します。"
|
||||||
internalServerError: "サーバー内部エラー"
|
internalServerError: "サーバー内部エラー"
|
||||||
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
|
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
|
||||||
copyErrorInfo: "エラー情報をコピー"
|
copyErrorInfo: "エラー情報をコピー"
|
||||||
|
@ -2524,6 +2526,7 @@ _deck:
|
||||||
alwaysShowMainColumn: "常にメインカラムを表示"
|
alwaysShowMainColumn: "常にメインカラムを表示"
|
||||||
columnAlign: "カラムの寄せ"
|
columnAlign: "カラムの寄せ"
|
||||||
addColumn: "カラムを追加"
|
addColumn: "カラムを追加"
|
||||||
|
newNoteNotificationSettings: "新着ノート通知の設定"
|
||||||
configureColumn: "カラムの設定"
|
configureColumn: "カラムの設定"
|
||||||
swapLeft: "左に移動"
|
swapLeft: "左に移動"
|
||||||
swapRight: "右に移動"
|
swapRight: "右に移動"
|
||||||
|
|
|
@ -1235,6 +1235,10 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ
|
||||||
noDescription: "説明文はあらへんで"
|
noDescription: "説明文はあらへんで"
|
||||||
alwaysConfirmFollow: "フォローの際常に確認する"
|
alwaysConfirmFollow: "フォローの際常に確認する"
|
||||||
inquiry: "問い合わせ"
|
inquiry: "問い合わせ"
|
||||||
|
_delivery:
|
||||||
|
stop: "配信せぇへん"
|
||||||
|
_type:
|
||||||
|
none: "配信しとる"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "遊び方"
|
howToPlay: "遊び方"
|
||||||
hold: "ホールド"
|
hold: "ホールド"
|
||||||
|
@ -2032,7 +2036,6 @@ _permissions:
|
||||||
"read:admin:server-info": "サーバーの情報見る"
|
"read:admin:server-info": "サーバーの情報見る"
|
||||||
"read:admin:show-moderation-log": "モデレーションログ見る"
|
"read:admin:show-moderation-log": "モデレーションログ見る"
|
||||||
"read:admin:show-user": "ユーザーのプライベートな情報見る"
|
"read:admin:show-user": "ユーザーのプライベートな情報見る"
|
||||||
"read:admin:show-users": "ユーザーのプライベートな情報見る"
|
|
||||||
"write:admin:suspend-user": "ユーザーを凍結"
|
"write:admin:suspend-user": "ユーザーを凍結"
|
||||||
"write:admin:unset-user-avatar": "ユーザーのアバターを削除"
|
"write:admin:unset-user-avatar": "ユーザーのアバターを削除"
|
||||||
"write:admin:unset-user-banner": "ユーザーのバナーを削除"
|
"write:admin:unset-user-banner": "ユーザーのバナーを削除"
|
||||||
|
|
|
@ -649,6 +649,10 @@ replies: "답하기"
|
||||||
renotes: "리노트"
|
renotes: "리노트"
|
||||||
attach: "옇기"
|
attach: "옇기"
|
||||||
surrender: "아이예"
|
surrender: "아이예"
|
||||||
|
_delivery:
|
||||||
|
stop: "고만 보내예"
|
||||||
|
_type:
|
||||||
|
none: "보내고 잇어예"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
startTutorial: "길라잡이 하기"
|
startTutorial: "길라잡이 하기"
|
||||||
_initialTutorial:
|
_initialTutorial:
|
||||||
|
|
|
@ -1230,6 +1230,10 @@ useTotp: "일회용 비밀번호 사용"
|
||||||
useBackupCode: "백업 코드 사용"
|
useBackupCode: "백업 코드 사용"
|
||||||
launchApp: "앱 실행"
|
launchApp: "앱 실행"
|
||||||
useNativeUIForVideoAudioPlayer: "브라우저 UI에서 미디어 재생"
|
useNativeUIForVideoAudioPlayer: "브라우저 UI에서 미디어 재생"
|
||||||
|
_delivery:
|
||||||
|
stop: "정지됨"
|
||||||
|
_type:
|
||||||
|
none: "배포 중"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "설명"
|
howToPlay: "설명"
|
||||||
hold: "홀드"
|
hold: "홀드"
|
||||||
|
@ -2021,7 +2025,6 @@ _permissions:
|
||||||
"read:admin:server-info": "서버 정보 보기"
|
"read:admin:server-info": "서버 정보 보기"
|
||||||
"read:admin:show-moderation-log": "조정 기록 보기"
|
"read:admin:show-moderation-log": "조정 기록 보기"
|
||||||
"read:admin:show-user": "사용자 개인정보 보기"
|
"read:admin:show-user": "사용자 개인정보 보기"
|
||||||
"read:admin:show-users": "사용자 개인정보 보기"
|
|
||||||
"write:admin:suspend-user": "사용자 정지하기"
|
"write:admin:suspend-user": "사용자 정지하기"
|
||||||
"write:admin:unset-user-avatar": "사용자 아바타 삭제하기"
|
"write:admin:unset-user-avatar": "사용자 아바타 삭제하기"
|
||||||
"write:admin:unset-user-banner": "사용자 배너 삭제하기"
|
"write:admin:unset-user-banner": "사용자 배너 삭제하기"
|
||||||
|
|
|
@ -395,6 +395,10 @@ searchByGoogle: "ຄົ້ນຫາ"
|
||||||
file: "ໄຟລ໌"
|
file: "ໄຟລ໌"
|
||||||
replies: "ຕອບໄປທີ"
|
replies: "ຕອບໄປທີ"
|
||||||
renotes: "Renote"
|
renotes: "Renote"
|
||||||
|
_delivery:
|
||||||
|
stop: "ໂຈະ"
|
||||||
|
_type:
|
||||||
|
none: "ການພິມເຜີຍແຜ່"
|
||||||
_role:
|
_role:
|
||||||
_priority:
|
_priority:
|
||||||
middle: "ປານກາງ"
|
middle: "ປານກາງ"
|
||||||
|
|
|
@ -429,6 +429,10 @@ loggedInAsBot: "Momenteel als bot ingelogd"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
replies: "Antwoord"
|
replies: "Antwoord"
|
||||||
renotes: "Herdelen"
|
renotes: "Herdelen"
|
||||||
|
_delivery:
|
||||||
|
stop: "Opgeschort"
|
||||||
|
_type:
|
||||||
|
none: "Publiceren"
|
||||||
_email:
|
_email:
|
||||||
_follow:
|
_follow:
|
||||||
title: "volgde jou"
|
title: "volgde jou"
|
||||||
|
|
|
@ -464,6 +464,8 @@ icon: "Avatar"
|
||||||
replies: "Svar"
|
replies: "Svar"
|
||||||
renotes: "Renote"
|
renotes: "Renote"
|
||||||
surrender: "Avbryt"
|
surrender: "Avbryt"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspendert"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
theseSettingsCanEditLater: "Du kan endre disse innstillingene senere."
|
theseSettingsCanEditLater: "Du kan endre disse innstillingene senere."
|
||||||
_achievements:
|
_achievements:
|
||||||
|
|
|
@ -1023,6 +1023,10 @@ flip: "Odwróć"
|
||||||
lastNDays: "W ciągu ostatnich {n} dni"
|
lastNDays: "W ciągu ostatnich {n} dni"
|
||||||
surrender: "Odrzuć"
|
surrender: "Odrzuć"
|
||||||
gameRetry: "Spróbuj ponownie"
|
gameRetry: "Spróbuj ponownie"
|
||||||
|
_delivery:
|
||||||
|
stop: "Zawieszono"
|
||||||
|
_type:
|
||||||
|
none: "Publikowanie"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
_score:
|
_score:
|
||||||
score: "Wynik"
|
score: "Wynik"
|
||||||
|
|
|
@ -1012,6 +1012,10 @@ keepScreenOn: "Manter a tela do dispositivo sempre ligada"
|
||||||
flip: "Inversão"
|
flip: "Inversão"
|
||||||
lastNDays: "Últimos {n} dias"
|
lastNDays: "Últimos {n} dias"
|
||||||
surrender: "Cancelar"
|
surrender: "Cancelar"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspenso"
|
||||||
|
_type:
|
||||||
|
none: "Publicando"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
followUsers: "Siga usuários que lhe interessam para criar a sua linha do tempo."
|
followUsers: "Siga usuários que lhe interessam para criar a sua linha do tempo."
|
||||||
_serverSettings:
|
_serverSettings:
|
||||||
|
|
|
@ -651,6 +651,10 @@ show: "Arată"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
replies: "Răspunde"
|
replies: "Răspunde"
|
||||||
renotes: "Re-notează"
|
renotes: "Re-notează"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspendat"
|
||||||
|
_type:
|
||||||
|
none: "Publicare"
|
||||||
_role:
|
_role:
|
||||||
_priority:
|
_priority:
|
||||||
middle: "Mediu"
|
middle: "Mediu"
|
||||||
|
|
|
@ -1099,6 +1099,10 @@ flip: "Переворот"
|
||||||
code: "Код"
|
code: "Код"
|
||||||
lastNDays: "Последние {n} сут"
|
lastNDays: "Последние {n} сут"
|
||||||
surrender: "Этот пост не может быть отменен."
|
surrender: "Этот пост не может быть отменен."
|
||||||
|
_delivery:
|
||||||
|
stop: "Заморожено"
|
||||||
|
_type:
|
||||||
|
none: "Публикация"
|
||||||
_initialAccountSetting:
|
_initialAccountSetting:
|
||||||
accountCreated: "Аккаунт успешно создан!"
|
accountCreated: "Аккаунт успешно создан!"
|
||||||
letsStartAccountSetup: "Давайте настроим вашу учётную запись."
|
letsStartAccountSetup: "Давайте настроим вашу учётную запись."
|
||||||
|
|
|
@ -922,6 +922,10 @@ renotes: "Preposlať"
|
||||||
sourceCode: "Zdrojový kód"
|
sourceCode: "Zdrojový kód"
|
||||||
flip: "Preklopiť"
|
flip: "Preklopiť"
|
||||||
lastNDays: "Posledných {n} dní"
|
lastNDays: "Posledných {n} dní"
|
||||||
|
_delivery:
|
||||||
|
stop: "Zmrazené"
|
||||||
|
_type:
|
||||||
|
none: "Zverejňovanie"
|
||||||
_role:
|
_role:
|
||||||
priority: "Priorita"
|
priority: "Priorita"
|
||||||
_priority:
|
_priority:
|
||||||
|
|
|
@ -488,6 +488,10 @@ dataSaver: "Databesparing"
|
||||||
icon: "Profilbild"
|
icon: "Profilbild"
|
||||||
replies: "Svara"
|
replies: "Svara"
|
||||||
renotes: "Omnotera"
|
renotes: "Omnotera"
|
||||||
|
_delivery:
|
||||||
|
stop: "Suspenderad"
|
||||||
|
_type:
|
||||||
|
none: "Publiceras"
|
||||||
_achievements:
|
_achievements:
|
||||||
_types:
|
_types:
|
||||||
_open3windows:
|
_open3windows:
|
||||||
|
|
|
@ -1235,6 +1235,10 @@ keepOriginalFilenameDescription: "หากปิดการตั้งค่
|
||||||
noDescription: "ไม่มีข้อความอธิบาย"
|
noDescription: "ไม่มีข้อความอธิบาย"
|
||||||
alwaysConfirmFollow: "แสดงข้อความยืนยันเมื่อกดติดตาม"
|
alwaysConfirmFollow: "แสดงข้อความยืนยันเมื่อกดติดตาม"
|
||||||
inquiry: "ติดต่อเรา"
|
inquiry: "ติดต่อเรา"
|
||||||
|
_delivery:
|
||||||
|
stop: "ถูกระงับ"
|
||||||
|
_type:
|
||||||
|
none: "กำลังเผยแพร่"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "วิธีเล่น"
|
howToPlay: "วิธีเล่น"
|
||||||
hold: "หยุดชั่วคราว"
|
hold: "หยุดชั่วคราว"
|
||||||
|
@ -2032,7 +2036,6 @@ _permissions:
|
||||||
"read:admin:server-info": "ดูข้อมูลเซิร์ฟเวอร์"
|
"read:admin:server-info": "ดูข้อมูลเซิร์ฟเวอร์"
|
||||||
"read:admin:show-moderation-log": "ดูปูมการแก้ไข"
|
"read:admin:show-moderation-log": "ดูปูมการแก้ไข"
|
||||||
"read:admin:show-user": "ดูข้อมูลส่วนตัวของผู้ใช้"
|
"read:admin:show-user": "ดูข้อมูลส่วนตัวของผู้ใช้"
|
||||||
"read:admin:show-users": "ดูข้อมูลส่วนตัวของผู้ใช้"
|
|
||||||
"write:admin:suspend-user": "ระงับผู้ใช้"
|
"write:admin:suspend-user": "ระงับผู้ใช้"
|
||||||
"write:admin:unset-user-avatar": "ลบอวตารผู้ใช้"
|
"write:admin:unset-user-avatar": "ลบอวตารผู้ใช้"
|
||||||
"write:admin:unset-user-banner": "ลบแบนเนอร์ผู้ใช้"
|
"write:admin:unset-user-banner": "ลบแบนเนอร์ผู้ใช้"
|
||||||
|
|
|
@ -378,6 +378,10 @@ addMemo: "Kısa not ekle"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
replies: "yanıt"
|
replies: "yanıt"
|
||||||
renotes: "vazgeçme"
|
renotes: "vazgeçme"
|
||||||
|
_delivery:
|
||||||
|
stop: "Askıya alınmış"
|
||||||
|
_type:
|
||||||
|
none: "Paylaşım"
|
||||||
_accountDelete:
|
_accountDelete:
|
||||||
started: "Silme işlemi başlatıldı"
|
started: "Silme işlemi başlatıldı"
|
||||||
_email:
|
_email:
|
||||||
|
|
|
@ -914,6 +914,10 @@ renotes: "Поширити"
|
||||||
sourceCode: "Вихідний код"
|
sourceCode: "Вихідний код"
|
||||||
flip: "Перевернути"
|
flip: "Перевернути"
|
||||||
lastNDays: "Останні {n} днів"
|
lastNDays: "Останні {n} днів"
|
||||||
|
_delivery:
|
||||||
|
stop: "Призупинено"
|
||||||
|
_type:
|
||||||
|
none: "Публікація"
|
||||||
_achievements:
|
_achievements:
|
||||||
earnedAt: "Відкрито"
|
earnedAt: "Відкрито"
|
||||||
_types:
|
_types:
|
||||||
|
|
|
@ -846,6 +846,10 @@ icon: "Avatar"
|
||||||
replies: "Javob berish"
|
replies: "Javob berish"
|
||||||
renotes: "Qayta qayd etish"
|
renotes: "Qayta qayd etish"
|
||||||
flip: "Teskari"
|
flip: "Teskari"
|
||||||
|
_delivery:
|
||||||
|
stop: "To'xtatilgan"
|
||||||
|
_type:
|
||||||
|
none: "Yuborilmoqda"
|
||||||
_achievements:
|
_achievements:
|
||||||
_types:
|
_types:
|
||||||
_viewInstanceChart:
|
_viewInstanceChart:
|
||||||
|
|
|
@ -1118,6 +1118,10 @@ pullDownToRefresh: "Kéo xuống để làm mới"
|
||||||
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
|
cwNotationRequired: "Nếu \"Ẩn nội dung\" được bật thì cần phải có chú thích."
|
||||||
lastNDays: "{n} ngày trước"
|
lastNDays: "{n} ngày trước"
|
||||||
surrender: "Từ chối"
|
surrender: "Từ chối"
|
||||||
|
_delivery:
|
||||||
|
stop: "Đã vô hiệu hóa"
|
||||||
|
_type:
|
||||||
|
none: "Đang đăng"
|
||||||
_announcement:
|
_announcement:
|
||||||
forExistingUsers: "Chỉ những người dùng đã tồn tại"
|
forExistingUsers: "Chỉ những người dùng đã tồn tại"
|
||||||
forExistingUsersDescription: "Nếu được bật, thông báo này sẽ chỉ hiển thị với những người dùng đã tồn tại vào lúc thông báo được tạo. Nếu tắt đi, những tài khoản mới đăng ký sau khi thông báo được đăng lên cũng sẽ thấy nó."
|
forExistingUsersDescription: "Nếu được bật, thông báo này sẽ chỉ hiển thị với những người dùng đã tồn tại vào lúc thông báo được tạo. Nếu tắt đi, những tài khoản mới đăng ký sau khi thông báo được đăng lên cũng sẽ thấy nó."
|
||||||
|
|
|
@ -471,6 +471,7 @@ retype: "重新输入"
|
||||||
noteOf: "{user} 的帖子"
|
noteOf: "{user} 的帖子"
|
||||||
quoteAttached: "已引用"
|
quoteAttached: "已引用"
|
||||||
quoteQuestion: "是否引用此链接内容?"
|
quoteQuestion: "是否引用此链接内容?"
|
||||||
|
attachAsFileQuestion: "剪贴板内的文字过长。要转换为文本文件并添加吗?"
|
||||||
noMessagesYet: "现在没有新的聊天"
|
noMessagesYet: "现在没有新的聊天"
|
||||||
newMessageExists: "新信息"
|
newMessageExists: "新信息"
|
||||||
onlyOneFileCanBeAttached: "只能添加一个附件"
|
onlyOneFileCanBeAttached: "只能添加一个附件"
|
||||||
|
@ -1024,6 +1025,7 @@ thisPostMayBeAnnoyingHome: "发到首页"
|
||||||
thisPostMayBeAnnoyingCancel: "取消"
|
thisPostMayBeAnnoyingCancel: "取消"
|
||||||
thisPostMayBeAnnoyingIgnore: "就这样发布"
|
thisPostMayBeAnnoyingIgnore: "就这样发布"
|
||||||
collapseRenotes: "省略显示已经看过的转发内容"
|
collapseRenotes: "省略显示已经看过的转发内容"
|
||||||
|
collapseRenotesDescription: "将回应过或转贴过的贴子折叠表示。"
|
||||||
internalServerError: "内部服务器错误"
|
internalServerError: "内部服务器错误"
|
||||||
internalServerErrorDescription: "内部服务器发生了预期外的错误"
|
internalServerErrorDescription: "内部服务器发生了预期外的错误"
|
||||||
copyErrorInfo: "复制错误信息"
|
copyErrorInfo: "复制错误信息"
|
||||||
|
@ -1238,6 +1240,15 @@ keepOriginalFilenameDescription: "若关闭此设置,上传文件时文件名
|
||||||
noDescription: "没有描述"
|
noDescription: "没有描述"
|
||||||
alwaysConfirmFollow: "总是确认关注"
|
alwaysConfirmFollow: "总是确认关注"
|
||||||
inquiry: "联系我们"
|
inquiry: "联系我们"
|
||||||
|
_delivery:
|
||||||
|
status: "投递状态"
|
||||||
|
stop: "停止投递"
|
||||||
|
resume: "继续投递"
|
||||||
|
_type:
|
||||||
|
none: "投递中"
|
||||||
|
manuallySuspended: "手动停止中"
|
||||||
|
goneSuspended: "因服务器被删除而停止"
|
||||||
|
autoSuspendedForNotResponding: "因服务器无应答而停止"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "游戏说明"
|
howToPlay: "游戏说明"
|
||||||
hold: "抓住"
|
hold: "抓住"
|
||||||
|
@ -1696,8 +1707,10 @@ _role:
|
||||||
roleAssignedTo: "已分配给手动角色"
|
roleAssignedTo: "已分配给手动角色"
|
||||||
isLocal: "是本地用户"
|
isLocal: "是本地用户"
|
||||||
isRemote: "是远程用户"
|
isRemote: "是远程用户"
|
||||||
|
isCat: "猫猫用户"
|
||||||
isBot: "机器人用户"
|
isBot: "机器人用户"
|
||||||
isSuspended: "停用的用户"
|
isSuspended: "停用的用户"
|
||||||
|
isLocked: "锁推用户"
|
||||||
isExplorable: "启用“使账号可见”的用户"
|
isExplorable: "启用“使账号可见”的用户"
|
||||||
createdLessThan: "账户创建时间少于"
|
createdLessThan: "账户创建时间少于"
|
||||||
createdMoreThan: "账户创建时间超过"
|
createdMoreThan: "账户创建时间超过"
|
||||||
|
@ -2032,7 +2045,6 @@ _permissions:
|
||||||
"read:admin:server-info": "查看服务器信息"
|
"read:admin:server-info": "查看服务器信息"
|
||||||
"read:admin:show-moderation-log": "查看管理日志"
|
"read:admin:show-moderation-log": "查看管理日志"
|
||||||
"read:admin:show-user": "查看用户的非公开信息"
|
"read:admin:show-user": "查看用户的非公开信息"
|
||||||
"read:admin:show-users": "查看用户的非公开信息"
|
|
||||||
"write:admin:suspend-user": "冻结用户"
|
"write:admin:suspend-user": "冻结用户"
|
||||||
"write:admin:unset-user-avatar": "删除用户头像"
|
"write:admin:unset-user-avatar": "删除用户头像"
|
||||||
"write:admin:unset-user-banner": "删除用户横幅"
|
"write:admin:unset-user-banner": "删除用户横幅"
|
||||||
|
|
|
@ -108,11 +108,14 @@ enterEmoji: "輸入表情符號"
|
||||||
renote: "轉發"
|
renote: "轉發"
|
||||||
unrenote: "取消轉發"
|
unrenote: "取消轉發"
|
||||||
renoted: "轉發成功。"
|
renoted: "轉發成功。"
|
||||||
|
renotedToX: "轉發給 {name} 了。"
|
||||||
cantRenote: "無法轉發此貼文。"
|
cantRenote: "無法轉發此貼文。"
|
||||||
cantReRenote: "無法轉發之前已經轉發過的內容。"
|
cantReRenote: "無法轉發之前已經轉發過的內容。"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
inChannelRenote: "在頻道內轉發"
|
inChannelRenote: "在頻道內轉發"
|
||||||
inChannelQuote: "在頻道內引用"
|
inChannelQuote: "在頻道內引用"
|
||||||
|
renoteToChannel: "轉發至頻道"
|
||||||
|
renoteToOtherChannel: "轉發至其他頻道"
|
||||||
pinnedNote: "已置頂的貼文"
|
pinnedNote: "已置頂的貼文"
|
||||||
pinned: "置頂"
|
pinned: "置頂"
|
||||||
you: "您"
|
you: "您"
|
||||||
|
@ -169,7 +172,7 @@ cacheRemoteSensitiveFilesDescription: "若停用這個設定,則不會快取
|
||||||
flagAsBot: "此使用者是機器人"
|
flagAsBot: "此使用者是機器人"
|
||||||
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整 Misskey 內部系統將本帳戶識別為機器人。"
|
flagAsBotDescription: "如果本帳戶是由程式控制,請啟用此選項。啟用後,會作為標示幫助其他開發者防止機器人之間產生無限互動的行為,並會調整 Misskey 內部系統將本帳戶識別為機器人。"
|
||||||
flagAsCat: "此帳戶是一隻貓,喵~~~!!!"
|
flagAsCat: "此帳戶是一隻貓,喵~~~!!!"
|
||||||
flagAsCatDescription: "如果想將本帳戶標示為一隻貓,請開啟此標示"
|
flagAsCatDescription: "喵喵喵??"
|
||||||
flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
|
flagShowTimelineReplies: "在時間軸上顯示貼文的回覆"
|
||||||
flagShowTimelineRepliesDescription: "啟用後,時間軸除了顯示使用者的貼文以外,還會顯示使用者對其他貼文的回覆。"
|
flagShowTimelineRepliesDescription: "啟用後,時間軸除了顯示使用者的貼文以外,還會顯示使用者對其他貼文的回覆。"
|
||||||
autoAcceptFollowed: "自動允許來自追隨中使用者的追隨請求"
|
autoAcceptFollowed: "自動允許來自追隨中使用者的追隨請求"
|
||||||
|
@ -366,7 +369,7 @@ enableRegistration: "開放新使用者註冊"
|
||||||
invite: "邀請"
|
invite: "邀請"
|
||||||
driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
|
driveCapacityPerLocalAccount: "每個本地使用者的雲端硬碟容量"
|
||||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
|
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端空間大小"
|
||||||
inMb: "以Mbps為單位"
|
inMb: "以 MB 為單位"
|
||||||
bannerUrl: "橫幅圖片URL"
|
bannerUrl: "橫幅圖片URL"
|
||||||
backgroundImageUrl: "背景圖片的來源網址 "
|
backgroundImageUrl: "背景圖片的來源網址 "
|
||||||
basicInfo: "基本資訊"
|
basicInfo: "基本資訊"
|
||||||
|
@ -378,12 +381,12 @@ pinnedClipId: "置頂的摘錄ID"
|
||||||
pinnedNotes: "已置頂的貼文"
|
pinnedNotes: "已置頂的貼文"
|
||||||
hcaptcha: "hCaptcha"
|
hcaptcha: "hCaptcha"
|
||||||
enableHcaptcha: "啟用 hCaptcha"
|
enableHcaptcha: "啟用 hCaptcha"
|
||||||
hcaptchaSiteKey: "網站金鑰"
|
hcaptchaSiteKey: "hcaptchaSiteKey"
|
||||||
hcaptchaSecretKey: "金鑰"
|
hcaptchaSecretKey: "hcaptchaSecretKey"
|
||||||
mcaptcha: "mCaptcha"
|
mcaptcha: "mCaptcha"
|
||||||
enableMcaptcha: "啟用 mCaptcha"
|
enableMcaptcha: "啟用 mCaptcha"
|
||||||
mcaptchaSiteKey: "網站金鑰"
|
mcaptchaSiteKey: "網站金鑰"
|
||||||
mcaptchaSecretKey: "金鑰"
|
mcaptchaSecretKey: "私密金鑰"
|
||||||
mcaptchaInstanceUrl: "mCaptcha 的實例網址"
|
mcaptchaInstanceUrl: "mCaptcha 的實例網址"
|
||||||
recaptcha: "reCAPTCHA"
|
recaptcha: "reCAPTCHA"
|
||||||
enableRecaptcha: "啟用 reCAPTCHA"
|
enableRecaptcha: "啟用 reCAPTCHA"
|
||||||
|
@ -391,8 +394,8 @@ recaptchaSiteKey: "網站金鑰"
|
||||||
recaptchaSecretKey: "金鑰"
|
recaptchaSecretKey: "金鑰"
|
||||||
turnstile: "Turnstile"
|
turnstile: "Turnstile"
|
||||||
enableTurnstile: "啟用 Turnstile"
|
enableTurnstile: "啟用 Turnstile"
|
||||||
turnstileSiteKey: "網站金鑰"
|
turnstileSiteKey: "turnstileSiteKey"
|
||||||
turnstileSecretKey: "金鑰"
|
turnstileSecretKey: "turnstileSecretKey"
|
||||||
avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要關閉其他驗證方式嗎?您可以按「取消」保留多種驗證方式。"
|
avoidMultiCaptchaConfirm: "使用多種驗證方式可能會造成干擾,您要關閉其他驗證方式嗎?您可以按「取消」保留多種驗證方式。"
|
||||||
antennas: "天線"
|
antennas: "天線"
|
||||||
manageAntennas: "管理天線"
|
manageAntennas: "管理天線"
|
||||||
|
@ -464,10 +467,11 @@ title: "標題"
|
||||||
text: "文字"
|
text: "文字"
|
||||||
enable: "啟用"
|
enable: "啟用"
|
||||||
next: "下一步"
|
next: "下一步"
|
||||||
retype: "再次輸入"
|
retype: "重新輸入"
|
||||||
noteOf: "{user}的貼文"
|
noteOf: "{user}的貼文"
|
||||||
quoteAttached: "引用"
|
quoteAttached: "引用"
|
||||||
quoteQuestion: "是否要引用?"
|
quoteQuestion: "是否要引用?"
|
||||||
|
attachAsFileQuestion: "剪貼簿的文字較長。請問是否要改成附加檔案呢?"
|
||||||
noMessagesYet: "沒有訊息"
|
noMessagesYet: "沒有訊息"
|
||||||
newMessageExists: "有新的訊息"
|
newMessageExists: "有新的訊息"
|
||||||
onlyOneFileCanBeAttached: "只能加入一個附件"
|
onlyOneFileCanBeAttached: "只能加入一個附件"
|
||||||
|
@ -791,7 +795,7 @@ newVersionOfClientAvailable: "新版本的客戶端可用。"
|
||||||
usageAmount: "使用量"
|
usageAmount: "使用量"
|
||||||
capacity: "容量"
|
capacity: "容量"
|
||||||
inUse: "已使用"
|
inUse: "已使用"
|
||||||
editCode: "編輯代碼"
|
editCode: "編輯程式碼"
|
||||||
apply: "套用"
|
apply: "套用"
|
||||||
receiveAnnouncementFromInstance: "接收來自伺服器的通知"
|
receiveAnnouncementFromInstance: "接收來自伺服器的通知"
|
||||||
emailNotification: "郵件通知"
|
emailNotification: "郵件通知"
|
||||||
|
@ -1077,7 +1081,7 @@ addMemo: "新增備註"
|
||||||
editMemo: "編輯備註"
|
editMemo: "編輯備註"
|
||||||
reactionsList: "反應列表"
|
reactionsList: "反應列表"
|
||||||
renotesList: "轉發貼文列表"
|
renotesList: "轉發貼文列表"
|
||||||
notificationDisplay: "通知的顯示"
|
notificationDisplay: "通知"
|
||||||
leftTop: "左上"
|
leftTop: "左上"
|
||||||
rightTop: "右上"
|
rightTop: "右上"
|
||||||
leftBottom: "左下"
|
leftBottom: "左下"
|
||||||
|
@ -1179,15 +1183,15 @@ repositoryUrlOrTarballRequired: "如果儲存庫不是公開的,則必須提
|
||||||
feedback: "意見回饋"
|
feedback: "意見回饋"
|
||||||
feedbackUrl: "意見回饋 URL"
|
feedbackUrl: "意見回饋 URL"
|
||||||
impressum: "營運者資訊"
|
impressum: "營運者資訊"
|
||||||
impressumUrl: "營運者資訊網址"
|
impressumUrl: "營運者資訊 URL"
|
||||||
impressumDescription: "在德國與部份地區必須要明確顯示營運者資訊。"
|
impressumDescription: "在德國與部份地區必須要明確顯示營運者資訊。"
|
||||||
privacyPolicy: "隱私政策"
|
privacyPolicy: "隱私政策"
|
||||||
privacyPolicyUrl: "隱私政策網址"
|
privacyPolicyUrl: "隱私政策 URL"
|
||||||
tosAndPrivacyPolicy: "服務條款和隱私政策"
|
tosAndPrivacyPolicy: "服務條款和隱私政策"
|
||||||
avatarDecorations: "頭像裝飾"
|
avatarDecorations: "頭像裝飾"
|
||||||
attach: "裝上"
|
attach: "裝上"
|
||||||
detach: "取下"
|
detach: "取下"
|
||||||
detachAll: "移除所有裝飾"
|
detachAll: "全部移除"
|
||||||
angle: "角度"
|
angle: "角度"
|
||||||
flip: "翻轉"
|
flip: "翻轉"
|
||||||
showAvatarDecorations: "顯示頭像裝飾"
|
showAvatarDecorations: "顯示頭像裝飾"
|
||||||
|
@ -1225,16 +1229,25 @@ enableHorizontalSwipe: "滑動切換時間軸"
|
||||||
loading: "載入中"
|
loading: "載入中"
|
||||||
surrender: "退出"
|
surrender: "退出"
|
||||||
gameRetry: "再試一次"
|
gameRetry: "再試一次"
|
||||||
notUsePleaseLeaveBlank: "如不使用,請留空"
|
notUsePleaseLeaveBlank: "如果不使用的話請留白"
|
||||||
useTotp: "使用一次性密碼"
|
useTotp: "使用一次性密碼"
|
||||||
useBackupCode: "使用備用驗證碼"
|
useBackupCode: "使用備用驗證碼"
|
||||||
launchApp: "啟動 App"
|
launchApp: "啟動 APP"
|
||||||
useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊"
|
useNativeUIForVideoAudioPlayer: "使用瀏覽器的 UI 播放影片與音訊"
|
||||||
keepOriginalFilename: "保留原始檔名"
|
keepOriginalFilename: "保留原始檔名"
|
||||||
keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。"
|
keepOriginalFilenameDescription: "如果關閉此設置,上傳時檔案名稱會自動替換為隨機字串。"
|
||||||
noDescription: "沒有說明文字"
|
noDescription: "沒有說明文字"
|
||||||
alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
|
alwaysConfirmFollow: "點擊追隨時總是顯示確認訊息"
|
||||||
inquiry: "聯絡我們"
|
inquiry: "聯絡我們"
|
||||||
|
_delivery:
|
||||||
|
status: "傳送狀態"
|
||||||
|
stop: "已凍結"
|
||||||
|
resume: "繼續傳送"
|
||||||
|
_type:
|
||||||
|
none: "直播中"
|
||||||
|
manuallySuspended: "手動暫停中"
|
||||||
|
goneSuspended: "因為伺服器刪除所以暫停中"
|
||||||
|
autoSuspendedForNotResponding: "因為伺服器沒有回應所以暫停中"
|
||||||
_bubbleGame:
|
_bubbleGame:
|
||||||
howToPlay: "玩法說明"
|
howToPlay: "玩法說明"
|
||||||
hold: "保留"
|
hold: "保留"
|
||||||
|
@ -1243,7 +1256,7 @@ _bubbleGame:
|
||||||
scoreYen: "賺取的金額"
|
scoreYen: "賺取的金額"
|
||||||
highScore: "最高分"
|
highScore: "最高分"
|
||||||
maxChain: "最大結合數"
|
maxChain: "最大結合數"
|
||||||
yen: "{yen} 日圓"
|
yen: "{yen}円"
|
||||||
estimatedQty: "{qty}個"
|
estimatedQty: "{qty}個"
|
||||||
scoreSweets: "飯糰 {onigiriQtyWithUnit}"
|
scoreSweets: "飯糰 {onigiriQtyWithUnit}"
|
||||||
_howToPlay:
|
_howToPlay:
|
||||||
|
@ -1271,7 +1284,7 @@ _initialAccountSetting:
|
||||||
privacySetting: "隱私設定"
|
privacySetting: "隱私設定"
|
||||||
theseSettingsCanEditLater: "這裡的設定可以在之後變更。"
|
theseSettingsCanEditLater: "這裡的設定可以在之後變更。"
|
||||||
youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。"
|
youCanEditMoreSettingsInSettingsPageLater: "除此之外,還可以在「設定」頁面進行各種設定。之後請確認看看。"
|
||||||
followUsers: "為了構築時間軸,試著追蹤您感興趣的使用者吧。"
|
followUsers: "為了構築時間軸,試著追隨您感興趣的使用者吧。"
|
||||||
pushNotificationDescription: "啟用推送通知,就可以在設備上接收{name}的通知。"
|
pushNotificationDescription: "啟用推送通知,就可以在設備上接收{name}的通知。"
|
||||||
initialAccountSettingCompleted: "初始設定完成了!"
|
initialAccountSettingCompleted: "初始設定完成了!"
|
||||||
haveFun: "盡情享受{name}吧!"
|
haveFun: "盡情享受{name}吧!"
|
||||||
|
@ -1326,7 +1339,7 @@ _initialTutorial:
|
||||||
title: "隱藏內容(CW)"
|
title: "隱藏內容(CW)"
|
||||||
description: "將顯示「註釋」中寫入的內容而不是本文。按一下「顯示內容」以顯示本文。"
|
description: "將顯示「註釋」中寫入的內容而不是本文。按一下「顯示內容」以顯示本文。"
|
||||||
_exampleNote:
|
_exampleNote:
|
||||||
cw: "美食恐怖主義注意"
|
cw: "注意消夜文"
|
||||||
note: "我吃了一個巧克力甜甜圈🍩😋"
|
note: "我吃了一個巧克力甜甜圈🍩😋"
|
||||||
useCases: "伺服器的服務條款可能會規範特定的貼文需要使用隱藏內容,除此之外也會用在隱藏劇情洩漏與敏感內容的貼文。"
|
useCases: "伺服器的服務條款可能會規範特定的貼文需要使用隱藏內容,除此之外也會用在隱藏劇情洩漏與敏感內容的貼文。"
|
||||||
_howToMakeAttachmentsSensitive:
|
_howToMakeAttachmentsSensitive:
|
||||||
|
@ -1351,7 +1364,7 @@ _serverRules:
|
||||||
_serverSettings:
|
_serverSettings:
|
||||||
iconUrl: "圖示的 URL"
|
iconUrl: "圖示的 URL"
|
||||||
appIconDescription: "指定顯示 {host} 為應用程式時的圖示。"
|
appIconDescription: "指定顯示 {host} 為應用程式時的圖示。"
|
||||||
appIconUsageExample: "例如:漸進式網路應用程式(PWA)、於手機桌面新增書籤"
|
appIconUsageExample: "例如:PWA 或是在手機桌面作為書籤等"
|
||||||
appIconStyleRecommendation: "因為可能會裁剪成圓形或圓角,所以建議用單色填滿邊框及背景。"
|
appIconStyleRecommendation: "因為可能會裁剪成圓形或圓角,所以建議用單色填滿邊框及背景。"
|
||||||
appIconResolutionMustBe: "解析度必須為 {resolution}。"
|
appIconResolutionMustBe: "解析度必須為 {resolution}。"
|
||||||
manifestJsonOverride: "覆寫 manifest.json"
|
manifestJsonOverride: "覆寫 manifest.json"
|
||||||
|
@ -1559,7 +1572,7 @@ _achievements:
|
||||||
_postedAt0min0sec:
|
_postedAt0min0sec:
|
||||||
title: "報時"
|
title: "報時"
|
||||||
description: "在零分零秒發佈貼文"
|
description: "在零分零秒發佈貼文"
|
||||||
flavor: "啵、啵、啵、嗶ーー"
|
flavor: "啵.啵.啵.嗶ー"
|
||||||
_selfQuote:
|
_selfQuote:
|
||||||
title: "自我引用"
|
title: "自我引用"
|
||||||
description: "引用了自己的貼文"
|
description: "引用了自己的貼文"
|
||||||
|
@ -1694,8 +1707,8 @@ _role:
|
||||||
roleAssignedTo: "手動指派角色完成"
|
roleAssignedTo: "手動指派角色完成"
|
||||||
isLocal: "本地使用者"
|
isLocal: "本地使用者"
|
||||||
isRemote: "遠端使用者"
|
isRemote: "遠端使用者"
|
||||||
isCat: "使用者是貓"
|
isCat: "貓使用者"
|
||||||
isBot: "使用者是機器人"
|
isBot: "機器人使用者"
|
||||||
isSuspended: "被停權的使用者"
|
isSuspended: "被停權的使用者"
|
||||||
isLocked: "上鎖的使用者"
|
isLocked: "上鎖的使用者"
|
||||||
isExplorable: "開啟了「使您的帳戶更容易被找到」功能的使用者"
|
isExplorable: "開啟了「使您的帳戶更容易被找到」功能的使用者"
|
||||||
|
@ -1857,7 +1870,7 @@ _theme:
|
||||||
invalid: "佈景主題格式錯誤"
|
invalid: "佈景主題格式錯誤"
|
||||||
make: "製作佈景主題"
|
make: "製作佈景主題"
|
||||||
base: "基於"
|
base: "基於"
|
||||||
addConstant: "添加常數"
|
addConstant: "新增常數"
|
||||||
constant: "常數"
|
constant: "常數"
|
||||||
defaultValue: "預設值"
|
defaultValue: "預設值"
|
||||||
color: "顏色"
|
color: "顏色"
|
||||||
|
@ -1936,16 +1949,16 @@ _ago:
|
||||||
minutesAgo: "{n}分鐘前"
|
minutesAgo: "{n}分鐘前"
|
||||||
hoursAgo: "{n}小時前"
|
hoursAgo: "{n}小時前"
|
||||||
daysAgo: "{n}天前"
|
daysAgo: "{n}天前"
|
||||||
weeksAgo: "{n} 週前"
|
weeksAgo: "{n}周前"
|
||||||
monthsAgo: "{n}個月前"
|
monthsAgo: "{n}個月前"
|
||||||
yearsAgo: "{n}年前"
|
yearsAgo: "{n}年前"
|
||||||
invalid: "無"
|
invalid: "無"
|
||||||
_timeIn:
|
_timeIn:
|
||||||
seconds: "{n}秒後"
|
seconds: "{n}秒後"
|
||||||
minutes: "{n} 分後"
|
minutes: "{n}分鐘後"
|
||||||
hours: "{n}小時後"
|
hours: "{n}小時後"
|
||||||
days: "{n} 日後"
|
days: "{n}天後"
|
||||||
weeks: "{n} 週後"
|
weeks: "{n}周後"
|
||||||
months: "{n}個月後"
|
months: "{n}個月後"
|
||||||
years: "{n}年後"
|
years: "{n}年後"
|
||||||
_time:
|
_time:
|
||||||
|
@ -2032,7 +2045,6 @@ _permissions:
|
||||||
"read:admin:server-info": "查看伺服器的資訊"
|
"read:admin:server-info": "查看伺服器的資訊"
|
||||||
"read:admin:show-moderation-log": "查看審查紀錄"
|
"read:admin:show-moderation-log": "查看審查紀錄"
|
||||||
"read:admin:show-user": "查看使用者的私密資訊"
|
"read:admin:show-user": "查看使用者的私密資訊"
|
||||||
"read:admin:show-users": "查看使用者的私密資訊"
|
|
||||||
"write:admin:suspend-user": "凍結使用者"
|
"write:admin:suspend-user": "凍結使用者"
|
||||||
"write:admin:unset-user-avatar": "刪除使用者的頭像"
|
"write:admin:unset-user-avatar": "刪除使用者的頭像"
|
||||||
"write:admin:unset-user-banner": "刪除使用者的橫幅"
|
"write:admin:unset-user-banner": "刪除使用者的橫幅"
|
||||||
|
@ -2085,13 +2097,13 @@ _antennaSources:
|
||||||
userList: "來自特定清單中的貼文"
|
userList: "來自特定清單中的貼文"
|
||||||
userBlacklist: "除指定使用者外的所有貼文"
|
userBlacklist: "除指定使用者外的所有貼文"
|
||||||
_weekday:
|
_weekday:
|
||||||
sunday: "週日"
|
sunday: "星期天"
|
||||||
monday: "週一"
|
monday: "星期一"
|
||||||
tuesday: "週二"
|
tuesday: "星期二"
|
||||||
wednesday: "週三"
|
wednesday: "星期三"
|
||||||
thursday: "週四"
|
thursday: "星期四"
|
||||||
friday: "週五"
|
friday: "星期五"
|
||||||
saturday: "週六"
|
saturday: "星期六"
|
||||||
_widgets:
|
_widgets:
|
||||||
profile: "個人檔案"
|
profile: "個人檔案"
|
||||||
instanceInfo: "伺服器資訊"
|
instanceInfo: "伺服器資訊"
|
||||||
|
@ -2173,7 +2185,7 @@ _postForm:
|
||||||
e: "寫些什麼吧……"
|
e: "寫些什麼吧……"
|
||||||
f: "靜待發文……"
|
f: "靜待發文……"
|
||||||
_profile:
|
_profile:
|
||||||
name: "名稱"
|
name: "名字"
|
||||||
username: "使用者名稱"
|
username: "使用者名稱"
|
||||||
description: "關於我"
|
description: "關於我"
|
||||||
youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag"
|
youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag"
|
||||||
|
@ -2247,7 +2259,7 @@ _play:
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "建立頁面"
|
newPage: "建立頁面"
|
||||||
editPage: "編輯頁面"
|
editPage: "編輯頁面"
|
||||||
readPage: "正檢視原始碼"
|
readPage: "正在檢視原始碼"
|
||||||
created: "頁面已建立"
|
created: "頁面已建立"
|
||||||
updated: "頁面已更新"
|
updated: "頁面已更新"
|
||||||
deleted: "頁面已被刪除"
|
deleted: "頁面已被刪除"
|
||||||
|
@ -2274,7 +2286,7 @@ _pages:
|
||||||
hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
|
hideTitleWhenPinned: "被置頂於個人資料時隱藏頁面標題"
|
||||||
font: "字型"
|
font: "字型"
|
||||||
fontSerif: "襯線體"
|
fontSerif: "襯線體"
|
||||||
fontSansSerif: "無襯線體"
|
fontSansSerif: "黑體"
|
||||||
eyeCatchingImageSet: "設定封面影像"
|
eyeCatchingImageSet: "設定封面影像"
|
||||||
eyeCatchingImageRemove: "刪除封面影像"
|
eyeCatchingImageRemove: "刪除封面影像"
|
||||||
chooseBlock: "新增方塊"
|
chooseBlock: "新增方塊"
|
||||||
|
@ -2384,7 +2396,7 @@ _drivecleaner:
|
||||||
orderByCreatedAtAsc: "按新增日期降序排列"
|
orderByCreatedAtAsc: "按新增日期降序排列"
|
||||||
_webhookSettings:
|
_webhookSettings:
|
||||||
createWebhook: "建立 Webhook"
|
createWebhook: "建立 Webhook"
|
||||||
name: "名稱"
|
name: "名字"
|
||||||
secret: "密鑰"
|
secret: "密鑰"
|
||||||
events: "何時運行 Webhook"
|
events: "何時運行 Webhook"
|
||||||
active: "已啟用"
|
active: "已啟用"
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class RemoveAntennaNotify1716450883149 {
|
||||||
|
name = 'RemoveAntennaNotify1716450883149'
|
||||||
|
|
||||||
|
async up(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" DROP COLUMN "notify"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async down(queryRunner) {
|
||||||
|
await queryRunner.query(`ALTER TABLE "antenna" ADD "notify" boolean NOT NULL`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.10.0"
|
"node": "^20.10.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node ./built/boot/entry.js",
|
"start": "node ./built/boot/entry.js",
|
||||||
|
@ -86,6 +86,8 @@
|
||||||
"@nestjs/core": "10.3.8",
|
"@nestjs/core": "10.3.8",
|
||||||
"@nestjs/testing": "10.3.8",
|
"@nestjs/testing": "10.3.8",
|
||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
|
"@sentry/node": "^8.5.0",
|
||||||
|
"@sentry/profiling-node": "^8.5.0",
|
||||||
"@simplewebauthn/server": "10.0.0",
|
"@simplewebauthn/server": "10.0.0",
|
||||||
"@sinonjs/fake-timers": "11.2.2",
|
"@sinonjs/fake-timers": "11.2.2",
|
||||||
"@smithy/node-http-handler": "2.5.0",
|
"@smithy/node-http-handler": "2.5.0",
|
||||||
|
|
|
@ -10,6 +10,8 @@ import * as os from 'node:os';
|
||||||
import cluster from 'node:cluster';
|
import cluster from 'node:cluster';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
import chalkTemplate from 'chalk-template';
|
import chalkTemplate from 'chalk-template';
|
||||||
|
import * as Sentry from '@sentry/node';
|
||||||
|
import { nodeProfilingIntegration } from '@sentry/profiling-node';
|
||||||
import Logger from '@/logger.js';
|
import Logger from '@/logger.js';
|
||||||
import { loadConfig } from '@/config.js';
|
import { loadConfig } from '@/config.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
|
@ -71,6 +73,24 @@ export async function masterMain() {
|
||||||
|
|
||||||
bootLogger.succ('Misskey initialized');
|
bootLogger.succ('Misskey initialized');
|
||||||
|
|
||||||
|
if (config.sentryForBackend) {
|
||||||
|
Sentry.init({
|
||||||
|
integrations: [
|
||||||
|
...(config.sentryForBackend.enableNodeProfiling ? [nodeProfilingIntegration()] : []),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Performance Monitoring
|
||||||
|
tracesSampleRate: 1.0, // Capture 100% of the transactions
|
||||||
|
|
||||||
|
// Set sampling rate for profiling - this is relative to tracesSampleRate
|
||||||
|
profilesSampleRate: 1.0,
|
||||||
|
|
||||||
|
maxBreadcrumbs: 0,
|
||||||
|
|
||||||
|
...config.sentryForBackend.options,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (envOption.disableClustering) {
|
if (envOption.disableClustering) {
|
||||||
if (envOption.onlyServer) {
|
if (envOption.onlyServer) {
|
||||||
await server();
|
await server();
|
||||||
|
|
|
@ -7,6 +7,7 @@ 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 * as Sentry from '@sentry/node';
|
||||||
import type { RedisOptions } from 'ioredis';
|
import type { RedisOptions } from 'ioredis';
|
||||||
|
|
||||||
type RedisOptionsSource = Partial<RedisOptions> & {
|
type RedisOptionsSource = Partial<RedisOptions> & {
|
||||||
|
@ -56,6 +57,8 @@ type Source = {
|
||||||
index: string;
|
index: string;
|
||||||
scope?: 'local' | 'global' | string[];
|
scope?: 'local' | 'global' | string[];
|
||||||
};
|
};
|
||||||
|
sentryForBackend?: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; };
|
||||||
|
sentryForFrontend?: { options: Partial<Sentry.NodeOptions> };
|
||||||
|
|
||||||
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
|
publishTarballInsteadOfProvideRepositoryUrl?: boolean;
|
||||||
|
|
||||||
|
@ -166,6 +169,8 @@ export type Config = {
|
||||||
redisForPubsub: RedisOptions & RedisOptionsSource;
|
redisForPubsub: RedisOptions & RedisOptionsSource;
|
||||||
redisForJobQueue: RedisOptions & RedisOptionsSource;
|
redisForJobQueue: RedisOptions & RedisOptionsSource;
|
||||||
redisForTimelines: RedisOptions & RedisOptionsSource;
|
redisForTimelines: RedisOptions & RedisOptionsSource;
|
||||||
|
sentryForBackend: { options: Partial<Sentry.NodeOptions>; enableNodeProfiling: boolean; } | undefined;
|
||||||
|
sentryForFrontend: { options: Partial<Sentry.NodeOptions> } | undefined;
|
||||||
perChannelMaxNoteCacheCount: number;
|
perChannelMaxNoteCacheCount: number;
|
||||||
perUserNotificationsMaxCount: number;
|
perUserNotificationsMaxCount: number;
|
||||||
deactivateAntennaThreshold: number;
|
deactivateAntennaThreshold: number;
|
||||||
|
@ -234,6 +239,8 @@ export function loadConfig(): Config {
|
||||||
redisForPubsub: config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, host) : redis,
|
redisForPubsub: config.redisForPubsub ? convertRedisOptions(config.redisForPubsub, host) : redis,
|
||||||
redisForJobQueue: config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, host) : redis,
|
redisForJobQueue: config.redisForJobQueue ? convertRedisOptions(config.redisForJobQueue, host) : redis,
|
||||||
redisForTimelines: config.redisForTimelines ? convertRedisOptions(config.redisForTimelines, host) : redis,
|
redisForTimelines: config.redisForTimelines ? convertRedisOptions(config.redisForTimelines, host) : redis,
|
||||||
|
sentryForBackend: config.sentryForBackend,
|
||||||
|
sentryForFrontend: config.sentryForFrontend,
|
||||||
id: config.id,
|
id: config.id,
|
||||||
proxy: config.proxy,
|
proxy: config.proxy,
|
||||||
proxySmtp: config.proxySmtp,
|
proxySmtp: config.proxySmtp,
|
||||||
|
|
|
@ -4,13 +4,14 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets, EntityNotFoundError } from 'typeorm';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead, UsersRepository } from '@/models/_.js';
|
import type { AnnouncementReadsRepository, AnnouncementsRepository, MiAnnouncement, MiAnnouncementRead, UsersRepository } from '@/models/_.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { Packed } from '@/misc/json-schema.js';
|
import { Packed } from '@/misc/json-schema.js';
|
||||||
import { IdService } from '@/core/IdService.js';
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
import { ModerationLogService } from '@/core/ModerationLogService.js';
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ export class AnnouncementService {
|
||||||
private idService: IdService,
|
private idService: IdService,
|
||||||
private globalEventService: GlobalEventService,
|
private globalEventService: GlobalEventService,
|
||||||
private moderationLogService: ModerationLogService,
|
private moderationLogService: ModerationLogService,
|
||||||
|
private announcementEntityService: AnnouncementEntityService,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +81,7 @@ export class AnnouncementService {
|
||||||
userId: values.userId,
|
userId: values.userId,
|
||||||
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
const packed = (await this.packMany([announcement]))[0];
|
const packed = await this.announcementEntityService.pack(announcement);
|
||||||
|
|
||||||
if (values.userId) {
|
if (values.userId) {
|
||||||
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
|
this.globalEventService.publishMainStream(values.userId, 'announcementCreated', {
|
||||||
|
@ -177,6 +179,24 @@ export class AnnouncementService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async getAnnouncement(announcementId: MiAnnouncement['id'], me: MiUser | null): Promise<Packed<'Announcement'>> {
|
||||||
|
const announcement = await this.announcementsRepository.findOneByOrFail({ id: announcementId });
|
||||||
|
if (me) {
|
||||||
|
if (announcement.userId && announcement.userId !== me.id) {
|
||||||
|
throw new EntityNotFoundError(this.announcementsRepository.metadata.target, { id: announcementId });
|
||||||
|
}
|
||||||
|
|
||||||
|
const read = await this.announcementReadsRepository.findOneBy({
|
||||||
|
announcementId: announcement.id,
|
||||||
|
userId: me.id,
|
||||||
|
});
|
||||||
|
return this.announcementEntityService.pack({ ...announcement, isRead: read !== null }, me);
|
||||||
|
} else {
|
||||||
|
return this.announcementEntityService.pack(announcement, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> {
|
public async read(user: MiUser, announcementId: MiAnnouncement['id']): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
@ -193,29 +213,4 @@ export class AnnouncementService {
|
||||||
this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
|
this.globalEventService.publishMainStream(user.id, 'readAllAnnouncements');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
|
||||||
public async packMany(
|
|
||||||
announcements: MiAnnouncement[],
|
|
||||||
me?: { id: MiUser['id'] } | null | undefined,
|
|
||||||
options?: {
|
|
||||||
reads?: MiAnnouncementRead[];
|
|
||||||
},
|
|
||||||
): Promise<Packed<'Announcement'>[]> {
|
|
||||||
const reads = me ? (options?.reads ?? await this.getReads(me.id)) : [];
|
|
||||||
return announcements.map(announcement => ({
|
|
||||||
id: announcement.id,
|
|
||||||
createdAt: this.idService.parse(announcement.id).date.toISOString(),
|
|
||||||
updatedAt: announcement.updatedAt?.toISOString() ?? null,
|
|
||||||
text: announcement.text,
|
|
||||||
title: announcement.title,
|
|
||||||
imageUrl: announcement.imageUrl,
|
|
||||||
icon: announcement.icon,
|
|
||||||
display: announcement.display,
|
|
||||||
needConfirmationToRead: announcement.needConfirmationToRead,
|
|
||||||
silence: announcement.silence,
|
|
||||||
forYou: announcement.userId === me?.id,
|
|
||||||
isRead: reads.some(read => read.announcementId === announcement.id),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ import ApRequestChart from './chart/charts/ap-request.js';
|
||||||
import { ChartManagementService } from './chart/ChartManagementService.js';
|
import { ChartManagementService } from './chart/ChartManagementService.js';
|
||||||
|
|
||||||
import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js';
|
import { AbuseUserReportEntityService } from './entities/AbuseUserReportEntityService.js';
|
||||||
|
import { AnnouncementEntityService } from './entities/AnnouncementEntityService.js';
|
||||||
import { AntennaEntityService } from './entities/AntennaEntityService.js';
|
import { AntennaEntityService } from './entities/AntennaEntityService.js';
|
||||||
import { AppEntityService } from './entities/AppEntityService.js';
|
import { AppEntityService } from './entities/AppEntityService.js';
|
||||||
import { AuthSessionEntityService } from './entities/AuthSessionEntityService.js';
|
import { AuthSessionEntityService } from './entities/AuthSessionEntityService.js';
|
||||||
|
@ -226,6 +227,7 @@ const $ApRequestChart: Provider = { provide: 'ApRequestChart', useExisting: ApRe
|
||||||
const $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService };
|
const $ChartManagementService: Provider = { provide: 'ChartManagementService', useExisting: ChartManagementService };
|
||||||
|
|
||||||
const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
|
const $AbuseUserReportEntityService: Provider = { provide: 'AbuseUserReportEntityService', useExisting: AbuseUserReportEntityService };
|
||||||
|
const $AnnouncementEntityService: Provider = { provide: 'AnnouncementEntityService', useExisting: AnnouncementEntityService };
|
||||||
const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
|
const $AntennaEntityService: Provider = { provide: 'AntennaEntityService', useExisting: AntennaEntityService };
|
||||||
const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
|
const $AppEntityService: Provider = { provide: 'AppEntityService', useExisting: AppEntityService };
|
||||||
const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
|
const $AuthSessionEntityService: Provider = { provide: 'AuthSessionEntityService', useExisting: AuthSessionEntityService };
|
||||||
|
@ -368,6 +370,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
ChartManagementService,
|
ChartManagementService,
|
||||||
|
|
||||||
AbuseUserReportEntityService,
|
AbuseUserReportEntityService,
|
||||||
|
AnnouncementEntityService,
|
||||||
AntennaEntityService,
|
AntennaEntityService,
|
||||||
AppEntityService,
|
AppEntityService,
|
||||||
AuthSessionEntityService,
|
AuthSessionEntityService,
|
||||||
|
@ -506,6 +509,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$ChartManagementService,
|
$ChartManagementService,
|
||||||
|
|
||||||
$AbuseUserReportEntityService,
|
$AbuseUserReportEntityService,
|
||||||
|
$AnnouncementEntityService,
|
||||||
$AntennaEntityService,
|
$AntennaEntityService,
|
||||||
$AppEntityService,
|
$AppEntityService,
|
||||||
$AuthSessionEntityService,
|
$AuthSessionEntityService,
|
||||||
|
@ -644,6 +648,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
ChartManagementService,
|
ChartManagementService,
|
||||||
|
|
||||||
AbuseUserReportEntityService,
|
AbuseUserReportEntityService,
|
||||||
|
AnnouncementEntityService,
|
||||||
AntennaEntityService,
|
AntennaEntityService,
|
||||||
AppEntityService,
|
AppEntityService,
|
||||||
AuthSessionEntityService,
|
AuthSessionEntityService,
|
||||||
|
@ -781,6 +786,7 @@ const $ApQuestionService: Provider = { provide: 'ApQuestionService', useExisting
|
||||||
$ChartManagementService,
|
$ChartManagementService,
|
||||||
|
|
||||||
$AbuseUserReportEntityService,
|
$AbuseUserReportEntityService,
|
||||||
|
$AnnouncementEntityService,
|
||||||
$AntennaEntityService,
|
$AntennaEntityService,
|
||||||
$AppEntityService,
|
$AppEntityService,
|
||||||
$AuthSessionEntityService,
|
$AuthSessionEntityService,
|
||||||
|
|
|
@ -504,6 +504,12 @@ export class DriveService {
|
||||||
|
|
||||||
if (much) {
|
if (much) {
|
||||||
this.registerLogger.info(`file with same hash is found: ${much.id}`);
|
this.registerLogger.info(`file with same hash is found: ${much.id}`);
|
||||||
|
if (sensitive && !much.isSensitive) {
|
||||||
|
// The file is federated as sensitive for this time, but was federated as non-sensitive before.
|
||||||
|
// Therefore, update the file to sensitive.
|
||||||
|
await this.driveFilesRepository.update({ id: much.id }, { isSensitive: true });
|
||||||
|
much.isSensitive = true;
|
||||||
|
}
|
||||||
return much;
|
return much;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ import type { UsersRepository, NotesRepository, FollowingsRepository, AbuseUserR
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import type { MiRemoteUser } from '@/models/User.js';
|
import type { MiRemoteUser } from '@/models/User.js';
|
||||||
import { isNotNull } from '@/misc/is-not-null.js';
|
import { isNotNull } from '@/misc/is-not-null.js';
|
||||||
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
import { getApHrefNullable, getApId, getApIds, getApType, isAccept, isActor, isAdd, isAnnounce, isBlock, isCollection, isCollectionOrOrderedCollection, isCreate, isDelete, isFlag, isFollow, isLike, isMove, isPost, isReject, isRemove, isTombstone, isUndo, isUpdate, validActor, validPost } from './type.js';
|
||||||
import { ApNoteService } from './models/ApNoteService.js';
|
import { ApNoteService } from './models/ApNoteService.js';
|
||||||
import { ApLoggerService } from './ApLoggerService.js';
|
import { ApLoggerService } from './ApLoggerService.js';
|
||||||
|
@ -37,9 +38,8 @@ import { ApResolverService } from './ApResolverService.js';
|
||||||
import { ApAudienceService } from './ApAudienceService.js';
|
import { ApAudienceService } from './ApAudienceService.js';
|
||||||
import { ApPersonService } from './models/ApPersonService.js';
|
import { ApPersonService } from './models/ApPersonService.js';
|
||||||
import { ApQuestionService } from './models/ApQuestionService.js';
|
import { ApQuestionService } from './models/ApQuestionService.js';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
|
||||||
import type { Resolver } from './ApResolverService.js';
|
import type { Resolver } from './ApResolverService.js';
|
||||||
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove } from './type.js';
|
import type { IAccept, IAdd, IAnnounce, IBlock, ICreate, IDelete, IFlag, IFollow, ILike, IObject, IReject, IRemove, IUndo, IUpdate, IMove, IPost } from './type.js';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ApInboxService {
|
export class ApInboxService {
|
||||||
|
@ -92,13 +92,15 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async performActivity(actor: MiRemoteUser, activity: IObject): Promise<void> {
|
public async performActivity(actor: MiRemoteUser, activity: IObject): Promise<string | void> {
|
||||||
|
let result = undefined as string | void;
|
||||||
if (isCollectionOrOrderedCollection(activity)) {
|
if (isCollectionOrOrderedCollection(activity)) {
|
||||||
|
const results = [] as [string, string | void][];
|
||||||
const resolver = this.apResolverService.createResolver();
|
const resolver = this.apResolverService.createResolver();
|
||||||
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
|
for (const item of toArray(isCollection(activity) ? activity.items : activity.orderedItems)) {
|
||||||
const act = await resolver.resolve(item);
|
const act = await resolver.resolve(item);
|
||||||
try {
|
try {
|
||||||
await this.performOneActivity(actor, act);
|
results.push([getApId(item), await this.performOneActivity(actor, act)]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof Error || typeof err === 'string') {
|
if (err instanceof Error || typeof err === 'string') {
|
||||||
this.logger.error(err);
|
this.logger.error(err);
|
||||||
|
@ -107,8 +109,13 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasReason = results.some(([, reason]) => (reason != null && !reason.startsWith('ok')));
|
||||||
|
if (hasReason) {
|
||||||
|
result = results.map(([id, reason]) => `${id}: ${reason}`).join('\n');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await this.performOneActivity(actor, activity);
|
result = await this.performOneActivity(actor, activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ついでにリモートユーザーの情報が古かったら更新しておく
|
// ついでにリモートユーザーの情報が古かったら更新しておく
|
||||||
|
@ -119,42 +126,43 @@ export class ApInboxService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public async performOneActivity(actor: MiRemoteUser, activity: IObject): Promise<void> {
|
public async performOneActivity(actor: MiRemoteUser, activity: IObject): Promise<string | void> {
|
||||||
if (actor.isSuspended) return;
|
if (actor.isSuspended) return;
|
||||||
|
|
||||||
if (isCreate(activity)) {
|
if (isCreate(activity)) {
|
||||||
await this.create(actor, activity);
|
return await this.create(actor, activity);
|
||||||
} else if (isDelete(activity)) {
|
} else if (isDelete(activity)) {
|
||||||
await this.delete(actor, activity);
|
return await this.delete(actor, activity);
|
||||||
} else if (isUpdate(activity)) {
|
} else if (isUpdate(activity)) {
|
||||||
await this.update(actor, activity);
|
return await this.update(actor, activity);
|
||||||
} else if (isFollow(activity)) {
|
} else if (isFollow(activity)) {
|
||||||
await this.follow(actor, activity);
|
return await this.follow(actor, activity);
|
||||||
} else if (isAccept(activity)) {
|
} else if (isAccept(activity)) {
|
||||||
await this.accept(actor, activity);
|
return await this.accept(actor, activity);
|
||||||
} else if (isReject(activity)) {
|
} else if (isReject(activity)) {
|
||||||
await this.reject(actor, activity);
|
return await this.reject(actor, activity);
|
||||||
} else if (isAdd(activity)) {
|
} else if (isAdd(activity)) {
|
||||||
await this.add(actor, activity).catch(err => this.logger.error(err));
|
return await this.add(actor, activity);
|
||||||
} else if (isRemove(activity)) {
|
} else if (isRemove(activity)) {
|
||||||
await this.remove(actor, activity).catch(err => this.logger.error(err));
|
return await this.remove(actor, activity);
|
||||||
} else if (isAnnounce(activity)) {
|
} else if (isAnnounce(activity)) {
|
||||||
await this.announce(actor, activity);
|
return await this.announce(actor, activity);
|
||||||
} else if (isLike(activity)) {
|
} else if (isLike(activity)) {
|
||||||
await this.like(actor, activity);
|
return await this.like(actor, activity);
|
||||||
} else if (isUndo(activity)) {
|
} else if (isUndo(activity)) {
|
||||||
await this.undo(actor, activity);
|
return await this.undo(actor, activity);
|
||||||
} else if (isBlock(activity)) {
|
} else if (isBlock(activity)) {
|
||||||
await this.block(actor, activity);
|
return await this.block(actor, activity);
|
||||||
} else if (isFlag(activity)) {
|
} else if (isFlag(activity)) {
|
||||||
await this.flag(actor, activity);
|
return await this.flag(actor, activity);
|
||||||
} else if (isMove(activity)) {
|
} else if (isMove(activity)) {
|
||||||
await this.move(actor, activity);
|
return await this.move(actor, activity);
|
||||||
} else {
|
} else {
|
||||||
this.logger.warn(`unrecognized activity type: ${activity.type}`);
|
return `unrecognized activity type: ${activity.type}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,38 +244,49 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async add(actor: MiRemoteUser, activity: IAdd): Promise<void> {
|
private async add(actor: MiRemoteUser, activity: IAdd): Promise<string | void> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.target == null) {
|
if (activity.target == null) {
|
||||||
throw new Error('target is null');
|
return 'target is null';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.target === actor.featured) {
|
if (activity.target === actor.featured) {
|
||||||
const note = await this.apNoteService.resolveNote(activity.object);
|
const note = await this.apNoteService.resolveNote(activity.object);
|
||||||
if (note == null) throw new Error('note not found');
|
if (note == null) return 'note not found';
|
||||||
await this.notePiningService.addPinned(actor, note.id);
|
await this.notePiningService.addPinned(actor, note.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`unknown target: ${activity.target}`);
|
return `unknown target: ${activity.target}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async announce(actor: MiRemoteUser, activity: IAnnounce): Promise<void> {
|
private async announce(actor: MiRemoteUser, activity: IAnnounce): Promise<string | void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
this.logger.info(`Announce: ${uri}`);
|
this.logger.info(`Announce: ${uri}`);
|
||||||
|
|
||||||
const targetUri = getApId(activity.object);
|
const resolver = this.apResolverService.createResolver();
|
||||||
|
|
||||||
await this.announceNote(actor, activity, targetUri);
|
if (!activity.object) return 'skip: activity has no object property';
|
||||||
|
const targetUri = getApId(activity.object);
|
||||||
|
if (targetUri.startsWith('bear:')) return 'skip: bearcaps url not supported.';
|
||||||
|
|
||||||
|
const target = await resolver.resolve(activity.object).catch(e => {
|
||||||
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
|
return e;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isPost(target)) return await this.announceNote(actor, activity, target);
|
||||||
|
|
||||||
|
return `skip: unknown object type ${getApType(target)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async announceNote(actor: MiRemoteUser, activity: IAnnounce, targetUri: string): Promise<void> {
|
private async announceNote(actor: MiRemoteUser, activity: IAnnounce, target: IPost): Promise<string | void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
if (actor.isSuspended) {
|
if (actor.isSuspended) {
|
||||||
|
@ -290,24 +309,21 @@ export class ApInboxService {
|
||||||
// Announce対象をresolve
|
// Announce対象をresolve
|
||||||
let renote;
|
let renote;
|
||||||
try {
|
try {
|
||||||
renote = await this.apNoteService.resolveNote(targetUri);
|
renote = await this.apNoteService.resolveNote(target);
|
||||||
if (renote == null) throw new Error('announce target is null');
|
if (renote == null) return 'announce target is null';
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// 対象が4xxならスキップ
|
// 対象が4xxならスキップ
|
||||||
if (err instanceof StatusError) {
|
if (err instanceof StatusError) {
|
||||||
if (!err.isRetryable) {
|
if (!err.isRetryable) {
|
||||||
this.logger.warn(`Ignored announce target ${targetUri} - ${err.statusCode}`);
|
return `Ignored announce target ${target.id} - ${err.statusCode}`;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return `Error in announce target ${target.id} - ${err.statusCode}`;
|
||||||
this.logger.warn(`Error in announce target ${targetUri} - ${err.statusCode}`);
|
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) {
|
if (!await this.noteEntityService.isVisibleForMe(renote, actor.id)) {
|
||||||
this.logger.warn('skip: invalid actor for this activity');
|
return 'skip: invalid actor for this activity';
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.info(`Creating the (Re)Note: ${uri}`);
|
this.logger.info(`Creating the (Re)Note: ${uri}`);
|
||||||
|
@ -316,8 +332,7 @@ export class ApInboxService {
|
||||||
const createdAt = activity.published ? new Date(activity.published) : null;
|
const createdAt = activity.published ? new Date(activity.published) : null;
|
||||||
|
|
||||||
if (createdAt && createdAt < this.idService.parse(renote.id).date) {
|
if (createdAt && createdAt < this.idService.parse(renote.id).date) {
|
||||||
this.logger.warn('skip: malformed createdAt');
|
return 'skip: malformed createdAt';
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.noteCreateService.create(actor, {
|
await this.noteCreateService.create(actor, {
|
||||||
|
@ -351,11 +366,15 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async create(actor: MiRemoteUser, activity: ICreate): Promise<void> {
|
private async create(actor: MiRemoteUser, activity: ICreate): Promise<string | void> {
|
||||||
const uri = getApId(activity);
|
const uri = getApId(activity);
|
||||||
|
|
||||||
this.logger.info(`Create: ${uri}`);
|
this.logger.info(`Create: ${uri}`);
|
||||||
|
|
||||||
|
if (!activity.object) return 'skip: activity has no object property';
|
||||||
|
const targetUri = getApId(activity.object);
|
||||||
|
if (targetUri.startsWith('bear:')) return 'skip: bearcaps url not supported.';
|
||||||
|
|
||||||
// copy audiences between activity <=> object.
|
// copy audiences between activity <=> object.
|
||||||
if (typeof activity.object === 'object') {
|
if (typeof activity.object === 'object') {
|
||||||
const to = unique(concat([toArray(activity.to), toArray(activity.object.to)]));
|
const to = unique(concat([toArray(activity.to), toArray(activity.object.to)]));
|
||||||
|
@ -382,7 +401,7 @@ export class ApInboxService {
|
||||||
if (isPost(object)) {
|
if (isPost(object)) {
|
||||||
await this.createNote(resolver, actor, object, false, activity);
|
await this.createNote(resolver, actor, object, false, activity);
|
||||||
} else {
|
} else {
|
||||||
this.logger.warn(`Unknown type: ${getApType(object)}`);
|
return `Unknown type: ${getApType(object)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,7 +443,7 @@ export class ApInboxService {
|
||||||
@bindThis
|
@bindThis
|
||||||
private async delete(actor: MiRemoteUser, activity: IDelete): Promise<string> {
|
private async delete(actor: MiRemoteUser, activity: IDelete): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 削除対象objectのtype
|
// 削除対象objectのtype
|
||||||
|
@ -583,29 +602,29 @@ export class ApInboxService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async remove(actor: MiRemoteUser, activity: IRemove): Promise<void> {
|
private async remove(actor: MiRemoteUser, activity: IRemove): Promise<string | void> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.target == null) {
|
if (activity.target == null) {
|
||||||
throw new Error('target is null');
|
return 'target is null';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activity.target === actor.featured) {
|
if (activity.target === actor.featured) {
|
||||||
const note = await this.apNoteService.resolveNote(activity.object);
|
const note = await this.apNoteService.resolveNote(activity.object);
|
||||||
if (note == null) throw new Error('note not found');
|
if (note == null) return 'note not found';
|
||||||
await this.notePiningService.removePinned(actor, note.id);
|
await this.notePiningService.removePinned(actor, note.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`unknown target: ${activity.target}`);
|
return `unknown target: ${activity.target}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
private async undo(actor: MiRemoteUser, activity: IUndo): Promise<string> {
|
private async undo(actor: MiRemoteUser, activity: IUndo): Promise<string> {
|
||||||
if (actor.uri !== activity.actor) {
|
if (actor.uri !== activity.actor) {
|
||||||
throw new Error('invalid actor');
|
return 'invalid actor';
|
||||||
}
|
}
|
||||||
|
|
||||||
const uri = activity.id ?? activity;
|
const uri = activity.id ?? activity;
|
||||||
|
@ -616,7 +635,7 @@ export class ApInboxService {
|
||||||
|
|
||||||
const object = await resolver.resolve(activity.object).catch(e => {
|
const object = await resolver.resolve(activity.object).catch(e => {
|
||||||
this.logger.error(`Resolution failed: ${e}`);
|
this.logger.error(`Resolution failed: ${e}`);
|
||||||
throw e;
|
return e;
|
||||||
});
|
});
|
||||||
|
|
||||||
// don't queue because the sender may attempt again when timeout
|
// don't queue because the sender may attempt again when timeout
|
||||||
|
|
|
@ -87,20 +87,20 @@ export class ApNoteService {
|
||||||
const expectHost = this.utilityService.extractDbHost(uri);
|
const expectHost = this.utilityService.extractDbHost(uri);
|
||||||
|
|
||||||
if (!validPost.includes(getApType(object))) {
|
if (!validPost.includes(getApType(object))) {
|
||||||
return new Error(`invalid Note: invalid object type ${getApType(object)}`);
|
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: invalid object type ${getApType(object)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.id && this.utilityService.extractDbHost(object.id) !== expectHost) {
|
if (object.id && this.utilityService.extractDbHost(object.id) !== expectHost) {
|
||||||
return new Error(`invalid Note: id has different host. expected: ${expectHost}, actual: ${this.utilityService.extractDbHost(object.id)}`);
|
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: id has different host. expected: ${expectHost}, actual: ${this.utilityService.extractDbHost(object.id)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const actualHost = object.attributedTo && this.utilityService.extractDbHost(getOneApId(object.attributedTo));
|
const actualHost = object.attributedTo && this.utilityService.extractDbHost(getOneApId(object.attributedTo));
|
||||||
if (object.attributedTo && actualHost !== expectHost) {
|
if (object.attributedTo && actualHost !== expectHost) {
|
||||||
return new Error(`invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${actualHost}`);
|
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', `invalid Note: attributedTo has different host. expected: ${expectHost}, actual: ${actualHost}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (object.published && !this.idService.isSafeT(new Date(object.published).valueOf())) {
|
if (object.published && !this.idService.isSafeT(new Date(object.published).valueOf())) {
|
||||||
return new Error('invalid Note: published timestamp is malformed');
|
return new IdentifiableError('d450b8a9-48e4-4dab-ae36-f4db763fda7c', 'invalid Note: published timestamp is malformed');
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -329,3 +329,4 @@ export const isAnnounce = (object: IObject): object is IAnnounce => getApType(ob
|
||||||
export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block';
|
export const isBlock = (object: IObject): object is IBlock => getApType(object) === 'Block';
|
||||||
export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag';
|
export const isFlag = (object: IObject): object is IFlag => getApType(object) === 'Flag';
|
||||||
export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move';
|
export const isMove = (object: IObject): object is IMove => getApType(object) === 'Move';
|
||||||
|
export const isNote = (object: IObject): object is IPost => getApType(object) === 'Note';
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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 { AnnouncementsRepository, AnnouncementReadsRepository, MiAnnouncement, MiUser } from '@/models/_.js';
|
||||||
|
import type { Packed } from '@/misc/json-schema.js';
|
||||||
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { IdService } from '@/core/IdService.js';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AnnouncementEntityService {
|
||||||
|
constructor(
|
||||||
|
@Inject(DI.announcementsRepository)
|
||||||
|
private announcementsRepository: AnnouncementsRepository,
|
||||||
|
|
||||||
|
@Inject(DI.announcementReadsRepository)
|
||||||
|
private announcementReadsRepository: AnnouncementReadsRepository,
|
||||||
|
|
||||||
|
private idService: IdService,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async pack(
|
||||||
|
src: MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null },
|
||||||
|
me?: { id: MiUser['id'] } | null | undefined,
|
||||||
|
): Promise<Packed<'Announcement'>> {
|
||||||
|
const announcement = typeof src === 'object'
|
||||||
|
? src
|
||||||
|
: await this.announcementsRepository.findOneByOrFail({
|
||||||
|
id: src,
|
||||||
|
}) as MiAnnouncement & { isRead?: boolean | null };
|
||||||
|
|
||||||
|
if (me && announcement.isRead === undefined) {
|
||||||
|
announcement.isRead = await this.announcementReadsRepository
|
||||||
|
.countBy({
|
||||||
|
announcementId: announcement.id,
|
||||||
|
userId: me.id,
|
||||||
|
})
|
||||||
|
.then((count: number) => count > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: announcement.id,
|
||||||
|
createdAt: this.idService.parse(announcement.id).date.toISOString(),
|
||||||
|
updatedAt: announcement.updatedAt?.toISOString() ?? null,
|
||||||
|
title: announcement.title,
|
||||||
|
text: announcement.text,
|
||||||
|
imageUrl: announcement.imageUrl,
|
||||||
|
icon: announcement.icon,
|
||||||
|
display: announcement.display,
|
||||||
|
forYou: announcement.userId === me?.id,
|
||||||
|
needConfirmationToRead: announcement.needConfirmationToRead,
|
||||||
|
silence: announcement.silence,
|
||||||
|
isRead: announcement.isRead !== null ? announcement.isRead : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@bindThis
|
||||||
|
public async packMany(
|
||||||
|
announcements: (MiAnnouncement['id'] | MiAnnouncement & { isRead?: boolean | null } | MiAnnouncement)[],
|
||||||
|
me?: { id: MiUser['id'] } | null | undefined,
|
||||||
|
) : Promise<Packed<'Announcement'>[]> {
|
||||||
|
return (await Promise.allSettled(announcements.map(x => this.pack(x, me))))
|
||||||
|
.filter(result => result.status === 'fulfilled')
|
||||||
|
.map(result => (result as PromiseFulfilledResult<Packed<'Announcement'>>).value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,7 +38,6 @@ export class AntennaEntityService {
|
||||||
users: antenna.users,
|
users: antenna.users,
|
||||||
caseSensitive: antenna.caseSensitive,
|
caseSensitive: antenna.caseSensitive,
|
||||||
localOnly: antenna.localOnly,
|
localOnly: antenna.localOnly,
|
||||||
notify: antenna.notify,
|
|
||||||
excludeBots: antenna.excludeBots,
|
excludeBots: antenna.excludeBots,
|
||||||
withReplies: antenna.withReplies,
|
withReplies: antenna.withReplies,
|
||||||
withFile: antenna.withFile,
|
withFile: antenna.withFile,
|
||||||
|
|
|
@ -90,9 +90,6 @@ export class MiAntenna {
|
||||||
})
|
})
|
||||||
public expression: string | null;
|
public expression: string | null;
|
||||||
|
|
||||||
@Column('boolean')
|
|
||||||
public notify: boolean;
|
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column('boolean', {
|
@Column('boolean', {
|
||||||
default: true,
|
default: true,
|
||||||
|
|
|
@ -72,10 +72,6 @@ export const packedAntennaSchema = {
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
notify: {
|
|
||||||
type: 'boolean',
|
|
||||||
optional: false, nullable: false,
|
|
||||||
},
|
|
||||||
excludeBots: {
|
excludeBots: {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
optional: false, nullable: false,
|
optional: false, nullable: false,
|
||||||
|
|
|
@ -84,7 +84,6 @@ export class ExportAntennasProcessorService {
|
||||||
excludeBots: antenna.excludeBots,
|
excludeBots: antenna.excludeBots,
|
||||||
withReplies: antenna.withReplies,
|
withReplies: antenna.withReplies,
|
||||||
withFile: antenna.withFile,
|
withFile: antenna.withFile,
|
||||||
notify: antenna.notify,
|
|
||||||
}));
|
}));
|
||||||
if (antennas.length - 1 !== index) {
|
if (antennas.length - 1 !== index) {
|
||||||
write(', ');
|
write(', ');
|
||||||
|
|
|
@ -47,9 +47,8 @@ const validate = new Ajv().compile({
|
||||||
excludeBots: { type: 'boolean' },
|
excludeBots: { type: 'boolean' },
|
||||||
withReplies: { type: 'boolean' },
|
withReplies: { type: 'boolean' },
|
||||||
withFile: { type: 'boolean' },
|
withFile: { type: 'boolean' },
|
||||||
notify: { type: 'boolean' },
|
|
||||||
},
|
},
|
||||||
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
|
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
|
||||||
});
|
});
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -92,7 +91,6 @@ export class ImportAntennasProcessorService {
|
||||||
excludeBots: antenna.excludeBots,
|
excludeBots: antenna.excludeBots,
|
||||||
withReplies: antenna.withReplies,
|
withReplies: antenna.withReplies,
|
||||||
withFile: antenna.withFile,
|
withFile: antenna.withFile,
|
||||||
notify: antenna.notify,
|
|
||||||
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
this.logger.succ('Antenna created: ' + result.id);
|
this.logger.succ('Antenna created: ' + result.id);
|
||||||
this.globalEventService.publishInternalEvent('antennaCreated', result);
|
this.globalEventService.publishInternalEvent('antennaCreated', result);
|
||||||
|
|
|
@ -204,13 +204,22 @@ export class InboxProcessorService {
|
||||||
|
|
||||||
// アクティビティを処理
|
// アクティビティを処理
|
||||||
try {
|
try {
|
||||||
await this.apInboxService.performActivity(authUser.user, activity);
|
const result = await this.apInboxService.performActivity(authUser.user, activity);
|
||||||
|
if (result && !result.startsWith('ok')) {
|
||||||
|
this.logger.warn(`inbox activity ignored (maybe): id=${activity.id} reason=${result}`);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof IdentifiableError) {
|
if (e instanceof IdentifiableError) {
|
||||||
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') {
|
if (e.id === '689ee33f-f97c-479a-ac49-1b9f8140af99') {
|
||||||
return 'blocked notes with prohibited words';
|
return 'blocked notes with prohibited words';
|
||||||
}
|
}
|
||||||
if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') return 'actor has been suspended';
|
if (e.id === '85ab9bd7-3a41-4530-959d-f07073900109') {
|
||||||
|
return 'actor has been suspended';
|
||||||
|
}
|
||||||
|
if (e.id === 'd450b8a9-48e4-4dab-ae36-f4db763fda7c') { // invalid Note
|
||||||
|
return e.message;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { randomUUID } from 'node:crypto';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import * as stream from 'node:stream/promises';
|
import * as stream from 'node:stream/promises';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import * as Sentry from '@sentry/node';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import { getIpHash } from '@/misc/get-ip-hash.js';
|
import { getIpHash } from '@/misc/get-ip-hash.js';
|
||||||
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
import type { MiLocalUser, MiUser } from '@/models/User.js';
|
||||||
|
@ -17,6 +18,7 @@ import { MetaService } from '@/core/MetaService.js';
|
||||||
import { createTemp } from '@/misc/create-temp.js';
|
import { createTemp } from '@/misc/create-temp.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
import { RoleService } from '@/core/RoleService.js';
|
import { RoleService } from '@/core/RoleService.js';
|
||||||
|
import type { Config } from '@/config.js';
|
||||||
import { ApiError } from './error.js';
|
import { ApiError } from './error.js';
|
||||||
import { RateLimiterService } from './RateLimiterService.js';
|
import { RateLimiterService } from './RateLimiterService.js';
|
||||||
import { ApiLoggerService } from './ApiLoggerService.js';
|
import { ApiLoggerService } from './ApiLoggerService.js';
|
||||||
|
@ -38,6 +40,9 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
private userIpHistoriesClearIntervalId: NodeJS.Timeout;
|
private userIpHistoriesClearIntervalId: NodeJS.Timeout;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
@Inject(DI.config)
|
||||||
|
private config: Config,
|
||||||
|
|
||||||
@Inject(DI.userIpsRepository)
|
@Inject(DI.userIpsRepository)
|
||||||
private userIpsRepository: UserIpsRepository,
|
private userIpsRepository: UserIpsRepository,
|
||||||
|
|
||||||
|
@ -88,6 +93,48 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#onExecError(ep: IEndpoint, data: any, err: Error): void {
|
||||||
|
if (err instanceof ApiError || err instanceof AuthenticationError) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
const errId = randomUUID();
|
||||||
|
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
||||||
|
ep: ep.name,
|
||||||
|
ps: data,
|
||||||
|
e: {
|
||||||
|
message: err.message,
|
||||||
|
code: err.name,
|
||||||
|
stack: err.stack,
|
||||||
|
id: errId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.error(err, errId);
|
||||||
|
|
||||||
|
if (this.config.sentryForBackend) {
|
||||||
|
Sentry.captureMessage(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
||||||
|
extra: {
|
||||||
|
ep: ep.name,
|
||||||
|
ps: data,
|
||||||
|
e: {
|
||||||
|
message: err.message,
|
||||||
|
code: err.name,
|
||||||
|
stack: err.stack,
|
||||||
|
id: errId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ApiError(null, {
|
||||||
|
e: {
|
||||||
|
message: err.message,
|
||||||
|
code: err.name,
|
||||||
|
id: errId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
public handleRequest(
|
public handleRequest(
|
||||||
endpoint: IEndpoint & { exec: any },
|
endpoint: IEndpoint & { exec: any },
|
||||||
|
@ -362,31 +409,11 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||||
}
|
}
|
||||||
|
|
||||||
// API invoking
|
// API invoking
|
||||||
return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => {
|
if (this.config.sentryForBackend) {
|
||||||
if (err instanceof ApiError || err instanceof AuthenticationError) {
|
return await Sentry.startSpan({ name: 'API: ' + ep.name }, () => ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err)));
|
||||||
throw err;
|
|
||||||
} else {
|
} else {
|
||||||
const errId = randomUUID();
|
return await ep.exec(data, user, token, file, request.ip, request.headers).catch((err: Error) => this.#onExecError(ep, data, err));
|
||||||
this.logger.error(`Internal error occurred in ${ep.name}: ${err.message}`, {
|
|
||||||
ep: ep.name,
|
|
||||||
ps: data,
|
|
||||||
e: {
|
|
||||||
message: err.message,
|
|
||||||
code: err.name,
|
|
||||||
stack: err.stack,
|
|
||||||
id: errId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.error(err, errId);
|
|
||||||
throw new ApiError(null, {
|
|
||||||
e: {
|
|
||||||
message: err.message,
|
|
||||||
code: err.name,
|
|
||||||
id: errId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
|
|
@ -89,6 +89,7 @@ import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js'
|
||||||
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
||||||
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
|
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
|
||||||
import * as ep___announcements from './endpoints/announcements.js';
|
import * as ep___announcements from './endpoints/announcements.js';
|
||||||
|
import * as ep___announcements_show from './endpoints/announcements/show.js';
|
||||||
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
||||||
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
||||||
import * as ep___antennas_list from './endpoints/antennas/list.js';
|
import * as ep___antennas_list from './endpoints/antennas/list.js';
|
||||||
|
@ -475,6 +476,7 @@ const $admin_roles_unassign: Provider = { provide: 'ep:admin/roles/unassign', us
|
||||||
const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default };
|
const $admin_roles_updateDefaultPolicies: Provider = { provide: 'ep:admin/roles/update-default-policies', useClass: ep___admin_roles_updateDefaultPolicies.default };
|
||||||
const $admin_roles_users: Provider = { provide: 'ep:admin/roles/users', useClass: ep___admin_roles_users.default };
|
const $admin_roles_users: Provider = { provide: 'ep:admin/roles/users', useClass: ep___admin_roles_users.default };
|
||||||
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
|
const $announcements: Provider = { provide: 'ep:announcements', useClass: ep___announcements.default };
|
||||||
|
const $announcements_show: Provider = { provide: 'ep:announcements/show', useClass: ep___announcements_show.default };
|
||||||
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
|
const $antennas_create: Provider = { provide: 'ep:antennas/create', useClass: ep___antennas_create.default };
|
||||||
const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
|
const $antennas_delete: Provider = { provide: 'ep:antennas/delete', useClass: ep___antennas_delete.default };
|
||||||
const $antennas_list: Provider = { provide: 'ep:antennas/list', useClass: ep___antennas_list.default };
|
const $antennas_list: Provider = { provide: 'ep:antennas/list', useClass: ep___antennas_list.default };
|
||||||
|
@ -865,6 +867,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$admin_roles_updateDefaultPolicies,
|
$admin_roles_updateDefaultPolicies,
|
||||||
$admin_roles_users,
|
$admin_roles_users,
|
||||||
$announcements,
|
$announcements,
|
||||||
|
$announcements_show,
|
||||||
$antennas_create,
|
$antennas_create,
|
||||||
$antennas_delete,
|
$antennas_delete,
|
||||||
$antennas_list,
|
$antennas_list,
|
||||||
|
@ -1250,6 +1253,7 @@ const $reversi_verify: Provider = { provide: 'ep:reversi/verify', useClass: ep__
|
||||||
$admin_roles_updateDefaultPolicies,
|
$admin_roles_updateDefaultPolicies,
|
||||||
$admin_roles_users,
|
$admin_roles_users,
|
||||||
$announcements,
|
$announcements,
|
||||||
|
$announcements_show,
|
||||||
$antennas_create,
|
$antennas_create,
|
||||||
$antennas_delete,
|
$antennas_delete,
|
||||||
$antennas_list,
|
$antennas_list,
|
||||||
|
|
|
@ -91,6 +91,7 @@ import * as ep___admin_roles_unassign from './endpoints/admin/roles/unassign.js'
|
||||||
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
import * as ep___admin_roles_updateDefaultPolicies from './endpoints/admin/roles/update-default-policies.js';
|
||||||
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
|
import * as ep___admin_roles_users from './endpoints/admin/roles/users.js';
|
||||||
import * as ep___announcements from './endpoints/announcements.js';
|
import * as ep___announcements from './endpoints/announcements.js';
|
||||||
|
import * as ep___announcements_show from './endpoints/announcements/show.js';
|
||||||
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
import * as ep___antennas_create from './endpoints/antennas/create.js';
|
||||||
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
import * as ep___antennas_delete from './endpoints/antennas/delete.js';
|
||||||
import * as ep___antennas_list from './endpoints/antennas/list.js';
|
import * as ep___antennas_list from './endpoints/antennas/list.js';
|
||||||
|
@ -474,6 +475,7 @@ const eps = [
|
||||||
['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
|
['admin/roles/update-default-policies', ep___admin_roles_updateDefaultPolicies],
|
||||||
['admin/roles/users', ep___admin_roles_users],
|
['admin/roles/users', ep___admin_roles_users],
|
||||||
['announcements', ep___announcements],
|
['announcements', ep___announcements],
|
||||||
|
['announcements/show', ep___announcements_show],
|
||||||
['antennas/create', ep___antennas_create],
|
['antennas/create', ep___antennas_create],
|
||||||
['antennas/delete', ep___antennas_delete],
|
['antennas/delete', ep___antennas_delete],
|
||||||
['antennas/list', ep___antennas_list],
|
['antennas/list', ep___antennas_list],
|
||||||
|
|
|
@ -7,9 +7,9 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Brackets } from 'typeorm';
|
import { Brackets } from 'typeorm';
|
||||||
import { Endpoint } from '@/server/api/endpoint-base.js';
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
import { QueryService } from '@/core/QueryService.js';
|
import { QueryService } from '@/core/QueryService.js';
|
||||||
import { AnnouncementService } from '@/core/AnnouncementService.js';
|
import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type { AnnouncementReadsRepository, AnnouncementsRepository } from '@/models/_.js';
|
import type { AnnouncementsRepository } from '@/models/_.js';
|
||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['meta'],
|
tags: ['meta'],
|
||||||
|
@ -44,11 +44,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
@Inject(DI.announcementsRepository)
|
@Inject(DI.announcementsRepository)
|
||||||
private announcementsRepository: AnnouncementsRepository,
|
private announcementsRepository: AnnouncementsRepository,
|
||||||
|
|
||||||
@Inject(DI.announcementReadsRepository)
|
|
||||||
private announcementReadsRepository: AnnouncementReadsRepository,
|
|
||||||
|
|
||||||
private queryService: QueryService,
|
private queryService: QueryService,
|
||||||
private announcementService: AnnouncementService,
|
private announcementEntityService: AnnouncementEntityService,
|
||||||
) {
|
) {
|
||||||
super(meta, paramDef, async (ps, me) => {
|
super(meta, paramDef, async (ps, me) => {
|
||||||
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId)
|
||||||
|
@ -60,7 +57,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
|
|
||||||
const announcements = await query.limit(ps.limit).getMany();
|
const announcements = await query.limit(ps.limit).getMany();
|
||||||
|
|
||||||
return this.announcementService.packMany(announcements, me);
|
return this.announcementEntityService.packMany(announcements, me);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { EntityNotFoundError } from 'typeorm';
|
||||||
|
import { Endpoint } from '@/server/api/endpoint-base.js';
|
||||||
|
import { AnnouncementService } from '@/core/AnnouncementService.js';
|
||||||
|
import { ApiError } from '../../error.js';
|
||||||
|
|
||||||
|
export const meta = {
|
||||||
|
tags: ['meta'],
|
||||||
|
|
||||||
|
requireCredential: false,
|
||||||
|
|
||||||
|
res: {
|
||||||
|
type: 'object',
|
||||||
|
optional: false, nullable: false,
|
||||||
|
ref: 'Announcement',
|
||||||
|
},
|
||||||
|
|
||||||
|
errors: {
|
||||||
|
noSuchAnnouncement: {
|
||||||
|
message: 'No such announcement.',
|
||||||
|
code: 'NO_SUCH_ANNOUNCEMENT',
|
||||||
|
id: 'b57b5e1d-4f49-404a-9edb-46b00268f121',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export const paramDef = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
announcementId: { type: 'string', format: 'misskey:id' },
|
||||||
|
},
|
||||||
|
required: ['announcementId'],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-disable-line import/no-default-export
|
||||||
|
constructor(
|
||||||
|
private announcementService: AnnouncementService,
|
||||||
|
) {
|
||||||
|
super(meta, paramDef, async (ps, me) => {
|
||||||
|
try {
|
||||||
|
return await this.announcementService.getAnnouncement(ps.announcementId, me);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof EntityNotFoundError) throw new ApiError(meta.errors.noSuchAnnouncement);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -67,9 +67,8 @@ export const paramDef = {
|
||||||
excludeBots: { type: 'boolean' },
|
excludeBots: { type: 'boolean' },
|
||||||
withReplies: { type: 'boolean' },
|
withReplies: { type: 'boolean' },
|
||||||
withFile: { type: 'boolean' },
|
withFile: { type: 'boolean' },
|
||||||
notify: { type: 'boolean' },
|
|
||||||
},
|
},
|
||||||
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile', 'notify'],
|
required: ['name', 'src', 'keywords', 'excludeKeywords', 'users', 'caseSensitive', 'withReplies', 'withFile'],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
@ -128,7 +127,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
excludeBots: ps.excludeBots,
|
excludeBots: ps.excludeBots,
|
||||||
withReplies: ps.withReplies,
|
withReplies: ps.withReplies,
|
||||||
withFile: ps.withFile,
|
withFile: ps.withFile,
|
||||||
notify: ps.notify,
|
|
||||||
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
|
}).then(x => this.antennasRepository.findOneByOrFail(x.identifiers[0]));
|
||||||
|
|
||||||
this.globalEventService.publishInternalEvent('antennaCreated', antenna);
|
this.globalEventService.publishInternalEvent('antennaCreated', antenna);
|
||||||
|
|
|
@ -66,7 +66,6 @@ export const paramDef = {
|
||||||
excludeBots: { type: 'boolean' },
|
excludeBots: { type: 'boolean' },
|
||||||
withReplies: { type: 'boolean' },
|
withReplies: { type: 'boolean' },
|
||||||
withFile: { type: 'boolean' },
|
withFile: { type: 'boolean' },
|
||||||
notify: { type: 'boolean' },
|
|
||||||
},
|
},
|
||||||
required: ['antennaId'],
|
required: ['antennaId'],
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -124,7 +123,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
excludeBots: ps.excludeBots,
|
excludeBots: ps.excludeBots,
|
||||||
withReplies: ps.withReplies,
|
withReplies: ps.withReplies,
|
||||||
withFile: ps.withFile,
|
withFile: ps.withFile,
|
||||||
notify: ps.notify,
|
|
||||||
isActive: true,
|
isActive: true,
|
||||||
lastUsedAt: new Date(),
|
lastUsedAt: new Date(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -501,6 +501,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
private async verifyLink(url: string, user: MiLocalUser) {
|
private async verifyLink(url: string, user: MiLocalUser) {
|
||||||
if (!safeForSql(url)) return;
|
if (!safeForSql(url)) return;
|
||||||
|
|
||||||
|
try {
|
||||||
const html = await this.httpRequestService.getHtml(url);
|
const html = await this.httpRequestService.getHtml(url);
|
||||||
|
|
||||||
const { window } = new JSDOM(html);
|
const { window } = new JSDOM(html);
|
||||||
|
@ -522,5 +523,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.close();
|
||||||
|
} catch (err) {
|
||||||
|
// なにもしない
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -464,7 +464,9 @@ export class ClientServerService {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Atom
|
// Atom
|
||||||
fastify.get<{ Params: { user: string; } }>('/@:user.atom', async (request, reply) => {
|
fastify.get<{ Params: { user?: string; } }>('/@:user.atom', async (request, reply) => {
|
||||||
|
if (request.params.user == null) return await renderBase(reply);
|
||||||
|
|
||||||
const feed = await getFeed(request.params.user);
|
const feed = await getFeed(request.params.user);
|
||||||
|
|
||||||
if (feed) {
|
if (feed) {
|
||||||
|
@ -477,7 +479,9 @@ export class ClientServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// RSS
|
// RSS
|
||||||
fastify.get<{ Params: { user: string; } }>('/@:user.rss', async (request, reply) => {
|
fastify.get<{ Params: { user?: string; } }>('/@:user.rss', async (request, reply) => {
|
||||||
|
if (request.params.user == null) return await renderBase(reply);
|
||||||
|
|
||||||
const feed = await getFeed(request.params.user);
|
const feed = await getFeed(request.params.user);
|
||||||
|
|
||||||
if (feed) {
|
if (feed) {
|
||||||
|
@ -490,7 +494,9 @@ export class ClientServerService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// JSON
|
// JSON
|
||||||
fastify.get<{ Params: { user: string; } }>('/@:user.json', async (request, reply) => {
|
fastify.get<{ Params: { user?: string; } }>('/@:user.json', async (request, reply) => {
|
||||||
|
if (request.params.user == null) return await renderBase(reply);
|
||||||
|
|
||||||
const feed = await getFeed(request.params.user);
|
const feed = await getFeed(request.params.user);
|
||||||
|
|
||||||
if (feed) {
|
if (feed) {
|
||||||
|
|
|
@ -38,7 +38,6 @@ describe('アンテナ', () => {
|
||||||
excludeKeywords: [['']],
|
excludeKeywords: [['']],
|
||||||
keywords: [['keyword']],
|
keywords: [['keyword']],
|
||||||
name: 'test',
|
name: 'test',
|
||||||
notify: false,
|
|
||||||
src: 'all' as const,
|
src: 'all' as const,
|
||||||
userListId: null,
|
userListId: null,
|
||||||
users: [''],
|
users: [''],
|
||||||
|
@ -151,7 +150,6 @@ describe('アンテナ', () => {
|
||||||
isActive: true,
|
isActive: true,
|
||||||
keywords: [['keyword']],
|
keywords: [['keyword']],
|
||||||
name: 'test',
|
name: 'test',
|
||||||
notify: false,
|
|
||||||
src: 'all',
|
src: 'all',
|
||||||
userListId: null,
|
userListId: null,
|
||||||
users: [''],
|
users: [''],
|
||||||
|
@ -219,8 +217,6 @@ describe('アンテナ', () => {
|
||||||
{ parameters: () => ({ withReplies: true }) },
|
{ parameters: () => ({ withReplies: true }) },
|
||||||
{ parameters: () => ({ withFile: false }) },
|
{ parameters: () => ({ withFile: false }) },
|
||||||
{ parameters: () => ({ withFile: true }) },
|
{ parameters: () => ({ withFile: true }) },
|
||||||
{ parameters: () => ({ notify: false }) },
|
|
||||||
{ parameters: () => ({ notify: true }) },
|
|
||||||
];
|
];
|
||||||
test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
|
test.each(antennaParamPattern)('を作成できること($#)', async ({ parameters }) => {
|
||||||
const response = await successfulApiCall({
|
const response = await successfulApiCall({
|
||||||
|
|
|
@ -191,7 +191,6 @@ describe('Account Move', () => {
|
||||||
localOnly: false,
|
localOnly: false,
|
||||||
withReplies: false,
|
withReplies: false,
|
||||||
withFile: false,
|
withFile: false,
|
||||||
notify: false,
|
|
||||||
}, alice);
|
}, alice);
|
||||||
antennaId = antenna.body.id;
|
antennaId = antenna.body.id;
|
||||||
|
|
||||||
|
@ -435,7 +434,6 @@ describe('Account Move', () => {
|
||||||
localOnly: false,
|
localOnly: false,
|
||||||
withReplies: false,
|
withReplies: false,
|
||||||
withFile: false,
|
withFile: false,
|
||||||
notify: false,
|
|
||||||
}, alice);
|
}, alice);
|
||||||
|
|
||||||
assert.strictEqual(res.status, 403);
|
assert.strictEqual(res.status, 403);
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { ModuleMocker } from 'jest-mock';
|
||||||
import { Test } from '@nestjs/testing';
|
import { Test } from '@nestjs/testing';
|
||||||
import { GlobalModule } from '@/GlobalModule.js';
|
import { GlobalModule } from '@/GlobalModule.js';
|
||||||
import { AnnouncementService } from '@/core/AnnouncementService.js';
|
import { AnnouncementService } from '@/core/AnnouncementService.js';
|
||||||
|
import { AnnouncementEntityService } from '@/core/entities/AnnouncementEntityService.js';
|
||||||
import type {
|
import type {
|
||||||
AnnouncementReadsRepository,
|
AnnouncementReadsRepository,
|
||||||
AnnouncementsRepository,
|
AnnouncementsRepository,
|
||||||
|
@ -67,6 +68,7 @@ describe('AnnouncementService', () => {
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
AnnouncementService,
|
AnnouncementService,
|
||||||
|
AnnouncementEntityService,
|
||||||
CacheService,
|
CacheService,
|
||||||
IdService,
|
IdService,
|
||||||
],
|
],
|
||||||
|
|
|
@ -11,6 +11,7 @@ export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, ()
|
||||||
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
|
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));
|
||||||
export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
|
export const userListsCache = new Cache<Misskey.entities.UserList[]>(1000 * 60 * 30, () => misskeyApi('users/lists/list'));
|
||||||
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
|
export const antennasCache = new Cache<Misskey.entities.Antenna[]>(1000 * 60 * 30, () => misskeyApi('antennas/list'));
|
||||||
|
export const favoritedChannelsCache = new Cache<Misskey.entities.Channel[]>(1000 * 60 * 30, () => misskeyApi('channels/my-favorites', { limit: 100 }));
|
||||||
export const userFavoriteListsCache = new Cache(1000 * 60 * 30, () => misskeyApi('users/lists/list-favorite'));
|
export const userFavoriteListsCache = new Cache(1000 * 60 * 30, () => misskeyApi('users/lists/list-favorite'));
|
||||||
export const userChannelsCache = new Cache<Misskey.entities.UserChannel[]>(1000 * 60 * 30, () => misskeyApi('channels/owned'));
|
export const userChannelsCache = new Cache<Misskey.entities.UserChannel[]>(1000 * 60 * 30, () => misskeyApi('channels/owned'));
|
||||||
export const userChannelFollowingsCache = new Cache<Misskey.entities.UserChannelFollowing[]>(1000 * 60 * 30, () => misskeyApi('channels/followed'));
|
export const userChannelFollowingsCache = new Cache<Misskey.entities.UserChannelFollowing[]>(1000 * 60 * 30, () => misskeyApi('channels/followed'));
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<MkButton inline rounded primary @click="selectButton($event)">{{ i18n.ts.selectFile }}</MkButton>
|
||||||
|
<div :class="['_nowrap', !fileName && $style.fileNotSelected]">{{ friendlyFileName }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import { selectFile } from '@/scripts/select-file.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
fileId?: string | null;
|
||||||
|
validate?: (file: Misskey.entities.DriveFile) => Promise<boolean>;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(ev: 'update', result: Misskey.entities.DriveFile): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const fileUrl = ref('');
|
||||||
|
const fileName = ref<string>('');
|
||||||
|
|
||||||
|
const friendlyFileName = computed<string>(() => {
|
||||||
|
if (fileName.value) {
|
||||||
|
return fileName.value;
|
||||||
|
}
|
||||||
|
if (fileUrl.value) {
|
||||||
|
return fileUrl.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i18n.ts.fileNotSelected;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (props.fileId) {
|
||||||
|
misskeyApi('drive/files/show', {
|
||||||
|
fileId: props.fileId,
|
||||||
|
}).then((apiRes) => {
|
||||||
|
fileName.value = apiRes.name;
|
||||||
|
fileUrl.value = apiRes.url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectButton(ev: MouseEvent) {
|
||||||
|
selectFile(ev.currentTarget ?? ev.target).then(async (file) => {
|
||||||
|
if (!file) return;
|
||||||
|
if (props.validate && !await props.validate(file)) return;
|
||||||
|
|
||||||
|
emit('update', file);
|
||||||
|
fileName.value = file.name;
|
||||||
|
fileUrl.value = file.url;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style module>
|
||||||
|
.fileNotSelected {
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--infoWarnFg);
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -21,8 +21,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<MkSpacer :marginMin="20" :marginMax="32">
|
<MkSpacer :marginMin="20" :marginMax="32">
|
||||||
<div v-if="Object.keys(form).filter(item => !form[item].hidden).length > 0" class="_gaps_m">
|
<div v-if="Object.keys(form).filter(item => !form[item].hidden).length > 0" class="_gaps_m">
|
||||||
<template v-for="(v, k) in Object.fromEntries(Object.entries(form).filter(([_, v]) => !('hidden' in v) || 'hidden' in v && !v.hidden))">
|
<template v-for="(v, k) in Object.fromEntries(Object.entries(form))">
|
||||||
<MkInput v-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1">
|
<template v-if="typeof v.hidden == 'function' ? v.hidden(values) : v.hidden"></template>
|
||||||
|
<MkInput v-else-if="v.type === 'number'" v-model="values[k]" type="number" :step="v.step || 1">
|
||||||
<template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template>
|
<template #label><span v-text="v.label || k"></span><span v-if="v.required === false"> ({{ i18n.ts.optional }})</span></template>
|
||||||
<template v-if="v.description" #caption>{{ v.description }}</template>
|
<template v-if="v.description" #caption>{{ v.description }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
@ -53,6 +54,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkButton v-else-if="v.type === 'button'" @click="v.action($event, values)">
|
<MkButton v-else-if="v.type === 'button'" @click="v.action($event, values)">
|
||||||
<span v-text="v.content || k"></span>
|
<span v-text="v.content || k"></span>
|
||||||
</MkButton>
|
</MkButton>
|
||||||
|
<XFile
|
||||||
|
v-else-if="v.type === 'drive-file'"
|
||||||
|
:fileId="v.defaultFileId"
|
||||||
|
:validate="async f => !v.validate || await v.validate(f)"
|
||||||
|
@update="f => values[k] = f"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_fullinfo">
|
<div v-else class="_fullinfo">
|
||||||
|
@ -72,6 +79,7 @@ import MkSelect from './MkSelect.vue';
|
||||||
import MkRange from './MkRange.vue';
|
import MkRange from './MkRange.vue';
|
||||||
import MkButton from './MkButton.vue';
|
import MkButton from './MkButton.vue';
|
||||||
import MkRadios from './MkRadios.vue';
|
import MkRadios from './MkRadios.vue';
|
||||||
|
import XFile from './MkFormDialog.file.vue';
|
||||||
import type { Form } from '@/scripts/form.js';
|
import type { Form } from '@/scripts/form.js';
|
||||||
import MkModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
|
@ -536,7 +536,7 @@ export function waiting(): Promise<void> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function form<F extends Form>(title: string, f: F): Promise<{ canceled: true } | { result: GetFormResultType<F> }> {
|
export function form<F extends Form>(title: string, f: F): Promise<{ canceled: true, result?: undefined } | { canceled?: false, result: GetFormResultType<F> }> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/MkFormDialog.vue')), { title, form: f }, {
|
popup(defineAsyncComponent(() => import('@/components/MkFormDialog.vue')), { title, form: f }, {
|
||||||
done: result => {
|
done: result => {
|
||||||
|
|
|
@ -42,7 +42,7 @@ import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
|
import MkFileListForAdmin from '@/components/MkFileListForAdmin.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { lookupFile } from '@/scripts/admin-lookup.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
|
||||||
|
@ -73,33 +73,10 @@ function clear() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function show(file) {
|
|
||||||
os.pageWindow(`/admin/file/${file.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function find() {
|
|
||||||
const { canceled, result: q } = await os.inputText({
|
|
||||||
title: i18n.ts.fileIdOrUrl,
|
|
||||||
minLength: 1,
|
|
||||||
});
|
|
||||||
if (canceled) return;
|
|
||||||
|
|
||||||
misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
|
|
||||||
show(file);
|
|
||||||
}).catch(err => {
|
|
||||||
if (err.code === 'NO_SUCH_FILE') {
|
|
||||||
os.alert({
|
|
||||||
type: 'error',
|
|
||||||
text: i18n.ts.notFound,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const headerActions = computed(() => [{
|
const headerActions = computed(() => [{
|
||||||
text: i18n.ts.lookup,
|
text: i18n.ts.lookup,
|
||||||
icon: 'ti ti-search',
|
icon: 'ti ti-search',
|
||||||
handler: find,
|
handler: lookupFile,
|
||||||
}, {
|
}, {
|
||||||
text: i18n.ts.clearCachedFiles,
|
text: i18n.ts.clearCachedFiles,
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
|
|
|
@ -33,9 +33,10 @@ import { i18n } from '@/i18n.js';
|
||||||
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
import MkSuperMenu from '@/components/MkSuperMenu.vue';
|
||||||
import MkInfo from '@/components/MkInfo.vue';
|
import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
import { lookup } from '@/scripts/lookup.js';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { lookupUser, lookupUserByEmail } from '@/scripts/lookup-user.js';
|
import { lookupUser, lookupUserByEmail, lookupFile } from '@/scripts/admin-lookup.js';
|
||||||
import { useRouter } from '@/router/supplier.js';
|
import { useRouter } from '@/router/supplier.js';
|
||||||
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
|
import { PageMetadata, definePageMetadata, provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { bannerDark, bannerLight, defaultStore, iconDark, iconLight } from '@/store.js';
|
import { bannerDark, bannerLight, defaultStore, iconDark, iconLight } from '@/store.js';
|
||||||
|
@ -96,7 +97,7 @@ const menuDef = computed(() => [{
|
||||||
type: 'button',
|
type: 'button',
|
||||||
icon: 'ti ti-search',
|
icon: 'ti ti-search',
|
||||||
text: i18n.ts.lookup,
|
text: i18n.ts.lookup,
|
||||||
action: lookup,
|
action: adminLookup,
|
||||||
}, ...(instance.disableRegistration ? [{
|
}, ...(instance.disableRegistration ? [{
|
||||||
type: 'button',
|
type: 'button',
|
||||||
icon: 'ti ti-user-plus',
|
icon: 'ti ti-user-plus',
|
||||||
|
@ -296,7 +297,7 @@ function invite() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function lookup(ev: MouseEvent) {
|
function adminLookup(ev: MouseEvent) {
|
||||||
os.popupMenu([{
|
os.popupMenu([{
|
||||||
text: i18n.ts.user,
|
text: i18n.ts.user,
|
||||||
icon: 'ti ti-user',
|
icon: 'ti ti-user',
|
||||||
|
@ -309,23 +310,17 @@ function lookup(ev: MouseEvent) {
|
||||||
action: () => {
|
action: () => {
|
||||||
lookupUserByEmail();
|
lookupUserByEmail();
|
||||||
},
|
},
|
||||||
}, {
|
|
||||||
text: i18n.ts.note,
|
|
||||||
icon: 'ti ti-pencil',
|
|
||||||
action: () => {
|
|
||||||
alert('TODO');
|
|
||||||
},
|
|
||||||
}, {
|
}, {
|
||||||
text: i18n.ts.file,
|
text: i18n.ts.file,
|
||||||
icon: 'ti ti-cloud',
|
icon: 'ti ti-cloud',
|
||||||
action: () => {
|
action: () => {
|
||||||
alert('TODO');
|
lookupFile();
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
text: i18n.ts.instance,
|
text: i18n.ts.lookup,
|
||||||
icon: 'ti ti-planet',
|
icon: 'ti ti-world-search',
|
||||||
action: () => {
|
action: () => {
|
||||||
alert('TODO');
|
lookup();
|
||||||
},
|
},
|
||||||
}], ev.currentTarget ?? ev.target);
|
}], ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSelect from '@/components/MkSelect.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkPagination from '@/components/MkPagination.vue';
|
import MkPagination from '@/components/MkPagination.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { lookupUser } from '@/scripts/lookup-user.js';
|
import { lookupUser } from '@/scripts/admin-lookup.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
import MkUserCardMini from '@/components/MkUserCardMini.vue';
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
<!--
|
||||||
|
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
-->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<MkStickyContainer>
|
||||||
|
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||||
|
<MkSpacer :contentMax="800">
|
||||||
|
<Transition
|
||||||
|
:enterActiveClass="defaultStore.state.animation ? $style.fadeEnterActive : ''"
|
||||||
|
:leaveActiveClass="defaultStore.state.animation ? $style.fadeLeaveActive : ''"
|
||||||
|
:enterFromClass="defaultStore.state.animation ? $style.fadeEnterFrom : ''"
|
||||||
|
:leaveToClass="defaultStore.state.animation ? $style.fadeLeaveTo : ''"
|
||||||
|
mode="out-in"
|
||||||
|
>
|
||||||
|
<div v-if="announcement" :key="announcement.id" class="_panel" :class="$style.announcement">
|
||||||
|
<div v-if="announcement.forYou" :class="$style.forYou"><i class="ti ti-pin"></i> {{ i18n.ts.forYou }}</div>
|
||||||
|
<div :class="$style.header">
|
||||||
|
<span v-if="$i && !announcement.silence && !announcement.isRead" style="margin-right: 0.5em;">🆕</span>
|
||||||
|
<span style="margin-right: 0.5em;">
|
||||||
|
<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
|
||||||
|
<i v-else-if="announcement.icon === 'warning'" class="ti ti-alert-triangle" style="color: var(--warn);"></i>
|
||||||
|
<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
|
||||||
|
<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
|
||||||
|
</span>
|
||||||
|
<Mfm :text="announcement.title"/>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.content">
|
||||||
|
<Mfm :text="announcement.text"/>
|
||||||
|
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
|
||||||
|
<div style="margin-top: 8px; opacity: 0.7; font-size: 85%;">
|
||||||
|
{{ i18n.ts.createdAt }}: <MkTime :time="announcement.createdAt" mode="detail"/>
|
||||||
|
</div>
|
||||||
|
<div v-if="announcement.updatedAt" style="opacity: 0.7; font-size: 85%;">
|
||||||
|
{{ i18n.ts.updatedAt }}: <MkTime :time="announcement.updatedAt" mode="detail"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="$i && !announcement.silence && !announcement.isRead" :class="$style.footer">
|
||||||
|
<MkButton primary @click="read(announcement)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<MkError v-else-if="error" @retry="fetch()"/>
|
||||||
|
<MkLoading v-else/>
|
||||||
|
</Transition>
|
||||||
|
</MkSpacer>
|
||||||
|
</MkStickyContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, watch } from 'vue';
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
|
import { $i, updateAccount } from '@/account.js';
|
||||||
|
import { defaultStore } from '@/store.js';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
announcementId: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const announcement = ref<Misskey.entities.Announcement | null>(null);
|
||||||
|
const error = ref<any>(null);
|
||||||
|
const path = computed(() => props.announcementId);
|
||||||
|
|
||||||
|
function fetch() {
|
||||||
|
announcement.value = null;
|
||||||
|
misskeyApi('announcements/show', {
|
||||||
|
announcementId: props.announcementId,
|
||||||
|
}).then(async _announcement => {
|
||||||
|
announcement.value = _announcement;
|
||||||
|
}).catch(err => {
|
||||||
|
error.value = err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function read(target: Misskey.entities.Announcement): Promise<void> {
|
||||||
|
if (target.needConfirmationToRead) {
|
||||||
|
const confirm = await os.confirm({
|
||||||
|
type: 'question',
|
||||||
|
title: i18n.ts._announcement.readConfirmTitle,
|
||||||
|
text: i18n.tsx._announcement.readConfirmText({ title: target.title }),
|
||||||
|
});
|
||||||
|
if (confirm.canceled) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.isRead = true;
|
||||||
|
await misskeyApi('i/read-announcement', { announcementId: target.id });
|
||||||
|
if ($i) {
|
||||||
|
updateAccount({
|
||||||
|
unreadAnnouncements: $i.unreadAnnouncements.filter((a: { id: string; }) => a.id !== target.id),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(() => path.value, fetch, { immediate: true });
|
||||||
|
|
||||||
|
const headerActions = computed(() => []);
|
||||||
|
|
||||||
|
const headerTabs = computed(() => []);
|
||||||
|
|
||||||
|
definePageMetadata(() => ({
|
||||||
|
title: announcement.value ? `${i18n.ts.announcements}: ${announcement.value.title}` : i18n.ts.announcements,
|
||||||
|
icon: 'ti ti-speakerphone',
|
||||||
|
}));
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.announcement {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.forYou {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 90%;
|
||||||
|
white-space: pre;
|
||||||
|
color: #d28a3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 120%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
> img {
|
||||||
|
display: block;
|
||||||
|
max-height: 300px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -21,14 +21,19 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
|
<i v-else-if="announcement.icon === 'error'" class="ti ti-circle-x" style="color: var(--error);"></i>
|
||||||
<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
|
<i v-else-if="announcement.icon === 'success'" class="ti ti-check" style="color: var(--success);"></i>
|
||||||
</span>
|
</span>
|
||||||
<span>{{ announcement.title }}</span>
|
<MkA :to="`/announcements/${announcement.id}`"><span>{{ announcement.title }}</span></MkA>
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.content">
|
<div :class="$style.content">
|
||||||
<Mfm :text="announcement.text"/>
|
<Mfm :text="announcement.text"/>
|
||||||
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
|
<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
|
||||||
<div style="opacity: 0.7; font-size: 85%;">
|
<MkA :to="`/announcements/${announcement.id}`">
|
||||||
<MkTime :time="announcement.updatedAt ?? announcement.createdAt" mode="detail"/>
|
<div style="margin-top: 8px; opacity: 0.7; font-size: 85%;">
|
||||||
|
{{ i18n.ts.createdAt }}: <MkTime :time="announcement.createdAt" mode="detail"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="announcement.updatedAt" style="opacity: 0.7; font-size: 85%;">
|
||||||
|
{{ i18n.ts.updatedAt }}: <MkTime :time="announcement.updatedAt" mode="detail"/>
|
||||||
|
</div>
|
||||||
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="tab !== 'past' && $i && !announcement.silence && !announcement.isRead" :class="$style.footer">
|
<div v-if="tab !== 'past' && $i && !announcement.silence && !announcement.isRead" :class="$style.footer">
|
||||||
<MkButton primary @click="read(announcement)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
|
<MkButton primary @click="read(announcement)"><i class="ti ti-check"></i> {{ i18n.ts.gotIt }}</MkButton>
|
||||||
|
@ -73,24 +78,24 @@ const paginationEl = ref<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
const tab = ref('current');
|
const tab = ref('current');
|
||||||
|
|
||||||
async function read(announcement) {
|
async function read(target) {
|
||||||
if (announcement.needConfirmationToRead) {
|
if (target.needConfirmationToRead) {
|
||||||
const confirm = await os.confirm({
|
const confirm = await os.confirm({
|
||||||
type: 'question',
|
type: 'question',
|
||||||
title: i18n.ts._announcement.readConfirmTitle,
|
title: i18n.ts._announcement.readConfirmTitle,
|
||||||
text: i18n.tsx._announcement.readConfirmText({ title: announcement.title }),
|
text: i18n.tsx._announcement.readConfirmText({ title: target.title }),
|
||||||
});
|
});
|
||||||
if (confirm.canceled) return;
|
if (confirm.canceled) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!paginationEl.value) return;
|
if (!paginationEl.value) return;
|
||||||
paginationEl.value.updateItem(announcement.id, a => {
|
paginationEl.value.updateItem(target.id, a => {
|
||||||
a.isRead = true;
|
a.isRead = true;
|
||||||
return a;
|
return a;
|
||||||
});
|
});
|
||||||
misskeyApi('i/read-announcement', { announcementId: announcement.id });
|
misskeyApi('i/read-announcement', { announcementId: target.id });
|
||||||
updateAccount({
|
updateAccount({
|
||||||
unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== announcement.id),
|
unreadAnnouncements: $i!.unreadAnnouncements.filter(a => a.id !== target.id),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,7 @@ import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import MkNotes from '@/components/MkNotes.vue';
|
import MkNotes from '@/components/MkNotes.vue';
|
||||||
import { url } from '@/config.js';
|
import { url } from '@/config.js';
|
||||||
|
import { favoritedChannelsCache } from '@/cache.js';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/MkInput.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import { defaultStore } from '@/store.js';
|
import { defaultStore } from '@/store.js';
|
||||||
|
@ -152,6 +153,7 @@ function favorite() {
|
||||||
channelId: channel.value.id,
|
channelId: channel.value.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
favorited.value = true;
|
favorited.value = true;
|
||||||
|
favoritedChannelsCache.delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +169,7 @@ async function unfavorite() {
|
||||||
channelId: channel.value.id,
|
channelId: channel.value.id,
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
favorited.value = false;
|
favorited.value = false;
|
||||||
|
favoritedChannelsCache.delete();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkSwitch v-model="localOnly">{{ i18n.ts.localOnly }}</MkSwitch>
|
<MkSwitch v-model="localOnly">{{ i18n.ts.localOnly }}</MkSwitch>
|
||||||
<MkSwitch v-model="caseSensitive">{{ i18n.ts.caseSensitive }}</MkSwitch>
|
<MkSwitch v-model="caseSensitive">{{ i18n.ts.caseSensitive }}</MkSwitch>
|
||||||
<MkSwitch v-model="withFile">{{ i18n.ts.withFileAntenna }}</MkSwitch>
|
<MkSwitch v-model="withFile">{{ i18n.ts.withFileAntenna }}</MkSwitch>
|
||||||
<MkSwitch v-model="notify">{{ i18n.ts.notifyAntenna }}</MkSwitch>
|
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.actions">
|
<div :class="$style.actions">
|
||||||
<MkButton inline primary @click="saveAntenna()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
<MkButton inline primary @click="saveAntenna()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton>
|
||||||
|
@ -82,7 +81,6 @@ const localOnly = ref<boolean>(props.antenna.localOnly);
|
||||||
const excludeBots = ref<boolean>(props.antenna.excludeBots);
|
const excludeBots = ref<boolean>(props.antenna.excludeBots);
|
||||||
const withReplies = ref<boolean>(props.antenna.withReplies);
|
const withReplies = ref<boolean>(props.antenna.withReplies);
|
||||||
const withFile = ref<boolean>(props.antenna.withFile);
|
const withFile = ref<boolean>(props.antenna.withFile);
|
||||||
const notify = ref<boolean>(props.antenna.notify);
|
|
||||||
const userLists = ref<Misskey.entities.UserList[] | null>(null);
|
const userLists = ref<Misskey.entities.UserList[] | null>(null);
|
||||||
|
|
||||||
watch(() => src.value, async () => {
|
watch(() => src.value, async () => {
|
||||||
|
@ -99,7 +97,6 @@ async function saveAntenna() {
|
||||||
excludeBots: excludeBots.value,
|
excludeBots: excludeBots.value,
|
||||||
withReplies: withReplies.value,
|
withReplies: withReplies.value,
|
||||||
withFile: withFile.value,
|
withFile: withFile.value,
|
||||||
notify: notify.value,
|
|
||||||
caseSensitive: caseSensitive.value,
|
caseSensitive: caseSensitive.value,
|
||||||
localOnly: localOnly.value,
|
localOnly: localOnly.value,
|
||||||
users: users.value.trim().split('\n').map(x => x.trim()),
|
users: users.value.trim().split('\n').map(x => x.trim()),
|
||||||
|
|
|
@ -94,6 +94,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div class="_gaps_m">
|
<div class="_gaps_m">
|
||||||
<div class="_gaps_s">
|
<div class="_gaps_s">
|
||||||
|
<MkSwitch v-model="collapseRenotes">
|
||||||
|
<template #label>{{ i18n.ts.collapseRenotes }}</template>
|
||||||
|
<template #caption>{{ i18n.ts.collapseRenotesDescription }}</template>
|
||||||
|
</MkSwitch>
|
||||||
<MkSwitch v-model="showNoteActionsOnlyHover">{{ i18n.ts.showNoteActionsOnlyHover }}</MkSwitch>
|
<MkSwitch v-model="showNoteActionsOnlyHover">{{ i18n.ts.showNoteActionsOnlyHover }}</MkSwitch>
|
||||||
<MkSwitch v-model="showClipButtonInNoteFooter">{{ i18n.ts.showClipButtonInNoteFooter }}</MkSwitch>
|
<MkSwitch v-model="showClipButtonInNoteFooter">{{ i18n.ts.showClipButtonInNoteFooter }}</MkSwitch>
|
||||||
<MkSwitch v-model="collapseRenotes">{{ i18n.ts.collapseRenotes }}</MkSwitch>
|
<MkSwitch v-model="collapseRenotes">{{ i18n.ts.collapseRenotes }}</MkSwitch>
|
||||||
|
|
|
@ -50,7 +50,7 @@ import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||||
import { antennasCache, userFavoriteListsCache, userListsCache } from '@/cache.js';
|
import { antennasCache, userFavoriteListsCache, userListsCache, favoritedChannelsCache } from '@/cache.js';
|
||||||
import { deviceKind } from '@/scripts/device-kind.js';
|
import { deviceKind } from '@/scripts/device-kind.js';
|
||||||
import { deepMerge } from '@/scripts/merge.js';
|
import { deepMerge } from '@/scripts/merge.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
@ -193,9 +193,7 @@ async function chooseAntenna(ev: MouseEvent): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chooseChannel(ev: MouseEvent): Promise<void> {
|
async function chooseChannel(ev: MouseEvent): Promise<void> {
|
||||||
const channels = await misskeyApi('channels/my-favorites', {
|
const channels = await favoritedChannelsCache.fetch();
|
||||||
limit: 100,
|
|
||||||
});
|
|
||||||
const items: MenuItem[] = [
|
const items: MenuItem[] = [
|
||||||
...channels.map(channel => {
|
...channels.map(channel => {
|
||||||
const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null;
|
const lastReadedAt = miLocalStorage.getItemAsJson(`channelLastReadedAt:${channel.id}`) ?? null;
|
||||||
|
|
|
@ -193,6 +193,9 @@ const routes: RouteDef[] = [{
|
||||||
}, {
|
}, {
|
||||||
path: '/announcements',
|
path: '/announcements',
|
||||||
component: page(() => import('@/pages/announcements.vue')),
|
component: page(() => import('@/pages/announcements.vue')),
|
||||||
|
}, {
|
||||||
|
path: '/announcements/:announcementId',
|
||||||
|
component: page(() => import('@/pages/announcement.vue')),
|
||||||
}, {
|
}, {
|
||||||
path: '/about',
|
path: '/about',
|
||||||
component: page(() => import('@/pages/about.vue')),
|
component: page(() => import('@/pages/about.vue')),
|
||||||
|
|
|
@ -63,3 +63,26 @@ export async function lookupUserByEmail() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function lookupFile() {
|
||||||
|
const { canceled, result: q } = await os.inputText({
|
||||||
|
title: i18n.ts.fileIdOrUrl,
|
||||||
|
minLength: 1,
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
const show = (file) => {
|
||||||
|
os.pageWindow(`/admin/file/${file.id}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
misskeyApi('admin/drive/show-file', q.startsWith('http://') || q.startsWith('https://') ? { url: q.trim() } : { fileId: q.trim() }).then(file => {
|
||||||
|
show(file);
|
||||||
|
}).catch(err => {
|
||||||
|
if (err.code === 'NO_SUCH_FILE') {
|
||||||
|
os.alert({
|
||||||
|
type: 'error',
|
||||||
|
text: i18n.ts.notFound,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -3,18 +3,22 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
|
|
||||||
type EnumItem = string | {
|
type EnumItem = string | {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Hidden = boolean | ((v: any) => boolean);
|
||||||
|
|
||||||
export type FormItem = {
|
export type FormItem = {
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'string';
|
type: 'string';
|
||||||
default: string | null;
|
default: string | null;
|
||||||
description?: string;
|
description?: string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: Hidden;
|
||||||
multiline?: boolean;
|
multiline?: boolean;
|
||||||
treatAsMfm?: boolean;
|
treatAsMfm?: boolean;
|
||||||
} | {
|
} | {
|
||||||
|
@ -23,27 +27,27 @@ export type FormItem = {
|
||||||
default: number | null;
|
default: number | null;
|
||||||
description?: string;
|
description?: string;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: Hidden;
|
||||||
step?: number;
|
step?: number;
|
||||||
} | {
|
} | {
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'boolean';
|
type: 'boolean';
|
||||||
default: boolean | null;
|
default: boolean | null;
|
||||||
description?: string;
|
description?: string;
|
||||||
hidden?: boolean;
|
hidden?: Hidden;
|
||||||
} | {
|
} | {
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'enum';
|
type: 'enum';
|
||||||
default: string | null;
|
default: string | null;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: Hidden;
|
||||||
enum: EnumItem[];
|
enum: EnumItem[];
|
||||||
} | {
|
} | {
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'radio';
|
type: 'radio';
|
||||||
default: unknown | null;
|
default: unknown | null;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
hidden?: boolean;
|
hidden?: Hidden;
|
||||||
options: {
|
options: {
|
||||||
label: string;
|
label: string;
|
||||||
value: unknown;
|
value: unknown;
|
||||||
|
@ -58,20 +62,27 @@ export type FormItem = {
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
textConverter?: (value: number) => string;
|
textConverter?: (value: number) => string;
|
||||||
|
hidden?: Hidden;
|
||||||
} | {
|
} | {
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'object';
|
type: 'object';
|
||||||
default: Record<string, unknown> | null;
|
default: Record<string, unknown> | null;
|
||||||
hidden: boolean;
|
hidden: Hidden;
|
||||||
} | {
|
} | {
|
||||||
label?: string;
|
label?: string;
|
||||||
type: 'array';
|
type: 'array';
|
||||||
default: unknown[] | null;
|
default: unknown[] | null;
|
||||||
hidden: boolean;
|
hidden: Hidden;
|
||||||
} | {
|
} | {
|
||||||
type: 'button';
|
type: 'button';
|
||||||
content?: string;
|
content?: string;
|
||||||
|
hidden?: Hidden;
|
||||||
action: (ev: MouseEvent, v: any) => void;
|
action: (ev: MouseEvent, v: any) => void;
|
||||||
|
} | {
|
||||||
|
type: 'drive-file';
|
||||||
|
defaultFileId?: string | null;
|
||||||
|
hidden?: Hidden;
|
||||||
|
validate?: (v: Misskey.entities.DriveFile) => Promise<boolean>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Form = Record<string, FormItem>;
|
export type Form = Record<string, FormItem>;
|
||||||
|
@ -84,8 +95,9 @@ type GetItemType<Item extends FormItem> =
|
||||||
Item['type'] extends 'range' ? number :
|
Item['type'] extends 'range' ? number :
|
||||||
Item['type'] extends 'enum' ? string :
|
Item['type'] extends 'enum' ? string :
|
||||||
Item['type'] extends 'array' ? unknown[] :
|
Item['type'] extends 'array' ? unknown[] :
|
||||||
Item['type'] extends 'object' ? Record<string, unknown>
|
Item['type'] extends 'object' ? Record<string, unknown> :
|
||||||
: never;
|
Item['type'] extends 'drive-file' ? Misskey.entities.DriveFile | undefined :
|
||||||
|
never;
|
||||||
|
|
||||||
export type GetFormResultType<F extends Form> = {
|
export type GetFormResultType<F extends Form> = {
|
||||||
[P in keyof F]: GetItemType<F[P]>;
|
[P in keyof F]: GetItemType<F[P]>;
|
||||||
|
|
|
@ -16,7 +16,7 @@ import { url } from '@/config.js';
|
||||||
import { defaultStore, noteActions } from '@/store.js';
|
import { defaultStore, noteActions } from '@/store.js';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
import { getUserMenu } from '@/scripts/get-user-menu.js';
|
||||||
import { clipsCache } from '@/cache.js';
|
import { clipsCache, favoritedChannelsCache } from '@/cache.js';
|
||||||
import { MenuItem } from '@/types/menu.js';
|
import { MenuItem } from '@/types/menu.js';
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { isSupportShare } from '@/scripts/navigator.js';
|
import { isSupportShare } from '@/scripts/navigator.js';
|
||||||
|
@ -609,9 +609,7 @@ export function getRenoteMenu(props: {
|
||||||
icon: 'ti ti-repeat',
|
icon: 'ti ti-repeat',
|
||||||
text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel,
|
text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel,
|
||||||
children: async () => {
|
children: async () => {
|
||||||
const channels = await misskeyApi('channels/my-favorites', {
|
const channels = await favoritedChannelsCache.fetch();
|
||||||
limit: 30,
|
|
||||||
});
|
|
||||||
return channels.filter((channel) => {
|
return channels.filter((channel) => {
|
||||||
if (!appearNote.channelId) return true;
|
if (!appearNote.channelId) return true;
|
||||||
return channel.id !== appearNote.channelId;
|
return channel.id !== appearNote.channelId;
|
||||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
v-for="announcement in $i.unreadAnnouncements.filter(x => x.display === 'banner')"
|
v-for="announcement in $i.unreadAnnouncements.filter(x => x.display === 'banner')"
|
||||||
:key="announcement.id"
|
:key="announcement.id"
|
||||||
:class="$style.item"
|
:class="$style.item"
|
||||||
to="/announcements"
|
:to="`/announcements/${announcement.id}`"
|
||||||
>
|
>
|
||||||
<span :class="$style.icon">
|
<span :class="$style.icon">
|
||||||
<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
|
<i v-if="announcement.icon === 'info'" class="ti ti-info-circle"></i>
|
||||||
|
|
|
@ -9,18 +9,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
<i class="ti ti-antenna"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MkTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId"/>
|
<MkTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @note="onNote"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef } from 'vue';
|
import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import { updateColumn, Column } from './deck-store.js';
|
import { updateColumn, Column } from './deck-store.js';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
column: Column;
|
column: Column;
|
||||||
|
@ -28,6 +32,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||||
|
const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.column.antennaId == null) {
|
if (props.column.antennaId == null) {
|
||||||
|
@ -35,6 +40,10 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(soundSetting, v => {
|
||||||
|
updateColumn(props.column.id, { soundSetting: v });
|
||||||
|
});
|
||||||
|
|
||||||
async function setAntenna() {
|
async function setAntenna() {
|
||||||
const antennas = await misskeyApi('antennas/list');
|
const antennas = await misskeyApi('antennas/list');
|
||||||
const { canceled, result: antenna } = await os.select({
|
const { canceled, result: antenna } = await os.select({
|
||||||
|
@ -54,7 +63,11 @@ function editAntenna() {
|
||||||
os.pageWindow('my/antennas/' + props.column.antennaId);
|
os.pageWindow('my/antennas/' + props.column.antennaId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = [
|
function onNote() {
|
||||||
|
sound.playMisskeySfxFile(soundSetting.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu: MenuItem[] = [
|
||||||
{
|
{
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.selectAntenna,
|
text: i18n.ts.selectAntenna,
|
||||||
|
@ -65,6 +78,11 @@ const menu = [
|
||||||
text: i18n.ts.editAntenna,
|
text: i18n.ts.editAntenna,
|
||||||
action: editAntenna,
|
action: editAntenna,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'ti ti-bell',
|
||||||
|
text: i18n.ts._deck.newNoteNotificationSettings,
|
||||||
|
action: () => soundSettingsButton(soundSetting),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -13,21 +13,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div style="padding: 8px; text-align: center;">
|
<div style="padding: 8px; text-align: center;">
|
||||||
<MkButton primary gradate rounded inline small @click="post"><i class="ti ti-pencil"></i></MkButton>
|
<MkButton primary gradate rounded inline small @click="post"><i class="ti ti-pencil"></i></MkButton>
|
||||||
</div>
|
</div>
|
||||||
<MkTimeline ref="timeline" src="channel" :channel="column.channelId"/>
|
<MkTimeline ref="timeline" src="channel" :channel="column.channelId" @note="onNote"/>
|
||||||
</template>
|
</template>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { shallowRef } from 'vue';
|
import { ref, shallowRef, watch } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import { updateColumn, Column } from './deck-store.js';
|
import { updateColumn, Column } from './deck-store.js';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
import { favoritedChannelsCache } from '@/cache.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
column: Column;
|
column: Column;
|
||||||
|
@ -36,26 +41,29 @@ const props = defineProps<{
|
||||||
|
|
||||||
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||||
const channel = shallowRef<Misskey.entities.Channel>();
|
const channel = shallowRef<Misskey.entities.Channel>();
|
||||||
|
const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
|
||||||
|
|
||||||
if (props.column.channelId == null) {
|
if (props.column.channelId == null) {
|
||||||
setChannel();
|
setChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setChannel() {
|
watch(soundSetting, v => {
|
||||||
const channels = await misskeyApi('channels/my-favorites', {
|
updateColumn(props.column.id, { soundSetting: v });
|
||||||
limit: 100,
|
|
||||||
});
|
});
|
||||||
const { canceled, result: channel } = await os.select({
|
|
||||||
|
async function setChannel() {
|
||||||
|
const channels = await favoritedChannelsCache.fetch();
|
||||||
|
const { canceled, result: chosenChannel } = await os.select({
|
||||||
title: i18n.ts.selectChannel,
|
title: i18n.ts.selectChannel,
|
||||||
items: channels.map(x => ({
|
items: channels.map(x => ({
|
||||||
value: x, text: x.name,
|
value: x, text: x.name,
|
||||||
})),
|
})),
|
||||||
default: props.column.channelId,
|
default: props.column.channelId,
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled || chosenChannel == null) return;
|
||||||
updateColumn(props.column.id, {
|
updateColumn(props.column.id, {
|
||||||
channelId: channel.id,
|
channelId: chosenChannel.id,
|
||||||
name: channel.name,
|
name: chosenChannel.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,9 +79,17 @@ async function post() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = [{
|
function onNote() {
|
||||||
|
sound.playMisskeySfxFile(soundSetting.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu: MenuItem[] = [{
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.selectChannel,
|
text: i18n.ts.selectChannel,
|
||||||
action: setChannel,
|
action: setChannel,
|
||||||
|
}, {
|
||||||
|
icon: 'ti ti-bell',
|
||||||
|
text: i18n.ts._deck.newNoteNotificationSettings,
|
||||||
|
action: () => soundSettingsButton(soundSetting),
|
||||||
}];
|
}];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { notificationTypes } from 'misskey-js';
|
||||||
import { Storage } from '@/pizzax.js';
|
import { Storage } from '@/pizzax.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { deepClone } from '@/scripts/clone.js';
|
import { deepClone } from '@/scripts/clone.js';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
|
||||||
type ColumnWidget = {
|
type ColumnWidget = {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -33,6 +34,7 @@ export type Column = {
|
||||||
withRenotes?: boolean;
|
withRenotes?: boolean;
|
||||||
withReplies?: boolean;
|
withReplies?: boolean;
|
||||||
onlyFiles?: boolean;
|
onlyFiles?: boolean;
|
||||||
|
soundSetting: SoundStore;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const deckStore = markRaw(new Storage('deck', {
|
export const deckStore = markRaw(new Storage('deck', {
|
||||||
|
|
|
@ -9,7 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
<i class="ti ti-list"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MkTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" :withRenotes="withRenotes"/>
|
<MkTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" :withRenotes="withRenotes" @note="onNote"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -21,6 +21,10 @@ import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
column: Column;
|
column: Column;
|
||||||
|
@ -29,6 +33,7 @@ const props = defineProps<{
|
||||||
|
|
||||||
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||||
const withRenotes = ref(props.column.withRenotes ?? true);
|
const withRenotes = ref(props.column.withRenotes ?? true);
|
||||||
|
const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
|
||||||
|
|
||||||
if (props.column.listId == null) {
|
if (props.column.listId == null) {
|
||||||
setList();
|
setList();
|
||||||
|
@ -40,6 +45,10 @@ watch(withRenotes, v => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(soundSetting, v => {
|
||||||
|
updateColumn(props.column.id, { soundSetting: v });
|
||||||
|
});
|
||||||
|
|
||||||
async function setList() {
|
async function setList() {
|
||||||
const lists = await misskeyApi('users/lists/list');
|
const lists = await misskeyApi('users/lists/list');
|
||||||
const { canceled, result: list } = await os.select({
|
const { canceled, result: list } = await os.select({
|
||||||
|
@ -59,7 +68,11 @@ function editList() {
|
||||||
os.pageWindow('my/lists/' + props.column.listId);
|
os.pageWindow('my/lists/' + props.column.listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = [
|
function onNote() {
|
||||||
|
sound.playMisskeySfxFile(soundSetting.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu: MenuItem[] = [
|
||||||
{
|
{
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.selectList,
|
text: i18n.ts.selectList,
|
||||||
|
@ -75,5 +88,10 @@ const menu = [
|
||||||
text: i18n.ts.showRenotes,
|
text: i18n.ts.showRenotes,
|
||||||
ref: withRenotes,
|
ref: withRenotes,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'ti ti-bell',
|
||||||
|
text: i18n.ts._deck.newNoteNotificationSettings,
|
||||||
|
action: () => soundSettingsButton(soundSetting),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -9,18 +9,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
<i class="ti ti-badge"></i><span style="margin-left: 8px;">{{ column.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MkTimeline v-if="column.roleId" ref="timeline" src="role" :role="column.roleId"/>
|
<MkTimeline v-if="column.roleId" ref="timeline" src="role" :role="column.roleId" @note="onNote"/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, shallowRef } from 'vue';
|
import { onMounted, ref, shallowRef, watch } from 'vue';
|
||||||
import XColumn from './column.vue';
|
import XColumn from './column.vue';
|
||||||
import { updateColumn, Column } from './deck-store.js';
|
import { updateColumn, Column } from './deck-store.js';
|
||||||
import MkTimeline from '@/components/MkTimeline.vue';
|
import MkTimeline from '@/components/MkTimeline.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
import { misskeyApi } from '@/scripts/misskey-api.js';
|
import { misskeyApi } from '@/scripts/misskey-api.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
column: Column;
|
column: Column;
|
||||||
|
@ -28,6 +32,7 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||||
|
const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.column.roleId == null) {
|
if (props.column.roleId == null) {
|
||||||
|
@ -35,6 +40,10 @@ onMounted(() => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(soundSetting, v => {
|
||||||
|
updateColumn(props.column.id, { soundSetting: v });
|
||||||
|
});
|
||||||
|
|
||||||
async function setRole() {
|
async function setRole() {
|
||||||
const roles = (await misskeyApi('roles/list')).filter(x => x.isExplorable);
|
const roles = (await misskeyApi('roles/list')).filter(x => x.isExplorable);
|
||||||
const { canceled, result: role } = await os.select({
|
const { canceled, result: role } = await os.select({
|
||||||
|
@ -50,10 +59,18 @@ async function setRole() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = [{
|
function onNote() {
|
||||||
|
sound.playMisskeySfxFile(soundSetting.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu: MenuItem[] = [{
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.role,
|
text: i18n.ts.role,
|
||||||
action: setRole,
|
action: setRole,
|
||||||
|
}, {
|
||||||
|
icon: 'ti ti-bell',
|
||||||
|
text: i18n.ts._deck.newNoteNotificationSettings,
|
||||||
|
action: () => soundSettingsButton(soundSetting),
|
||||||
}];
|
}];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -29,6 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:withRenotes="withRenotes"
|
:withRenotes="withRenotes"
|
||||||
:withReplies="withReplies"
|
:withReplies="withReplies"
|
||||||
:onlyFiles="onlyFiles"
|
:onlyFiles="onlyFiles"
|
||||||
|
@note="onNote"
|
||||||
/>
|
/>
|
||||||
</XColumn>
|
</XColumn>
|
||||||
</template>
|
</template>
|
||||||
|
@ -42,6 +43,10 @@ import * as os from '@/os.js';
|
||||||
import { $i } from '@/account.js';
|
import { $i } from '@/account.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
|
import { MenuItem } from '@/types/menu.js';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js';
|
||||||
|
import * as sound from '@/scripts/sound.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
column: Column;
|
column: Column;
|
||||||
|
@ -53,6 +58,7 @@ const timeline = shallowRef<InstanceType<typeof MkTimeline>>();
|
||||||
|
|
||||||
const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
|
const isLocalTimelineAvailable = (($i == null && instance.policies.ltlAvailable) || ($i != null && $i.policies.ltlAvailable));
|
||||||
const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
|
const isGlobalTimelineAvailable = (($i == null && instance.policies.gtlAvailable) || ($i != null && $i.policies.gtlAvailable));
|
||||||
|
const soundSetting = ref<SoundStore>(props.column.soundSetting ?? { type: null, volume: 1 });
|
||||||
const withRenotes = ref(props.column.withRenotes ?? true);
|
const withRenotes = ref(props.column.withRenotes ?? true);
|
||||||
const withReplies = ref(props.column.withReplies ?? false);
|
const withReplies = ref(props.column.withReplies ?? false);
|
||||||
const onlyFiles = ref(props.column.onlyFiles ?? false);
|
const onlyFiles = ref(props.column.onlyFiles ?? false);
|
||||||
|
@ -75,6 +81,10 @@ watch(onlyFiles, v => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(soundSetting, v => {
|
||||||
|
updateColumn(props.column.id, { soundSetting: v });
|
||||||
|
});
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.column.tl == null) {
|
if (props.column.tl == null) {
|
||||||
setType();
|
setType();
|
||||||
|
@ -111,10 +121,18 @@ async function setType() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const menu = [{
|
function onNote() {
|
||||||
|
sound.playMisskeySfxFile(soundSetting.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const menu: MenuItem[] = [{
|
||||||
icon: 'ti ti-pencil',
|
icon: 'ti ti-pencil',
|
||||||
text: i18n.ts.timeline,
|
text: i18n.ts.timeline,
|
||||||
action: setType,
|
action: setType,
|
||||||
|
}, {
|
||||||
|
icon: 'ti ti-bell',
|
||||||
|
text: i18n.ts._deck.newNoteNotificationSettings,
|
||||||
|
action: () => soundSettingsButton(soundSetting),
|
||||||
}, {
|
}, {
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showRenotes,
|
text: i18n.ts.showRenotes,
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { Ref } from 'vue';
|
||||||
|
import { SoundStore } from '@/store.js';
|
||||||
|
import { getSoundDuration, playMisskeySfxFile, soundsTypes, SoundType } from '@/scripts/sound.js';
|
||||||
|
import { i18n } from '@/i18n.js';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
|
export async function soundSettingsButton(soundSetting: Ref<SoundStore>): Promise<void> {
|
||||||
|
function getSoundTypeName(f: SoundType): string {
|
||||||
|
switch (f) {
|
||||||
|
case null:
|
||||||
|
return i18n.ts.none;
|
||||||
|
case '_driveFile_':
|
||||||
|
return i18n.ts._soundSettings.driveFile;
|
||||||
|
default:
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { canceled, result } = await os.form(i18n.ts.sound, {
|
||||||
|
type: {
|
||||||
|
type: 'enum',
|
||||||
|
label: i18n.ts.sound,
|
||||||
|
default: soundSetting.value.type ?? 'none',
|
||||||
|
enum: soundsTypes.map(f => ({
|
||||||
|
value: f ?? 'none', label: getSoundTypeName(f),
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
soundFile: {
|
||||||
|
type: 'drive-file',
|
||||||
|
label: i18n.ts.file,
|
||||||
|
defaultFileId: soundSetting.value.type === '_driveFile_' ? soundSetting.value.fileId : null,
|
||||||
|
hidden: v => v.type !== '_driveFile_',
|
||||||
|
validate: async (file: Misskey.entities.DriveFile) => {
|
||||||
|
if (!file.type.startsWith('audio')) {
|
||||||
|
os.alert({
|
||||||
|
type: 'warning',
|
||||||
|
title: i18n.ts._soundSettings.driveFileTypeWarn,
|
||||||
|
text: i18n.ts._soundSettings.driveFileTypeWarnDescription,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const duration = await getSoundDuration(file.url);
|
||||||
|
if (duration >= 2000) {
|
||||||
|
const { canceled } = await os.confirm({
|
||||||
|
type: 'warning',
|
||||||
|
title: i18n.ts._soundSettings.driveFileDurationWarn,
|
||||||
|
text: i18n.ts._soundSettings.driveFileDurationWarnDescription,
|
||||||
|
okText: i18n.ts.continue,
|
||||||
|
cancelText: i18n.ts.cancel,
|
||||||
|
});
|
||||||
|
if (canceled) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
volume: {
|
||||||
|
type: 'range',
|
||||||
|
label: i18n.ts.volume,
|
||||||
|
default: soundSetting.value.volume ?? 1,
|
||||||
|
textConverter: (v) => `${Math.floor(v * 100)}%`,
|
||||||
|
min: 0,
|
||||||
|
max: 1,
|
||||||
|
step: 0.05,
|
||||||
|
},
|
||||||
|
listen: {
|
||||||
|
type: 'button',
|
||||||
|
content: i18n.ts.listen,
|
||||||
|
action: (_, v) => {
|
||||||
|
const sound = buildSoundStore(v);
|
||||||
|
if (!sound) return;
|
||||||
|
playMisskeySfxFile(sound);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (canceled) return;
|
||||||
|
|
||||||
|
const res = buildSoundStore(result);
|
||||||
|
if (res) soundSetting.value = res;
|
||||||
|
|
||||||
|
function buildSoundStore(result: any): SoundStore | null {
|
||||||
|
const type = (result.type === 'none' ? null : result.type) as SoundType;
|
||||||
|
const volume = result.volume as number;
|
||||||
|
const fileId = result.soundFile?.id ?? (soundSetting.value.type === '_driveFile_' ? soundSetting.value.fileId : undefined);
|
||||||
|
const fileUrl = result.soundFile?.url ?? (soundSetting.value.type === '_driveFile_' ? soundSetting.value.fileUrl : undefined);
|
||||||
|
|
||||||
|
if (type === '_driveFile_') {
|
||||||
|
if (!fileUrl || !fileId) {
|
||||||
|
os.alert({
|
||||||
|
type: 'warning',
|
||||||
|
text: i18n.ts._soundSettings.driveFileWarn,
|
||||||
|
});
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return { type, volume, fileId, fileUrl };
|
||||||
|
} else {
|
||||||
|
return { type, volume };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -336,6 +336,12 @@ type AnnouncementsRequest = operations['announcements']['requestBody']['content'
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
|
type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
|
||||||
|
|
||||||
|
// @public (undocumented)
|
||||||
|
type AnnouncementsShowResponse = operations['announcements___show']['responses']['200']['content']['application/json'];
|
||||||
|
|
||||||
// @public (undocumented)
|
// @public (undocumented)
|
||||||
type Antenna = components['schemas']['Antenna'];
|
type Antenna = components['schemas']['Antenna'];
|
||||||
|
|
||||||
|
@ -1224,6 +1230,8 @@ declare namespace entities {
|
||||||
AdminRolesUsersResponse,
|
AdminRolesUsersResponse,
|
||||||
AnnouncementsRequest,
|
AnnouncementsRequest,
|
||||||
AnnouncementsResponse,
|
AnnouncementsResponse,
|
||||||
|
AnnouncementsShowRequest,
|
||||||
|
AnnouncementsShowResponse,
|
||||||
AntennasCreateRequest,
|
AntennasCreateRequest,
|
||||||
AntennasCreateResponse,
|
AntennasCreateResponse,
|
||||||
AntennasDeleteRequest,
|
AntennasDeleteRequest,
|
||||||
|
|
|
@ -851,6 +851,17 @@ declare module '../api.js' {
|
||||||
credential?: string | null,
|
credential?: string | null,
|
||||||
): Promise<SwitchCaseResponseType<E, P>>;
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *No*
|
||||||
|
*/
|
||||||
|
request<E extends 'announcements/show', P extends Endpoints[E]['req']>(
|
||||||
|
endpoint: E,
|
||||||
|
params: P,
|
||||||
|
credential?: string | null,
|
||||||
|
): Promise<SwitchCaseResponseType<E, P>>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* No description provided.
|
* No description provided.
|
||||||
*
|
*
|
||||||
|
|
|
@ -101,6 +101,8 @@ import type {
|
||||||
AdminRolesUsersResponse,
|
AdminRolesUsersResponse,
|
||||||
AnnouncementsRequest,
|
AnnouncementsRequest,
|
||||||
AnnouncementsResponse,
|
AnnouncementsResponse,
|
||||||
|
AnnouncementsShowRequest,
|
||||||
|
AnnouncementsShowResponse,
|
||||||
AntennasCreateRequest,
|
AntennasCreateRequest,
|
||||||
AntennasCreateResponse,
|
AntennasCreateResponse,
|
||||||
AntennasDeleteRequest,
|
AntennasDeleteRequest,
|
||||||
|
@ -631,6 +633,7 @@ export type Endpoints = {
|
||||||
'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse };
|
'admin/roles/update-default-policies': { req: AdminRolesUpdateDefaultPoliciesRequest; res: EmptyResponse };
|
||||||
'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse };
|
'admin/roles/users': { req: AdminRolesUsersRequest; res: AdminRolesUsersResponse };
|
||||||
'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse };
|
'announcements': { req: AnnouncementsRequest; res: AnnouncementsResponse };
|
||||||
|
'announcements/show': { req: AnnouncementsShowRequest; res: AnnouncementsShowResponse };
|
||||||
'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse };
|
'antennas/create': { req: AntennasCreateRequest; res: AntennasCreateResponse };
|
||||||
'antennas/delete': { req: AntennasDeleteRequest; res: EmptyResponse };
|
'antennas/delete': { req: AntennasDeleteRequest; res: EmptyResponse };
|
||||||
'antennas/list': { req: EmptyRequest; res: AntennasListResponse };
|
'antennas/list': { req: EmptyRequest; res: AntennasListResponse };
|
||||||
|
|
|
@ -104,6 +104,8 @@ export type AdminRolesUsersRequest = operations['admin___roles___users']['reques
|
||||||
export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
|
export type AdminRolesUsersResponse = operations['admin___roles___users']['responses']['200']['content']['application/json'];
|
||||||
export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json'];
|
export type AnnouncementsRequest = operations['announcements']['requestBody']['content']['application/json'];
|
||||||
export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
|
export type AnnouncementsResponse = operations['announcements']['responses']['200']['content']['application/json'];
|
||||||
|
export type AnnouncementsShowRequest = operations['announcements___show']['requestBody']['content']['application/json'];
|
||||||
|
export type AnnouncementsShowResponse = operations['announcements___show']['responses']['200']['content']['application/json'];
|
||||||
export type AntennasCreateRequest = operations['antennas___create']['requestBody']['content']['application/json'];
|
export type AntennasCreateRequest = operations['antennas___create']['requestBody']['content']['application/json'];
|
||||||
export type AntennasCreateResponse = operations['antennas___create']['responses']['200']['content']['application/json'];
|
export type AntennasCreateResponse = operations['antennas___create']['responses']['200']['content']['application/json'];
|
||||||
export type AntennasDeleteRequest = operations['antennas___delete']['requestBody']['content']['application/json'];
|
export type AntennasDeleteRequest = operations['antennas___delete']['requestBody']['content']['application/json'];
|
||||||
|
|
|
@ -706,6 +706,15 @@ export type paths = {
|
||||||
*/
|
*/
|
||||||
post: operations['announcements'];
|
post: operations['announcements'];
|
||||||
};
|
};
|
||||||
|
'/announcements/show': {
|
||||||
|
/**
|
||||||
|
* announcements/show
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *No*
|
||||||
|
*/
|
||||||
|
post: operations['announcements___show'];
|
||||||
|
};
|
||||||
'/antennas/create': {
|
'/antennas/create': {
|
||||||
/**
|
/**
|
||||||
* antennas/create
|
* antennas/create
|
||||||
|
@ -4432,7 +4441,6 @@ export type components = {
|
||||||
caseSensitive: boolean;
|
caseSensitive: boolean;
|
||||||
/** @default false */
|
/** @default false */
|
||||||
localOnly: boolean;
|
localOnly: boolean;
|
||||||
notify: boolean;
|
|
||||||
/** @default false */
|
/** @default false */
|
||||||
excludeBots: boolean;
|
excludeBots: boolean;
|
||||||
/** @default false */
|
/** @default false */
|
||||||
|
@ -9663,6 +9671,60 @@ export type operations = {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* announcements/show
|
||||||
|
* @description No description provided.
|
||||||
|
*
|
||||||
|
* **Credential required**: *No*
|
||||||
|
*/
|
||||||
|
announcements___show: {
|
||||||
|
requestBody: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
/** Format: misskey:id */
|
||||||
|
announcementId: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: {
|
||||||
|
/** @description OK (with results) */
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Announcement'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Client error */
|
||||||
|
400: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Authentication error */
|
||||||
|
401: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Forbidden error */
|
||||||
|
403: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description I'm Ai */
|
||||||
|
418: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Internal server error */
|
||||||
|
500: {
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['Error'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* antennas/create
|
* antennas/create
|
||||||
* @description No description provided.
|
* @description No description provided.
|
||||||
|
@ -9686,7 +9748,6 @@ export type operations = {
|
||||||
excludeBots?: boolean;
|
excludeBots?: boolean;
|
||||||
withReplies: boolean;
|
withReplies: boolean;
|
||||||
withFile: boolean;
|
withFile: boolean;
|
||||||
notify: boolean;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -9968,7 +10029,6 @@ export type operations = {
|
||||||
excludeBots?: boolean;
|
excludeBots?: boolean;
|
||||||
withReplies?: boolean;
|
withReplies?: boolean;
|
||||||
withFile?: boolean;
|
withFile?: boolean;
|
||||||
notify?: boolean;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
630
pnpm-lock.yaml
630
pnpm-lock.yaml
|
@ -140,6 +140,12 @@ importers:
|
||||||
'@peertube/http-signature':
|
'@peertube/http-signature':
|
||||||
specifier: 1.7.0
|
specifier: 1.7.0
|
||||||
version: 1.7.0
|
version: 1.7.0
|
||||||
|
'@sentry/node':
|
||||||
|
specifier: ^8.5.0
|
||||||
|
version: 8.5.0
|
||||||
|
'@sentry/profiling-node':
|
||||||
|
specifier: ^8.5.0
|
||||||
|
version: 8.5.0
|
||||||
'@simplewebauthn/server':
|
'@simplewebauthn/server':
|
||||||
specifier: 10.0.0
|
specifier: 10.0.0
|
||||||
version: 10.0.0(encoding@0.1.13)
|
version: 10.0.0(encoding@0.1.13)
|
||||||
|
@ -3282,6 +3288,154 @@ packages:
|
||||||
'@open-draft/until@2.1.0':
|
'@open-draft/until@2.1.0':
|
||||||
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
|
resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==}
|
||||||
|
|
||||||
|
'@opentelemetry/api-logs@0.51.1':
|
||||||
|
resolution: {integrity: sha512-E3skn949Pk1z2XtXu/lxf6QAZpawuTM/IUEXcAzpiUkTd73Hmvw26FiN3cJuTmkpM5hZzHwkomVdtrh/n/zzwA==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
'@opentelemetry/api@1.8.0':
|
||||||
|
resolution: {integrity: sha512-I/s6F7yKUDdtMsoBWXJe8Qz40Tui5vsuKCWJEWVL+5q9sSWRzzx6v2KeNsOBEwd94j0eWkpWCH4yB6rZg9Mf0w==}
|
||||||
|
engines: {node: '>=8.0.0'}
|
||||||
|
|
||||||
|
'@opentelemetry/context-async-hooks@1.24.1':
|
||||||
|
resolution: {integrity: sha512-R5r6DO4kgEOVBxFXhXjwospLQkv+sYxwCfjvoZBe7Zm6KKXAV9kDSJhi/D1BweowdZmO+sdbENLs374gER8hpQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': '>=1.0.0 <1.9.0'
|
||||||
|
|
||||||
|
'@opentelemetry/core@1.24.1':
|
||||||
|
resolution: {integrity: sha512-wMSGfsdmibI88K9wB498zXY04yThPexo8jvwNNlm542HZB7XrrMRBbAyKJqG8qDRJwIBdBrPMi4V9ZPW/sqrcg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': '>=1.0.0 <1.9.0'
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-connect@0.36.0':
|
||||||
|
resolution: {integrity: sha512-k9++bmJZ9zDEs3u3DnKTn2l7QTiNFg3gPx7G9rW0TPnP+xZoBSBTrEcGYBaqflQlrFG23Q58+X1sM2ayWPv5Fg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-express@0.39.0':
|
||||||
|
resolution: {integrity: sha512-AG8U7z7D0JcBu/7dDcwb47UMEzj9/FMiJV2iQZqrsZnxR3FjB9J9oIH2iszJYci2eUdp2WbdvtpD9RV/zmME5A==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-fastify@0.36.1':
|
||||||
|
resolution: {integrity: sha512-3Nfm43PI0I+3EX+1YbSy6xbDu276R1Dh1tqAk68yd4yirnIh52Kd5B+nJ8CgHA7o3UKakpBjj6vSzi5vNCzJIA==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-graphql@0.40.0':
|
||||||
|
resolution: {integrity: sha512-LVRdEHWACWOczv2imD+mhUrLMxsEjPPi32vIZJT57zygR5aUiA4em8X3aiGOCycgbMWkIu8xOSGSxdx3JmzN+w==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-hapi@0.38.0':
|
||||||
|
resolution: {integrity: sha512-ZcOqEuwuutTDYIjhDIStix22ECblG/i9pHje23QGs4Q4YS4RMaZ5hKCoQJxW88Z4K7T53rQkdISmoXFKDV8xMg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-http@0.51.1':
|
||||||
|
resolution: {integrity: sha512-6b3nZnFFEz/3xZ6w8bVxctPUWIPWiXuPQ725530JgxnN1cvYFd8CJ75PrHZNjynmzSSnqBkN3ef4R9N+RpMh8Q==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-ioredis@0.40.0':
|
||||||
|
resolution: {integrity: sha512-Jv/fH7KhpWe4KBirsiqeUJIYrsdR2iu2l4nWhfOlRvaZ+zYIiLEzTQR6QhBbyRoAbU4OuYJzjWusOmmpGBnwng==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-koa@0.40.0':
|
||||||
|
resolution: {integrity: sha512-dJc3H/bKMcgUYcQpLF+1IbmUKus0e5Fnn/+ru/3voIRHwMADT3rFSUcGLWSczkg68BCgz0vFWGDTvPtcWIFr7A==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mongodb@0.43.0':
|
||||||
|
resolution: {integrity: sha512-bMKej7Y76QVUD3l55Q9YqizXybHUzF3pujsBFjqbZrRn2WYqtsDtTUlbCK7fvXNPwFInqZ2KhnTqd0gwo8MzaQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mongoose@0.38.1':
|
||||||
|
resolution: {integrity: sha512-zaeiasdnRjXe6VhYCBMdkmAVh1S5MmXC/0spet+yqoaViGnYst/DOxPvhwg3yT4Yag5crZNWsVXnA538UjP6Ow==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mysql2@0.38.1':
|
||||||
|
resolution: {integrity: sha512-qkpHMgWSDTYVB1vlZ9sspf7l2wdS5DDq/rbIepDwX5BA0N0068JTQqh0CgAh34tdFqSCnWXIhcyOXC2TtRb0sg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mysql@0.38.1':
|
||||||
|
resolution: {integrity: sha512-+iBAawUaTfX/HAlvySwozx0C2B6LBfNPXX1W8Z2On1Uva33AGkw2UjL9XgIg1Pj4eLZ9R4EoJ/aFz+Xj4E/7Fw==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-nestjs-core@0.37.1':
|
||||||
|
resolution: {integrity: sha512-ebYQjHZEmGHWEALwwDGhSQVLBaurFnuLIkZD5igPXrt7ohfF4lc5/4al1LO+vKc0NHk8SJWStuRueT86ISA8Vg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-pg@0.41.0':
|
||||||
|
resolution: {integrity: sha512-BSlhpivzBD77meQNZY9fS4aKgydA8AJBzv2dqvxXFy/Hq64b7HURgw/ztbmwFeYwdF5raZZUifiiNSMLpOJoSA==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation@0.43.0':
|
||||||
|
resolution: {integrity: sha512-S1uHE+sxaepgp+t8lvIDuRgyjJWisAb733198kwQTUc9ZtYQ2V2gmyCtR1x21ePGVLoMiX/NWY7WA290hwkjJQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation@0.51.1':
|
||||||
|
resolution: {integrity: sha512-JIrvhpgqY6437QIqToyozrUG1h5UhwHkaGK/WAX+fkrpyPtc+RO5FkRtUd9BH0MibabHHvqsnBGKfKVijbmp8w==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.3.0
|
||||||
|
|
||||||
|
'@opentelemetry/redis-common@0.36.2':
|
||||||
|
resolution: {integrity: sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
'@opentelemetry/resources@1.24.1':
|
||||||
|
resolution: {integrity: sha512-cyv0MwAaPF7O86x5hk3NNgenMObeejZFLJJDVuSeSMIsknlsj3oOZzRv3qSzlwYomXsICfBeFFlxwHQte5mGXQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': '>=1.0.0 <1.9.0'
|
||||||
|
|
||||||
|
'@opentelemetry/sdk-metrics@1.24.1':
|
||||||
|
resolution: {integrity: sha512-FrAqCbbGao9iKI+Mgh+OsC9+U2YMoXnlDHe06yH7dvavCKzE3S892dGtX54+WhSFVxHR/TMRVJiK/CV93GR0TQ==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': '>=1.3.0 <1.9.0'
|
||||||
|
|
||||||
|
'@opentelemetry/sdk-trace-base@1.24.1':
|
||||||
|
resolution: {integrity: sha512-zz+N423IcySgjihl2NfjBf0qw1RWe11XIAWVrTNOSSI6dtSPJiVom2zipFB2AEEtJWpv0Iz6DY6+TjnyTV5pWg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': '>=1.0.0 <1.9.0'
|
||||||
|
|
||||||
|
'@opentelemetry/semantic-conventions@1.24.1':
|
||||||
|
resolution: {integrity: sha512-VkliWlS4/+GHLLW7J/rVBA00uXus1SWvwFvcUDxDwmFxYfg/2VI6ekwdXS28cjI8Qz2ky2BzG8OUHo+WeYIWqw==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
'@opentelemetry/sql-common@0.40.1':
|
||||||
|
resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==}
|
||||||
|
engines: {node: '>=14'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.1.0
|
||||||
|
|
||||||
'@peculiar/asn1-android@2.3.10':
|
'@peculiar/asn1-android@2.3.10':
|
||||||
resolution: {integrity: sha512-z9Rx9cFJv7UUablZISe7uksNbFJCq13hO0yEAOoIpAymALTLlvUOSLnGiQS7okPaM5dP42oTLhezH6XDXRXjGw==}
|
resolution: {integrity: sha512-z9Rx9cFJv7UUablZISe7uksNbFJCq13hO0yEAOoIpAymALTLlvUOSLnGiQS7okPaM5dP42oTLhezH6XDXRXjGw==}
|
||||||
|
|
||||||
|
@ -3305,6 +3459,9 @@ packages:
|
||||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|
||||||
|
'@prisma/instrumentation@5.14.0':
|
||||||
|
resolution: {integrity: sha512-DeybWvIZzu/mUsOYP9MVd6AyBj+MP7xIMrcuIn25MX8FiQX39QBnET5KhszTAip/ToctUuDwSJ46QkIoyo3RFA==}
|
||||||
|
|
||||||
'@radix-ui/react-compose-refs@1.0.1':
|
'@radix-ui/react-compose-refs@1.0.1':
|
||||||
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
|
resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -3467,6 +3624,37 @@ packages:
|
||||||
'@rushstack/ts-command-line@4.19.2':
|
'@rushstack/ts-command-line@4.19.2':
|
||||||
resolution: {integrity: sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==}
|
resolution: {integrity: sha512-cqmXXmBEBlzo9WtyUrHtF9e6kl0LvBY7aTSVX4jfnBfXWZQWnPq9JTFPlQZ+L/ZwjZ4HrNwQsOVvhe9oOucZkw==}
|
||||||
|
|
||||||
|
'@sentry/core@8.5.0':
|
||||||
|
resolution: {integrity: sha512-SO3ddBzGdha+Oflp+IKwBxj+7ds1q69OAT3VsypTd+WUFQdI9DIhR92Bjf+QQZCIzUNOi79VWOh3aOi3f6hMnw==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
|
||||||
|
'@sentry/node@8.5.0':
|
||||||
|
resolution: {integrity: sha512-t9cHAx/wLJYtdVf2XlzKlRJGvwdAp1wjzG0tC4E1Znx74OuUS1cFNo5WrGuOi0/YcWSxiJaxBvtUcsWK86fIgw==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
|
||||||
|
'@sentry/opentelemetry@8.5.0':
|
||||||
|
resolution: {integrity: sha512-AbxFUNjuTKQ9ugZrssmGtPxWkBr4USNoP7GjaaGCNwNzvIVYCa+i8dv7BROJiW2lsxNAremULEbh+nbVmhGxDA==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
peerDependencies:
|
||||||
|
'@opentelemetry/api': ^1.8.0
|
||||||
|
'@opentelemetry/core': ^1.24.1
|
||||||
|
'@opentelemetry/instrumentation': ^0.51.1
|
||||||
|
'@opentelemetry/sdk-trace-base': ^1.23.0
|
||||||
|
'@opentelemetry/semantic-conventions': ^1.23.0
|
||||||
|
|
||||||
|
'@sentry/profiling-node@8.5.0':
|
||||||
|
resolution: {integrity: sha512-nEXJqVNfZWYi4PakQXBZCJeH59UlnBv+zaYftDNUUXttCmzRXpL1ujNm5mJrJHlWjV7tgIFw02HW3nh2yyKOkw==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
'@sentry/types@8.5.0':
|
||||||
|
resolution: {integrity: sha512-eDgkSmKI4+XL0QZm4H3j/n1RgnrbnjXZmjj+LsfccRZQwbPu9bWlc8q7Y7Ty1gOsoUpX+TecNLp2a8CRID4KHA==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
|
||||||
|
'@sentry/utils@8.5.0':
|
||||||
|
resolution: {integrity: sha512-fdrCzo8SAYiw9JBhkJPqYqJkDXZ/wICzN7+zcXIuzKNhE1hdoFjeKcPnpUI3bKZCG6e3hT1PTYQXhVw7GIZV9w==}
|
||||||
|
engines: {node: '>=14.18'}
|
||||||
|
|
||||||
'@shikijs/core@1.4.0':
|
'@shikijs/core@1.4.0':
|
||||||
resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==}
|
resolution: {integrity: sha512-CxpKLntAi64h3j+TwWqVIQObPTED0FyXLHTTh3MKXtqiQNn2JGcMQQ362LftDbc9kYbDtrksNMNoVmVXzKFYUQ==}
|
||||||
|
|
||||||
|
@ -4272,12 +4460,18 @@ packages:
|
||||||
'@types/connect@3.4.35':
|
'@types/connect@3.4.35':
|
||||||
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
|
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
|
||||||
|
|
||||||
|
'@types/connect@3.4.36':
|
||||||
|
resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==}
|
||||||
|
|
||||||
'@types/content-disposition@0.5.8':
|
'@types/content-disposition@0.5.8':
|
||||||
resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
|
resolution: {integrity: sha512-QVSSvno3dE0MgO76pJhmv4Qyi/j0Yk9pBp0Y7TJ2Tlj+KCgJWY6qX7nnxCOLkZ3VYRSIk1WTxCvwUSdx6CCLdg==}
|
||||||
|
|
||||||
'@types/cookie@0.6.0':
|
'@types/cookie@0.6.0':
|
||||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||||
|
|
||||||
|
'@types/cookies@0.9.0':
|
||||||
|
resolution: {integrity: sha512-40Zk8qR147RABiQ7NQnBzWzDcjKzNrntB5BAmeGCb2p/MIyOE+4BVvc17wumsUqUw00bJYqoXFHYygQnEFh4/Q==}
|
||||||
|
|
||||||
'@types/cross-spawn@6.0.2':
|
'@types/cross-spawn@6.0.2':
|
||||||
resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
|
resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
|
||||||
|
|
||||||
|
@ -4341,9 +4535,15 @@ packages:
|
||||||
'@types/htmlescape@1.1.3':
|
'@types/htmlescape@1.1.3':
|
||||||
resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
|
resolution: {integrity: sha512-tuC81YJXGUe0q8WRtBNW+uyx79rkkzWK651ALIXXYq5/u/IxjX4iHneGF2uUqzsNp+F+9J2mFZOv9jiLTtIq0w==}
|
||||||
|
|
||||||
|
'@types/http-assert@1.5.5':
|
||||||
|
resolution: {integrity: sha512-4+tE/lwdAahgZT1g30Jkdm9PzFRde0xwxBNUyRsCitRvCQB90iuA2uJYdUnhnANRcqGXaWOGY4FEoxeElNAK2g==}
|
||||||
|
|
||||||
'@types/http-cache-semantics@4.0.4':
|
'@types/http-cache-semantics@4.0.4':
|
||||||
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==}
|
||||||
|
|
||||||
|
'@types/http-errors@2.0.4':
|
||||||
|
resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==}
|
||||||
|
|
||||||
'@types/http-link-header@1.0.5':
|
'@types/http-link-header@1.0.5':
|
||||||
resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==}
|
resolution: {integrity: sha512-AxhIKR8UbyoqCTNp9rRepkktHuUOw3DjfOfDCaO9kwI8AYzjhxyrvZq4+mRw/2daD3hYDknrtSeV6SsPwmc71w==}
|
||||||
|
|
||||||
|
@ -4380,9 +4580,21 @@ packages:
|
||||||
'@types/jsrsasign@10.5.14':
|
'@types/jsrsasign@10.5.14':
|
||||||
resolution: {integrity: sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==}
|
resolution: {integrity: sha512-lppSlfK6etu+cuKs40K4rg8As79PH6hzIB+v55zSqImbSH3SE6Fm8MBHCiI91cWlAP3Z4igtJK1VL3fSN09blQ==}
|
||||||
|
|
||||||
|
'@types/keygrip@1.0.6':
|
||||||
|
resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==}
|
||||||
|
|
||||||
'@types/keyv@3.1.4':
|
'@types/keyv@3.1.4':
|
||||||
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==}
|
||||||
|
|
||||||
|
'@types/koa-compose@3.2.8':
|
||||||
|
resolution: {integrity: sha512-4Olc63RY+MKvxMwVknCUDhRQX1pFQoBZ/lXcRLP69PQkEpze/0cr8LNqJQe5NFb/b19DWi2a5bTi2VAlQzhJuA==}
|
||||||
|
|
||||||
|
'@types/koa@2.14.0':
|
||||||
|
resolution: {integrity: sha512-DTDUyznHGNHAl+wd1n0z1jxNajduyTh8R53xoewuerdBzGo6Ogj6F2299BFtrexJw4NtgjsI5SMPCmV9gZwGXA==}
|
||||||
|
|
||||||
|
'@types/koa__router@12.0.3':
|
||||||
|
resolution: {integrity: sha512-5YUJVv6NwM1z7m6FuYpKfNLTZ932Z6EF6xy2BbtpJSyn13DKNQEkXVffFVSnJHxvwwWh2SAeumpjAYUELqgjyw==}
|
||||||
|
|
||||||
'@types/lodash@4.14.191':
|
'@types/lodash@4.14.191':
|
||||||
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
|
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
|
||||||
|
|
||||||
|
@ -4419,6 +4631,9 @@ packages:
|
||||||
'@types/mute-stream@0.0.4':
|
'@types/mute-stream@0.0.4':
|
||||||
resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==}
|
resolution: {integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==}
|
||||||
|
|
||||||
|
'@types/mysql@2.15.22':
|
||||||
|
resolution: {integrity: sha512-wK1pzsJVVAjYCSZWQoWHziQZbNggXFDUEIGf54g4ZM/ERuP86uGdWeKZWMYlqTPMZfHJJvLPyogXGvCOg87yLQ==}
|
||||||
|
|
||||||
'@types/node-fetch@2.6.4':
|
'@types/node-fetch@2.6.4':
|
||||||
resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
|
resolution: {integrity: sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg==}
|
||||||
|
|
||||||
|
@ -4459,9 +4674,15 @@ packages:
|
||||||
'@types/offscreencanvas@2019.7.0':
|
'@types/offscreencanvas@2019.7.0':
|
||||||
resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==}
|
resolution: {integrity: sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==}
|
||||||
|
|
||||||
|
'@types/pg-pool@2.0.4':
|
||||||
|
resolution: {integrity: sha512-qZAvkv1K3QbmHHFYSNRYPkRjOWRLBYrL4B9c+wG0GSVGBw0NtJwPcgx/DSddeDJvRGMHCEQ4VMEVfuJ/0gZ3XQ==}
|
||||||
|
|
||||||
'@types/pg@8.11.5':
|
'@types/pg@8.11.5':
|
||||||
resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==}
|
resolution: {integrity: sha512-2xMjVviMxneZHDHX5p5S6tsRRs7TpDHeeK7kTTMe/kAC/mRRNjWHjZg0rkiY+e17jXSZV3zJYDxXV8Cy72/Vuw==}
|
||||||
|
|
||||||
|
'@types/pg@8.6.1':
|
||||||
|
resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==}
|
||||||
|
|
||||||
'@types/pretty-hrtime@1.0.1':
|
'@types/pretty-hrtime@1.0.1':
|
||||||
resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
|
resolution: {integrity: sha512-VjID5MJb1eGKthz2qUerWT8+R4b9N+CHvGCzg9fn4kWZgaF9AhdYikQio3R7wV8YY1NsQKPaCwKz1Yff+aHNUQ==}
|
||||||
|
|
||||||
|
@ -4525,6 +4746,9 @@ packages:
|
||||||
'@types/serviceworker@0.0.67':
|
'@types/serviceworker@0.0.67':
|
||||||
resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==}
|
resolution: {integrity: sha512-7TCH7iNsCSNb+aUD9M/36TekrWFSLCjNK8zw/3n5kOtRjbLtDfGYMXTrDnGhSfqXNwpqmt9Vd90w5C/ad1tX6Q==}
|
||||||
|
|
||||||
|
'@types/shimmer@1.0.5':
|
||||||
|
resolution: {integrity: sha512-9Hp0ObzwwO57DpLFF0InUjUm/II8GmKAvzbefxQTihCb7KI6yc9yzf0nLc4mVdby5N4DRCgQM2wCup9KTieeww==}
|
||||||
|
|
||||||
'@types/simple-oauth2@5.0.7':
|
'@types/simple-oauth2@5.0.7':
|
||||||
resolution: {integrity: sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA==}
|
resolution: {integrity: sha512-8JbWVJbiTSBQP/7eiyGKyXWAqp3dKQZpaA+pdW16FCi32ujkzRMG8JfjoAzdWt6W8U591ZNdHcPtP2D7ILTKuA==}
|
||||||
|
|
||||||
|
@ -4921,6 +5145,16 @@ packages:
|
||||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
acorn-import-assertions@1.9.0:
|
||||||
|
resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==}
|
||||||
|
peerDependencies:
|
||||||
|
acorn: ^8
|
||||||
|
|
||||||
|
acorn-import-attributes@1.9.5:
|
||||||
|
resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==}
|
||||||
|
peerDependencies:
|
||||||
|
acorn: ^8
|
||||||
|
|
||||||
acorn-jsx@5.3.2:
|
acorn-jsx@5.3.2:
|
||||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -7140,6 +7374,12 @@ packages:
|
||||||
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
|
import-in-the-middle@1.4.2:
|
||||||
|
resolution: {integrity: sha512-9WOz1Yh/cvO/p69sxRmhyQwrIGGSp7EIdcb+fFNVi7CzQGQB8U1/1XrKVSbEd/GNOAeM0peJtmi7+qphe7NvAw==}
|
||||||
|
|
||||||
|
import-in-the-middle@1.7.4:
|
||||||
|
resolution: {integrity: sha512-Lk+qzWmiQuRPPulGQeK5qq0v32k2bHnWrRPFgqyvhw7Kkov5L6MOLOIU3pcWeujc9W4q54Cp3Q2WV16eQkc7Bg==}
|
||||||
|
|
||||||
import-lazy@4.0.0:
|
import-lazy@4.0.0:
|
||||||
resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
|
resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -8308,6 +8548,9 @@ packages:
|
||||||
resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==}
|
resolution: {integrity: sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
||||||
|
module-details-from-path@1.0.3:
|
||||||
|
resolution: {integrity: sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==}
|
||||||
|
|
||||||
mri@1.2.0:
|
mri@1.2.0:
|
||||||
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
@ -8426,6 +8669,10 @@ packages:
|
||||||
nise@5.1.4:
|
nise@5.1.4:
|
||||||
resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==}
|
resolution: {integrity: sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg==}
|
||||||
|
|
||||||
|
node-abi@3.62.0:
|
||||||
|
resolution: {integrity: sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==}
|
||||||
|
engines: {node: '>=10'}
|
||||||
|
|
||||||
node-abort-controller@3.1.1:
|
node-abort-controller@3.1.1:
|
||||||
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
||||||
|
|
||||||
|
@ -8659,6 +8906,10 @@ packages:
|
||||||
resolution: {integrity: sha512-es3mGcDXV6TKPo6n3aohzHm0qxhLyR39MhF6mkD1FwFGjhxnqMqfSIgM0eCpInZvqatve4CxmXcMZw3jnnsaXw==}
|
resolution: {integrity: sha512-es3mGcDXV6TKPo6n3aohzHm0qxhLyR39MhF6mkD1FwFGjhxnqMqfSIgM0eCpInZvqatve4CxmXcMZw3jnnsaXw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
opentelemetry-instrumentation-fetch-node@1.2.0:
|
||||||
|
resolution: {integrity: sha512-aiSt/4ubOTyb1N5C2ZbGrBvaJOXIZhZvpRPYuUVxQJe27wJZqf/o65iPrqgLcgfeOLaQ8cS2Q+762jrYvniTrA==}
|
||||||
|
engines: {node: '>18.0.0'}
|
||||||
|
|
||||||
optionator@0.9.3:
|
optionator@0.9.3:
|
||||||
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
@ -9606,6 +9857,10 @@ packages:
|
||||||
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
require-in-the-middle@7.3.0:
|
||||||
|
resolution: {integrity: sha512-nQFEv9gRw6SJAwWD2LrL0NmQvAcO7FBwJbwmr2ttPAacfy0xuiOjE5zt+zM4xDyuyvUaxBi/9gb2SoCyNEVJcw==}
|
||||||
|
engines: {node: '>=8.6.0'}
|
||||||
|
|
||||||
require-main-filename@2.0.0:
|
require-main-filename@2.0.0:
|
||||||
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==}
|
||||||
|
|
||||||
|
@ -9820,6 +10075,9 @@ packages:
|
||||||
shiki@1.4.0:
|
shiki@1.4.0:
|
||||||
resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==}
|
resolution: {integrity: sha512-5WIn0OL8PWm7JhnTwRWXniy6eEDY234mRrERVlFa646V2ErQqwIFd2UML7e0Pq9eqSKLoMa3Ke+xbsF+DAuy+Q==}
|
||||||
|
|
||||||
|
shimmer@1.2.1:
|
||||||
|
resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==}
|
||||||
|
|
||||||
side-channel@1.0.4:
|
side-channel@1.0.4:
|
||||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||||
|
|
||||||
|
@ -13785,6 +14043,203 @@ snapshots:
|
||||||
|
|
||||||
'@open-draft/until@2.1.0': {}
|
'@open-draft/until@2.1.0': {}
|
||||||
|
|
||||||
|
'@opentelemetry/api-logs@0.51.1':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
|
||||||
|
'@opentelemetry/api@1.8.0': {}
|
||||||
|
|
||||||
|
'@opentelemetry/context-async-hooks@1.24.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
|
||||||
|
'@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-connect@0.36.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@types/connect': 3.4.36
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-express@0.39.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-fastify@0.36.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-graphql@0.40.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-hapi@0.38.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-http@0.51.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
semver: 7.6.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-ioredis@0.40.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/redis-common': 0.36.2
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-koa@0.40.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@types/koa': 2.14.0
|
||||||
|
'@types/koa__router': 12.0.3
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mongodb@0.43.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/sdk-metrics': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mongoose@0.38.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mysql2@0.38.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-mysql@0.38.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@types/mysql': 2.15.22
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-nestjs-core@0.37.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation-pg@0.41.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@types/pg': 8.6.1
|
||||||
|
'@types/pg-pool': 2.0.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation@0.43.0(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@types/shimmer': 1.0.5
|
||||||
|
import-in-the-middle: 1.4.2
|
||||||
|
require-in-the-middle: 7.3.0
|
||||||
|
semver: 7.6.0
|
||||||
|
shimmer: 1.2.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/api-logs': 0.51.1
|
||||||
|
'@types/shimmer': 1.0.5
|
||||||
|
import-in-the-middle: 1.7.4
|
||||||
|
require-in-the-middle: 7.3.0
|
||||||
|
semver: 7.6.0
|
||||||
|
shimmer: 1.2.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@opentelemetry/redis-common@0.36.2': {}
|
||||||
|
|
||||||
|
'@opentelemetry/resources@1.24.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
|
||||||
|
'@opentelemetry/sdk-metrics@1.24.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
lodash.merge: 4.6.2
|
||||||
|
|
||||||
|
'@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
|
||||||
|
'@opentelemetry/semantic-conventions@1.24.1': {}
|
||||||
|
|
||||||
|
'@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.8.0)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
|
||||||
'@peculiar/asn1-android@2.3.10':
|
'@peculiar/asn1-android@2.3.10':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@peculiar/asn1-schema': 2.3.8
|
'@peculiar/asn1-schema': 2.3.8
|
||||||
|
@ -13828,6 +14283,14 @@ snapshots:
|
||||||
'@pkgjs/parseargs@0.11.0':
|
'@pkgjs/parseargs@0.11.0':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@prisma/instrumentation@5.14.0':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.3.1)':
|
'@radix-ui/react-compose-refs@1.0.1(@types/react@18.0.28)(react@18.3.1)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.23.4
|
'@babel/runtime': 7.23.4
|
||||||
|
@ -13974,6 +14437,72 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
|
|
||||||
|
'@sentry/core@8.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@sentry/types': 8.5.0
|
||||||
|
'@sentry/utils': 8.5.0
|
||||||
|
|
||||||
|
'@sentry/node@8.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/context-async-hooks': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-connect': 0.36.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-express': 0.39.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-fastify': 0.36.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-graphql': 0.40.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-hapi': 0.38.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-http': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-ioredis': 0.40.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-koa': 0.40.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-mongodb': 0.43.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-mongoose': 0.38.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-mysql': 0.38.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-mysql2': 0.38.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-nestjs-core': 0.37.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation-pg': 0.41.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/resources': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@prisma/instrumentation': 5.14.0
|
||||||
|
'@sentry/core': 8.5.0
|
||||||
|
'@sentry/opentelemetry': 8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)
|
||||||
|
'@sentry/types': 8.5.0
|
||||||
|
'@sentry/utils': 8.5.0
|
||||||
|
optionalDependencies:
|
||||||
|
opentelemetry-instrumentation-fetch-node: 1.2.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@sentry/opentelemetry@8.5.0(@opentelemetry/api@1.8.0)(@opentelemetry/core@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/instrumentation@0.51.1(@opentelemetry/api@1.8.0))(@opentelemetry/sdk-trace-base@1.24.1(@opentelemetry/api@1.8.0))(@opentelemetry/semantic-conventions@1.24.1)':
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/core': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/instrumentation': 0.51.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/sdk-trace-base': 1.24.1(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
'@sentry/core': 8.5.0
|
||||||
|
'@sentry/types': 8.5.0
|
||||||
|
'@sentry/utils': 8.5.0
|
||||||
|
|
||||||
|
'@sentry/profiling-node@8.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@sentry/core': 8.5.0
|
||||||
|
'@sentry/node': 8.5.0
|
||||||
|
'@sentry/types': 8.5.0
|
||||||
|
'@sentry/utils': 8.5.0
|
||||||
|
detect-libc: 2.0.3
|
||||||
|
node-abi: 3.62.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
|
'@sentry/types@8.5.0': {}
|
||||||
|
|
||||||
|
'@sentry/utils@8.5.0':
|
||||||
|
dependencies:
|
||||||
|
'@sentry/types': 8.5.0
|
||||||
|
|
||||||
'@shikijs/core@1.4.0': {}
|
'@shikijs/core@1.4.0': {}
|
||||||
|
|
||||||
'@sideway/address@4.1.4':
|
'@sideway/address@4.1.4':
|
||||||
|
@ -15353,10 +15882,21 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
|
'@types/connect@3.4.36':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
'@types/content-disposition@0.5.8': {}
|
'@types/content-disposition@0.5.8': {}
|
||||||
|
|
||||||
'@types/cookie@0.6.0': {}
|
'@types/cookie@0.6.0': {}
|
||||||
|
|
||||||
|
'@types/cookies@0.9.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/connect': 3.4.35
|
||||||
|
'@types/express': 4.17.17
|
||||||
|
'@types/keygrip': 1.0.6
|
||||||
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
'@types/cross-spawn@6.0.2':
|
'@types/cross-spawn@6.0.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
|
@ -15424,8 +15964,12 @@ snapshots:
|
||||||
|
|
||||||
'@types/htmlescape@1.1.3': {}
|
'@types/htmlescape@1.1.3': {}
|
||||||
|
|
||||||
|
'@types/http-assert@1.5.5': {}
|
||||||
|
|
||||||
'@types/http-cache-semantics@4.0.4': {}
|
'@types/http-cache-semantics@4.0.4': {}
|
||||||
|
|
||||||
|
'@types/http-errors@2.0.4': {}
|
||||||
|
|
||||||
'@types/http-link-header@1.0.5':
|
'@types/http-link-header@1.0.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
|
@ -15463,10 +16007,31 @@ snapshots:
|
||||||
|
|
||||||
'@types/jsrsasign@10.5.14': {}
|
'@types/jsrsasign@10.5.14': {}
|
||||||
|
|
||||||
|
'@types/keygrip@1.0.6': {}
|
||||||
|
|
||||||
'@types/keyv@3.1.4':
|
'@types/keyv@3.1.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
|
'@types/koa-compose@3.2.8':
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.14.0
|
||||||
|
|
||||||
|
'@types/koa@2.14.0':
|
||||||
|
dependencies:
|
||||||
|
'@types/accepts': 1.3.7
|
||||||
|
'@types/content-disposition': 0.5.8
|
||||||
|
'@types/cookies': 0.9.0
|
||||||
|
'@types/http-assert': 1.5.5
|
||||||
|
'@types/http-errors': 2.0.4
|
||||||
|
'@types/keygrip': 1.0.6
|
||||||
|
'@types/koa-compose': 3.2.8
|
||||||
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
|
'@types/koa__router@12.0.3':
|
||||||
|
dependencies:
|
||||||
|
'@types/koa': 2.14.0
|
||||||
|
|
||||||
'@types/lodash@4.14.191': {}
|
'@types/lodash@4.14.191': {}
|
||||||
|
|
||||||
'@types/long@4.0.2': {}
|
'@types/long@4.0.2': {}
|
||||||
|
@ -15497,6 +16062,10 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
|
'@types/mysql@2.15.22':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.12.7
|
||||||
|
|
||||||
'@types/node-fetch@2.6.4':
|
'@types/node-fetch@2.6.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
|
@ -15543,12 +16112,22 @@ snapshots:
|
||||||
|
|
||||||
'@types/offscreencanvas@2019.7.0': {}
|
'@types/offscreencanvas@2019.7.0': {}
|
||||||
|
|
||||||
|
'@types/pg-pool@2.0.4':
|
||||||
|
dependencies:
|
||||||
|
'@types/pg': 8.11.5
|
||||||
|
|
||||||
'@types/pg@8.11.5':
|
'@types/pg@8.11.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.12.7
|
'@types/node': 20.12.7
|
||||||
pg-protocol: 1.6.0
|
pg-protocol: 1.6.0
|
||||||
pg-types: 4.0.1
|
pg-types: 4.0.1
|
||||||
|
|
||||||
|
'@types/pg@8.6.1':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.12.7
|
||||||
|
pg-protocol: 1.6.1
|
||||||
|
pg-types: 2.2.0
|
||||||
|
|
||||||
'@types/pretty-hrtime@1.0.1': {}
|
'@types/pretty-hrtime@1.0.1': {}
|
||||||
|
|
||||||
'@types/prop-types@15.7.5': {}
|
'@types/prop-types@15.7.5': {}
|
||||||
|
@ -15606,6 +16185,8 @@ snapshots:
|
||||||
|
|
||||||
'@types/serviceworker@0.0.67': {}
|
'@types/serviceworker@0.0.67': {}
|
||||||
|
|
||||||
|
'@types/shimmer@1.0.5': {}
|
||||||
|
|
||||||
'@types/simple-oauth2@5.0.7': {}
|
'@types/simple-oauth2@5.0.7': {}
|
||||||
|
|
||||||
'@types/sinon@10.0.13':
|
'@types/sinon@10.0.13':
|
||||||
|
@ -16150,6 +16731,15 @@ snapshots:
|
||||||
mime-types: 2.1.35
|
mime-types: 2.1.35
|
||||||
negotiator: 0.6.3
|
negotiator: 0.6.3
|
||||||
|
|
||||||
|
acorn-import-assertions@1.9.0(acorn@8.11.3):
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.11.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
acorn-import-attributes@1.9.5(acorn@8.11.3):
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.11.3
|
||||||
|
|
||||||
acorn-jsx@5.3.2(acorn@7.4.1):
|
acorn-jsx@5.3.2(acorn@7.4.1):
|
||||||
dependencies:
|
dependencies:
|
||||||
acorn: 7.4.1
|
acorn: 7.4.1
|
||||||
|
@ -19070,6 +19660,21 @@ snapshots:
|
||||||
parent-module: 1.0.1
|
parent-module: 1.0.1
|
||||||
resolve-from: 4.0.0
|
resolve-from: 4.0.0
|
||||||
|
|
||||||
|
import-in-the-middle@1.4.2:
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.11.3
|
||||||
|
acorn-import-assertions: 1.9.0(acorn@8.11.3)
|
||||||
|
cjs-module-lexer: 1.2.2
|
||||||
|
module-details-from-path: 1.0.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
import-in-the-middle@1.7.4:
|
||||||
|
dependencies:
|
||||||
|
acorn: 8.11.3
|
||||||
|
acorn-import-attributes: 1.9.5(acorn@8.11.3)
|
||||||
|
cjs-module-lexer: 1.2.2
|
||||||
|
module-details-from-path: 1.0.3
|
||||||
|
|
||||||
import-lazy@4.0.0: {}
|
import-lazy@4.0.0: {}
|
||||||
|
|
||||||
import-local@3.1.0:
|
import-local@3.1.0:
|
||||||
|
@ -20583,6 +21188,8 @@ snapshots:
|
||||||
|
|
||||||
mock-socket@9.3.1: {}
|
mock-socket@9.3.1: {}
|
||||||
|
|
||||||
|
module-details-from-path@1.0.3: {}
|
||||||
|
|
||||||
mri@1.2.0: {}
|
mri@1.2.0: {}
|
||||||
|
|
||||||
ms@2.0.0: {}
|
ms@2.0.0: {}
|
||||||
|
@ -20719,6 +21326,10 @@ snapshots:
|
||||||
just-extend: 4.2.1
|
just-extend: 4.2.1
|
||||||
path-to-regexp: 1.8.0
|
path-to-regexp: 1.8.0
|
||||||
|
|
||||||
|
node-abi@3.62.0:
|
||||||
|
dependencies:
|
||||||
|
semver: 7.6.0
|
||||||
|
|
||||||
node-abort-controller@3.1.1: {}
|
node-abort-controller@3.1.1: {}
|
||||||
|
|
||||||
node-addon-api@3.2.1:
|
node-addon-api@3.2.1:
|
||||||
|
@ -20971,6 +21582,15 @@ snapshots:
|
||||||
undici: 5.28.2
|
undici: 5.28.2
|
||||||
yargs-parser: 21.1.1
|
yargs-parser: 21.1.1
|
||||||
|
|
||||||
|
opentelemetry-instrumentation-fetch-node@1.2.0:
|
||||||
|
dependencies:
|
||||||
|
'@opentelemetry/api': 1.8.0
|
||||||
|
'@opentelemetry/instrumentation': 0.43.0(@opentelemetry/api@1.8.0)
|
||||||
|
'@opentelemetry/semantic-conventions': 1.24.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
optional: true
|
||||||
|
|
||||||
optionator@0.9.3:
|
optionator@0.9.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@aashutoshrathi/word-wrap': 1.2.6
|
'@aashutoshrathi/word-wrap': 1.2.6
|
||||||
|
@ -21990,6 +22610,14 @@ snapshots:
|
||||||
|
|
||||||
require-from-string@2.0.2: {}
|
require-from-string@2.0.2: {}
|
||||||
|
|
||||||
|
require-in-the-middle@7.3.0:
|
||||||
|
dependencies:
|
||||||
|
debug: 4.3.4(supports-color@8.1.1)
|
||||||
|
module-details-from-path: 1.0.3
|
||||||
|
resolve: 1.22.8
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
require-main-filename@2.0.0: {}
|
require-main-filename@2.0.0: {}
|
||||||
|
|
||||||
requires-port@1.0.0: {}
|
requires-port@1.0.0: {}
|
||||||
|
@ -22248,6 +22876,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@shikijs/core': 1.4.0
|
'@shikijs/core': 1.4.0
|
||||||
|
|
||||||
|
shimmer@1.2.1: {}
|
||||||
|
|
||||||
side-channel@1.0.4:
|
side-channel@1.0.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
call-bind: 1.0.2
|
call-bind: 1.0.2
|
||||||
|
|
Loading…
Reference in New Issue