Merge branch 'bmjwt' into acct-parse-url

This commit is contained in:
tamaina 2025-08-28 10:39:04 +09:00
commit 9bf42649a5
41 changed files with 260 additions and 170 deletions

View File

@ -12,10 +12,13 @@
- 既存のサーバーで当機能を有効化した場合は、処理量が多くなるため、一時的にストレージ使用量が増加する可能性があります。 - 既存のサーバーで当機能を有効化した場合は、処理量が多くなるため、一時的にストレージ使用量が増加する可能性があります。
- 増加量を抑えるには、最大処理継続時間をデフォルトより短くしてください。 - 増加量を抑えるには、最大処理継続時間をデフォルトより短くしてください。
- データベースサイズへの効果が見られない場合はautovacuumが有効になっているか確認してください - データベースサイズへの効果が見られない場合はautovacuumが有効になっているか確認してください
- ハイパーリンクによる参照は検知できないためリンク切れとなります。
- 現時点では、2023-10-01以前にクリップされたリモートのートは検知しないため削除対象となります。
- サーバーの初期設定が完了するまでは連合がオンにならないようになりました - サーバーの初期設定が完了するまでは連合がオンにならないようになりました
- 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました - 日本語における公開範囲名称の「ダイレクト」が「指名」に改称されました
- 実際の動作に即した名称になり、馴染みのない人でも理解しやすくなりました - 実際の動作に即した名称になり、馴染みのない人でも理解しやすくなりました
- 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました - 他サービスにおける「ダイレクトメッセージ」に相当するMisskeyの機能は「チャット」ですが(過去のバージョンのMisskeyでも、当該機能は「チャット」ではなく「ダイレクトメッセージ」でした)、「ダイレクト投稿」という名称の機能が存在するとそちらがダイレクトメッセージ機能であるような誤解を生んでいました
- 今後、「チャット」の名称を「ダイレクトメッセージ」に戻す可能性があります
- mfm.jsをアップデートしました - mfm.jsをアップデートしました
- Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応 - Enhance: Unicode 15.1 および 16.0 に収録されている絵文字に対応
- Enhance: acctに `.` が入っているユーザーのメンションに対応 - Enhance: acctに `.` が入っているユーザーのメンションに対応
@ -27,6 +30,7 @@
- プラグインは1.xに対応したものが必要です - プラグインは1.xに対応したものが必要です
- Playはそのまま動作しますが、新規に作られるプリセットは1.xになります - Playはそのまま動作しますが、新規に作られるプリセットは1.xになります
- 以前のバージョンから無効化されていた note_view_interruptor が有効になりました - 以前のバージョンから無効化されていた note_view_interruptor が有効になりました
- ハンドラは同期的である必要があります
- Feat: セーフモード - Feat: セーフモード
- プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます - プラグイン・テーマ・カスタムCSSの使用でクライアントの起動に問題が発生した際に、これらを無効にして起動できます
- 以下の方法でセーフモードを起動できます - 以下の方法でセーフモードを起動できます
@ -57,6 +61,7 @@
- Fix: 照会ダイアログでap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正 - Fix: 照会ダイアログでap/showでローカルユーザーを解決した際@username@nullに飛ばされる問題を修正
- Fix: アイコンのデコレーションを付ける際にデコレーションが表示されなくなる問題を修正 - Fix: アイコンのデコレーションを付ける際にデコレーションが表示されなくなる問題を修正
- Fix: 管理中アカウント一覧で正しい表示が行われない問題を修正 - Fix: 管理中アカウント一覧で正しい表示が行われない問題を修正
- Fix: lookupページでリモートURLを指定した際に正しく動作しない問題を修正
### Server ### Server
- Feat: サーバー管理コマンド - Feat: サーバー管理コマンド

6
locales/index.d.ts vendored
View File

@ -12032,15 +12032,15 @@ export interface Locale extends ILocale {
*/ */
"youCanConfigureMoreFederationSettingsLater": string; "youCanConfigureMoreFederationSettingsLater": string;
/** /**
* *
*/ */
"remoteContentsCleaning": string; "remoteContentsCleaning": string;
/** /**
* *
*/ */
"remoteContentsCleaning_description": string; "remoteContentsCleaning_description": string;
/** /**
* *
*/ */
"remoteContentsCleaning_description2": string; "remoteContentsCleaning_description2": string;
/** /**

View File

@ -3216,9 +3216,9 @@ _serverSetupWizard:
doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。" doYouConnectToFediverse_description1: "分散型サーバーで構成されるネットワーク(Fediverse)に接続すると、他のサーバーと相互にコンテンツのやり取りが可能です。"
doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。" doYouConnectToFediverse_description2: "Fediverseと接続することは「連合」とも呼ばれます。"
youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。" youCanConfigureMoreFederationSettingsLater: "連合可能なサーバーの指定など、高度な設定も後ほど可能です。"
remoteContentsCleaning: "受信コンテンツの自動クリーニング" remoteContentsCleaning: "リモートコンテンツの自動クリーニング"
remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、参照されていない古くなったコンテンツを自動でサーバーから削除し、ストレージを節約できます。" remoteContentsCleaning_description: "連合を行うと、継続して多くのコンテンツを受信します。自動クリーニングを有効にすると、参照されていない古くなったリモートコンテンツを自動でサーバーから削除し、ストレージを節約できます。"
remoteContentsCleaning_description2: "ハイパーリンクなど、一部の参照方法はシステム上で検知できません。" remoteContentsCleaning_description2: "ローカル内リモートコンテンツへのハイパーリンクはリンク切れとなります。"
adminInfo: "管理者情報" adminInfo: "管理者情報"
adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。" adminInfo_description: "問い合わせを受け付けるために使用される管理者情報を設定します。"
adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。" adminInfo_mustBeFilled: "オープンサーバー、または連合がオンの場合は必ず入力が必要です。"

View File

@ -481,6 +481,7 @@ export class UserEntityService implements OnModuleInit {
const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null; const notificationsInfo = isMe && isDetailed ? await this.getNotificationsInfo(user.id) : null;
// TODO: 例えば avatarUrl: true など間違った型を設定しても型エラーにならないのをどうにかする(ジェネリクス使わない方法で実装するしかなさそう?)
const packed = { const packed = {
id: user.id, id: user.id,
name: user.name, name: user.name,

View File

@ -65,6 +65,7 @@ import {
packedMetaDetailedSchema, packedMetaDetailedSchema,
packedMetaLiteSchema, packedMetaLiteSchema,
} from '@/models/json-schema/meta.js'; } from '@/models/json-schema/meta.js';
import { packedUserWebhookSchema } from '@/models/json-schema/user-webhook.js';
import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js'; import { packedSystemWebhookSchema } from '@/models/json-schema/system-webhook.js';
import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js'; import { packedAbuseReportNotificationRecipientSchema } from '@/models/json-schema/abuse-report-notification-recipient.js';
import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js'; import { packedChatMessageSchema, packedChatMessageLiteSchema, packedChatMessageLiteForRoomSchema, packedChatMessageLiteFor1on1Schema } from '@/models/json-schema/chat-message.js';
@ -134,6 +135,7 @@ export const refs = {
MetaLite: packedMetaLiteSchema, MetaLite: packedMetaLiteSchema,
MetaDetailedOnly: packedMetaDetailedOnlySchema, MetaDetailedOnly: packedMetaDetailedOnlySchema,
MetaDetailed: packedMetaDetailedSchema, MetaDetailed: packedMetaDetailedSchema,
UserWebhook: packedUserWebhookSchema,
SystemWebhook: packedSystemWebhookSchema, SystemWebhook: packedSystemWebhookSchema,
AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema, AbuseReportNotificationRecipient: packedAbuseReportNotificationRecipientSchema,
ChatMessage: packedChatMessageSchema, ChatMessage: packedChatMessageSchema,

View File

@ -0,0 +1,55 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { webhookEventTypes } from '@/models/Webhook.js';
export const packedUserWebhookSchema = {
type: 'object',
properties: {
id: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
userId: {
type: 'string',
format: 'id',
optional: false, nullable: false,
},
name: {
type: 'string',
optional: false, nullable: false,
},
on: {
type: 'array',
items: {
type: 'string',
optional: false, nullable: false,
enum: webhookEventTypes,
},
},
url: {
type: 'string',
optional: false, nullable: false,
},
secret: {
type: 'string',
optional: false, nullable: false,
},
active: {
type: 'boolean',
optional: false, nullable: false,
},
latestSentAt: {
type: 'string',
format: 'date-time',
optional: false, nullable: true,
},
latestStatus: {
type: 'integer',
optional: false, nullable: true,
},
},
} as const;

View File

@ -65,7 +65,7 @@ export const packedUserLiteSchema = {
avatarUrl: { avatarUrl: {
type: 'string', type: 'string',
format: 'url', format: 'url',
nullable: true, optional: false, nullable: false, optional: false,
}, },
avatarBlurhash: { avatarBlurhash: {
type: 'string', type: 'string',
@ -591,7 +591,7 @@ export const packedMeDetailedOnlySchema = {
}, },
mutedInstances: { mutedInstances: {
type: 'array', type: 'array',
nullable: true, optional: false, nullable: false, optional: false,
items: { items: {
type: 'string', type: 'string',
nullable: false, optional: false, nullable: false, optional: false,

View File

@ -157,6 +157,22 @@ export const meta = {
type: 'boolean', type: 'boolean',
optional: false, nullable: false, optional: false, nullable: false,
}, },
maybeSensitive: {
type: 'boolean',
optional: false, nullable: false,
},
maybePorn: {
type: 'boolean',
optional: false, nullable: false,
},
requestIp: {
type: 'string',
optional: false, nullable: true,
},
requestHeaders: {
type: 'object',
optional: false, nullable: true,
},
}, },
}, },
} as const; } as const;

View File

@ -223,10 +223,12 @@ export const meta = {
sensitiveMediaDetection: { sensitiveMediaDetection: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
enum: ['none', 'all', 'local', 'remote'],
}, },
sensitiveMediaDetectionSensitivity: { sensitiveMediaDetectionSensitivity: {
type: 'string', type: 'string',
optional: false, nullable: false, optional: false, nullable: false,
enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'],
}, },
setSensitiveFlagAutomatically: { setSensitiveFlagAutomatically: {
type: 'boolean', type: 'boolean',
@ -473,6 +475,10 @@ export const meta = {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,
}, },
feedbackUrl: {
type: 'string',
optional: false, nullable: true,
},
summalyProxy: { summalyProxy: {
type: 'string', type: 'string',
optional: false, nullable: true, optional: false, nullable: true,

View File

@ -46,6 +46,14 @@ export const meta = {
type: 'string', type: 'string',
}, },
}, },
iconUrl: {
type: 'string',
optional: true, nullable: true,
},
description: {
type: 'string',
optional: true, nullable: true,
},
}, },
}, },
}, },
@ -88,6 +96,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
createdAt: this.idService.parse(token.id).date.toISOString(), createdAt: this.idService.parse(token.id).date.toISOString(),
lastUsedAt: token.lastUsedAt?.toISOString(), lastUsedAt: token.lastUsedAt?.toISOString(),
permission: token.app ? token.app.permission : token.permission, permission: token.app ? token.app.permission : token.permission,
iconUrl: token.iconUrl,
description: token.description ?? token.app?.description ?? null,
}))); })));
}); });
} }

View File

@ -21,29 +21,7 @@ export const meta = {
type: 'array', type: 'array',
items: { items: {
type: 'object', type: 'object',
properties: { ref: 'UserWebhook',
id: {
type: 'string',
format: 'misskey:id',
},
userId: {
type: 'string',
format: 'misskey:id',
},
name: { type: 'string' },
on: {
type: 'array',
items: {
type: 'string',
enum: webhookEventTypes,
},
},
url: { type: 'string' },
secret: { type: 'string' },
active: { type: 'boolean' },
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
latestStatus: { type: 'integer', nullable: true },
},
}, },
}, },
} as const; } as const;
@ -65,19 +43,17 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
userId: me.id, userId: me.id,
}); });
return webhooks.map(webhook => ( return webhooks.map(webhook => ({
{ id: webhook.id,
id: webhook.id, userId: webhook.userId,
userId: webhook.userId, name: webhook.name,
name: webhook.name, on: webhook.on,
on: webhook.on, url: webhook.url,
url: webhook.url, secret: webhook.secret,
secret: webhook.secret, active: webhook.active,
active: webhook.active, latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null,
latestSentAt: webhook.latestSentAt ? webhook.latestSentAt.toISOString() : null, latestStatus: webhook.latestStatus,
latestStatus: webhook.latestStatus, }));
}
));
}); });
} }
} }

View File

@ -28,29 +28,7 @@ export const meta = {
res: { res: {
type: 'object', type: 'object',
properties: { ref: 'UserWebhook',
id: {
type: 'string',
format: 'misskey:id',
},
userId: {
type: 'string',
format: 'misskey:id',
},
name: { type: 'string' },
on: {
type: 'array',
items: {
type: 'string',
enum: webhookEventTypes,
},
},
url: { type: 'string' },
secret: { type: 'string' },
active: { type: 'boolean' },
latestSentAt: { type: 'string', format: 'date-time', nullable: true },
latestStatus: { type: 'integer', nullable: true },
},
}, },
} as const; } as const;

View File

@ -8,7 +8,7 @@
import { parse as vueSfcParse } from 'vue/compiler-sfc'; import { parse as vueSfcParse } from 'vue/compiler-sfc';
import { import {
createLogger, createLogger,
EnvironmentModuleGraph, type EnvironmentModuleGraph,
type LogErrorOptions, type LogErrorOptions,
type LogOptions, type LogOptions,
normalizePath, normalizePath,

View File

@ -4,11 +4,11 @@
*/ */
import { utils, values } from '@syuilo/aiscript'; import { utils, values } from '@syuilo/aiscript';
import { genId } from '@/utility/id.js';
import { ref } from 'vue'; import { ref } from 'vue';
import type { Ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { assertStringAndIsIn } from './common.js'; import { assertStringAndIsIn } from './common.js';
import type { Ref } from 'vue';
import { genId } from '@/utility/id.js';
const ALIGNS = ['left', 'center', 'right'] as const; const ALIGNS = ['left', 'center', 'right'] as const;
const FONTS = ['serif', 'sans-serif', 'monospace'] as const; const FONTS = ['serif', 'sans-serif', 'monospace'] as const;
@ -21,16 +21,15 @@ type BorderStyle = (typeof BORDER_STYLES)[number];
export type AsUiComponentBase = { export type AsUiComponentBase = {
id: string; id: string;
hidden?: boolean; hidden?: boolean;
children?: AsUiComponent['id'][];
}; };
export type AsUiRoot = AsUiComponentBase & { export type AsUiRoot = AsUiComponentBase & {
type: 'root'; type: 'root';
children: AsUiComponent['id'][];
}; };
export type AsUiContainer = AsUiComponentBase & { export type AsUiContainer = AsUiComponentBase & {
type: 'container'; type: 'container';
children?: AsUiComponent['id'][];
align?: Align; align?: Align;
bgColor?: string; bgColor?: string;
fgColor?: string; fgColor?: string;
@ -123,7 +122,6 @@ export type AsUiSelect = AsUiComponentBase & {
export type AsUiFolder = AsUiComponentBase & { export type AsUiFolder = AsUiComponentBase & {
type: 'folder'; type: 'folder';
children?: AsUiComponent['id'][];
title?: string; title?: string;
opened?: boolean; opened?: boolean;
}; };

View File

@ -61,8 +61,8 @@ import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/utili
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
user: Misskey.entities.User; user: Misskey.entities.User;
withLocked: boolean; withLocked?: boolean;
withDescription: boolean; withDescription?: boolean;
}>(), { }>(), {
withLocked: true, withLocked: true,
withDescription: true, withDescription: true,

View File

@ -39,13 +39,13 @@ withDefaults(defineProps<{
}); });
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'done', r?: Misskey.entities.DriveFolder[]): void; (ev: 'done', r?: (Misskey.entities.DriveFolder | null)[]): void;
(ev: 'closed'): void; (ev: 'closed'): void;
}>(); }>();
const dialog = useTemplateRef('dialog'); const dialog = useTemplateRef('dialog');
const selected = ref<Misskey.entities.DriveFolder[]>([]); const selected = ref<(Misskey.entities.DriveFolder | null)[]>([]);
function ok() { function ok() {
emit('done', selected.value); emit('done', selected.value);
@ -57,7 +57,7 @@ function cancel() {
dialog.value?.close(); dialog.value?.close();
} }
function onChangeSelection(v: Misskey.entities.DriveFolder[]) { function onChangeSelection(v: (Misskey.entities.DriveFolder | null)[]) {
selected.value = v; selected.value = v;
} }
</script> </script>

View File

@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Mfm class="summaryMfm" :text="flash.summary" :plain="true" :nowrap="true"/> <Mfm class="summaryMfm" :text="flash.summary" :plain="true" :nowrap="true"/>
</p> </p>
<footer> <footer>
<img v-if="flash.user.avatarUrl != null" class="icon" :src="flash.user.avatarUrl"/> <img class="icon" :src="flash.user.avatarUrl"/>
<p>{{ userName(flash.user) }}</p> <p>{{ userName(flash.user) }}</p>
</footer> </footer>
</article> </article>

View File

@ -94,6 +94,8 @@ async function calcAspectRatio() {
onMounted(() => { onMounted(() => {
calcAspectRatio(); calcAspectRatio();
if (gallery.value == null) return; // TS
lightbox = new PhotoSwipeLightbox({ lightbox = new PhotoSwipeLightbox({
dataSource: props.mediaList dataSource: props.mediaList
.filter(media => { .filter(media => {

View File

@ -23,8 +23,8 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<div :class="$style.root" class="_forceShrinkSpacer"> <div :class="$style.root" class="_forceShrinkSpacer">
<StackingRouterView v-if="prefer.s['experimental.stackingRouterView']" :key="reloadCount" :router="windowRouter"/> <StackingRouterView v-if="prefer.s['experimental.stackingRouterView']" :key="reloadCount.toString() + ':stacking'" :router="windowRouter"/>
<RouterView v-else :key="reloadCount" :router="windowRouter"/> <RouterView v-else :key="reloadCount.toString() + ':non-stacking'" :router="windowRouter"/>
</div> </div>
</MkWindow> </MkWindow>
</template> </template>
@ -58,20 +58,15 @@ const windowRouter = createRouter(props.initialPath);
const pageMetadata = ref<null | PageMetadata>(null); const pageMetadata = ref<null | PageMetadata>(null);
const windowEl = useTemplateRef('windowEl'); const windowEl = useTemplateRef('windowEl');
const history = ref<{ path: string; }[]>([{ const _history_ = ref<{ path: string; }[]>([{
path: windowRouter.getCurrentFullPath(), path: windowRouter.getCurrentFullPath(),
}]); }]);
const buttonsLeft = computed(() => { const buttonsLeft = computed(() => {
const buttons: Record<string, unknown>[] = []; return _history_.value.length > 1 ? [{
icon: 'ti ti-arrow-left',
if (history.value.length > 1) { title: i18n.ts.goBack,
buttons.push({ onClick: back,
icon: 'ti ti-arrow-left', }] : [];
onClick: back,
});
}
return buttons;
}); });
const buttonsRight = computed(() => { const buttonsRight = computed(() => {
const buttons = [{ const buttons = [{
@ -97,12 +92,12 @@ function getSearchMarker(path: string) {
const searchMarkerId = ref<string | null>(getSearchMarker(props.initialPath)); const searchMarkerId = ref<string | null>(getSearchMarker(props.initialPath));
windowRouter.addListener('push', ctx => { windowRouter.addListener('push', ctx => {
history.value.push({ path: ctx.fullPath }); _history_.value.push({ path: ctx.fullPath });
}); });
windowRouter.addListener('replace', ctx => { windowRouter.addListener('replace', ctx => {
history.value.pop(); _history_.value.pop();
history.value.push({ path: ctx.fullPath }); _history_.value.push({ path: ctx.fullPath });
}); });
windowRouter.addListener('change', ctx => { windowRouter.addListener('change', ctx => {
@ -150,8 +145,8 @@ const contextmenu = computed(() => ([{
}])); }]));
function back() { function back() {
history.value.pop(); _history_.value.pop();
windowRouter.replaceByPath(history.value.at(-1)!.path); windowRouter.replaceByPath(_history_.value.at(-1)!.path);
} }
function reload() { function reload() {

View File

@ -105,9 +105,7 @@ async function addRole() {
.map(r => ({ text: r.name, value: r })); .map(r => ({ text: r.name, value: r }));
const { canceled, result: role } = await os.select({ items }); const { canceled, result: role } = await os.select({ items });
if (canceled) { if (canceled || role == null) return;
return;
}
selectedRoleIds.value.push(role.id); selectedRoleIds.value.push(role.id);
} }

View File

@ -51,6 +51,7 @@ export type DefaultStoredWidget = {
<script lang="ts" setup> <script lang="ts" setup>
import { defineAsyncComponent, ref, computed } from 'vue'; import { defineAsyncComponent, ref, computed } from 'vue';
import { isLink } from '@@/js/is-link.js';
import { genId } from '@/utility/id.js'; import { genId } from '@/utility/id.js';
import MkSelect from '@/components/MkSelect.vue'; import MkSelect from '@/components/MkSelect.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
@ -58,7 +59,6 @@ import { widgets as widgetDefs, federationWidgets } from '@/widgets/index.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { isLink } from '@@/js/is-link.js';
const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default)); const Sortable = defineAsyncComponent(() => import('vuedraggable').then(x => x.default));
@ -81,7 +81,7 @@ const emit = defineEmits<{
(ev: 'updateWidgets', widgets: Widget[]): void; (ev: 'updateWidgets', widgets: Widget[]): void;
(ev: 'addWidget', widget: Widget): void; (ev: 'addWidget', widget: Widget): void;
(ev: 'removeWidget', widget: Widget): void; (ev: 'removeWidget', widget: Widget): void;
(ev: 'updateWidget', widget: Partial<Widget>): void; (ev: 'updateWidget', widget: { id: Widget['id']; data: Widget['data']; }): void;
(ev: 'exit'): void; (ev: 'exit'): void;
}>(); }>();
@ -104,7 +104,7 @@ const addWidget = () => {
const removeWidget = (widget) => { const removeWidget = (widget) => {
emit('removeWidget', widget); emit('removeWidget', widget);
}; };
const updateWidget = (id, data) => { const updateWidget = (id: Widget['id'], data: Widget['data']) => {
emit('updateWidget', { id, data }); emit('updateWidget', { id, data });
}; };

View File

@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
import { waitFor } from '@storybook/test'; import { waitFor } from '@storybook/test';
import MkPageHeader from './MkPageHeader.vue'; import MkPageHeader from './MkPageHeader.vue';
import type { StoryObj } from '@storybook/vue3'; import type { StoryObj } from '@storybook/vue3';
@ -59,6 +59,7 @@ export const Icon = {
{ {
...OneTab.args.tabs[0], ...OneTab.args.tabs[0],
icon: 'ti ti-home', icon: 'ti ti-home',
title: 'Home',
}, },
], ],
}, },
@ -71,6 +72,7 @@ export const IconOnly = {
{ {
key: Icon.args.tabs[0].key, key: Icon.args.tabs[0].key,
icon: Icon.args.tabs[0].icon, icon: Icon.args.tabs[0].icon,
title: Icon.args.tabs[0].title,
iconOnly: true, iconOnly: true,
}, },
], ],

View File

@ -30,19 +30,21 @@ const props = defineProps<{
router?: Router; router?: Router;
}>(); }>();
const router = props.router ?? inject(DI.router); const _router = props.router ?? inject(DI.router);
if (router == null) { if (_router == null) {
throw new Error('no router provided'); throw new Error('no router provided');
} }
const router = _router;
const viewId = randomId(); const viewId = randomId();
provide(DI.viewId, viewId); provide(DI.viewId, viewId);
const currentDepth = inject(DI.routerCurrentDepth, 0); const currentDepth = inject(DI.routerCurrentDepth, 0);
provide(DI.routerCurrentDepth, currentDepth + 1); provide(DI.routerCurrentDepth, currentDepth + 1);
const current = router.current!; const current = router.current;
const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage); const currentPageComponent = shallowRef('component' in current.route ? current.route.component : MkLoadingPage);
const currentPageProps = ref(current.props); const currentPageProps = ref(current.props);
let currentRoutePath = current.route.path; let currentRoutePath = current.route.path;

View File

@ -16,9 +16,11 @@ import { onActivated, onDeactivated, onMounted, onUnmounted } from 'vue';
import MkAchievements from '@/components/MkAchievements.vue'; import MkAchievements from '@/components/MkAchievements.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js'; import { definePage } from '@/page.js';
import { $i } from '@/i.js'; import { ensureSignin } from '@/i.js';
import { claimAchievement } from '@/utility/achievements.js'; import { claimAchievement } from '@/utility/achievements.js';
const $i = ensureSignin();
let timer: number | null; let timer: number | null;
function viewAchievements3min() { function viewAchievements3min() {

View File

@ -156,12 +156,9 @@ async function done() {
isSensitive: isSensitive.value, isSensitive: isSensitive.value,
localOnly: localOnly.value, localOnly: localOnly.value,
roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.value.map(x => x.id), roleIdsThatCanBeUsedThisEmojiAsReaction: rolesThatCanBeUsedThisEmojiAsReaction.value.map(x => x.id),
fileId: file.value ? file.value.id : undefined,
}; };
if (file.value) {
params.fileId = file.value.id;
}
if (props.emoji) { if (props.emoji) {
await os.apiWithDialog('admin/emoji/update', { await os.apiWithDialog('admin/emoji/update', {
id: props.emoji.id, id: props.emoji.id,
@ -177,7 +174,12 @@ async function done() {
windowEl.value?.close(); windowEl.value?.close();
} else { } else {
const created = await os.apiWithDialog('admin/emoji/add', params); if (params.fileId == null) return;
const created = await os.apiWithDialog('admin/emoji/add', {
...params,
fileId: params.fileId, // TS
});
emit('done', { emit('done', {
created: created, created: created,

View File

@ -48,7 +48,7 @@ function _fetch_() {
if (res.type === 'User') { if (res.type === 'User') {
mainRouter.replace('/@:acct/:page?', { mainRouter.replace('/@:acct/:page?', {
params: { params: {
acct: res.host != null ? `${res.object.username}@${res.object.host}` : res.object.username, acct: res.object.host != null ? `${res.object.username}@${res.object.host}` : res.object.username,
}, },
}); });
} else if (res.type === 'Note') { } else if (res.type === 'Note') {

View File

@ -82,10 +82,10 @@ const logs = ref<{
text: string; text: string;
print: boolean; print: boolean;
}[]>([]); }[]>([]);
const root = ref<AsUiRoot>(); const root = ref<AsUiRoot | undefined>();
const components = ref<Ref<AsUiComponent>[]>([]); const components = ref<Ref<AsUiComponent>[]>([]);
const uiKey = ref(0); const uiKey = ref(0);
const uiInspectorOpenedComponents = ref(new Map<string, boolean>); const uiInspectorOpenedComponents = ref(new WeakMap<AsUiComponent | Ref<AsUiComponent>, boolean>);
const saved = miLocalStorage.getItem('scratchpad'); const saved = miLocalStorage.getItem('scratchpad');
if (saved) { if (saved) {
@ -186,11 +186,13 @@ const headerActions = computed(() => []);
const headerTabs = computed(() => []); const headerTabs = computed(() => []);
const showns = computed(() => { const showns = computed(() => {
if (root.value == null) return new Set<string>();
const result = new Set<string>(); const result = new Set<string>();
(function addChildrenToResult(c: AsUiComponent) { (function addChildrenToResult(c: AsUiComponent) {
result.add(c.id); result.add(c.id);
if (c.children) { const children = c.children;
const childComponents = components.value.filter(v => c.children.includes(v.value.id)); if (children) {
const childComponents = components.value.filter(v => children.includes(v.value.id));
for (const child of childComponents) { for (const child of childComponents) {
addChildrenToResult(child.value); addChildrenToResult(child.value);
} }

View File

@ -91,7 +91,7 @@ async function addItem() {
value: '-', text: i18n.ts.divider, value: '-', text: i18n.ts.divider,
}], }],
}); });
if (canceled) return; if (canceled || item == null) return;
items.value = [...items.value, { items.value = [...items.value, {
id: genId(), id: genId(),
type: item, type: item,

View File

@ -40,7 +40,7 @@ async function install() {
code.value = null; code.value = null;
router.push('/settings/plugin'); router.push('/settings/plugin');
} catch (err) { } catch (err: any) {
os.alert({ os.alert({
type: 'error', type: 'error',
title: 'Install failed', title: 'Install failed',

View File

@ -53,7 +53,7 @@ function getInstanceIcon(instance: Misskey.entities.FederationInstance): string
misskeyApiGet('federation/instances', { misskeyApiGet('federation/instances', {
sort: '+pubSub', sort: '+pubSub',
limit: 20, limit: 20,
blocked: 'false', blocked: false,
}).then(_instances => { }).then(_instances => {
instances.value = _instances; instances.value = _instances;
}); });

View File

@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
mode="default" mode="default"
> >
<MkMarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse"> <MkMarqueeText :key="key" :duration="marqueeDuration" :reverse="marqueeReverse">
<span v-for="instance in instances" :key="instance.id" :class="[$style.item, { [$style.colored]: colored }]" :style="{ background: colored ? instance.themeColor : '' }"> <span v-for="instance in instances" :key="instance.id" :class="[$style.item, { [$style.colored]: colored }]" :style="{ background: colored ? instance.themeColor ?? '' : '' }">
<img :class="$style.icon" :src="getInstanceIcon(instance)" alt=""/> <img :class="$style.icon" :src="getInstanceIcon(instance)" alt=""/>
<MkA :to="`/instance-info/${instance.host}`" :class="$style.host" class="_monospace"> <MkA :to="`/instance-info/${instance.host}`" :class="$style.host" class="_monospace">
{{ instance.host }} {{ instance.host }}

View File

@ -300,15 +300,13 @@ export async function createCroppedImageDriveFileFromImageDriveFile(imageDriveFi
}); });
} }
export async function selectDriveFolder(initialFolder: Misskey.entities.DriveFolder['id'] | null): Promise<Misskey.entities.DriveFolder[]> { export async function selectDriveFolder(initialFolder: Misskey.entities.DriveFolder['id'] | null): Promise<(Misskey.entities.DriveFolder | null)[]> {
return new Promise(async resolve => { return new Promise(async resolve => {
const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkDriveFolderSelectDialog.vue').then(x => x.default), { const { dispose } = await os.popupAsyncWithDialog(import('@/components/MkDriveFolderSelectDialog.vue').then(x => x.default), {
initialFolder, initialFolder,
}, { }, {
done: folders => { done: folders => {
if (folders) { resolve(folders);
resolve(folders);
}
}, },
closed: () => dispose(), closed: () => dispose(),
}); });

View File

@ -9,7 +9,7 @@ import * as mfm from 'mfm-js';
export function extractMentions(nodes: mfm.MfmNode[]): mfm.MfmMention['props'][] { export function extractMentions(nodes: mfm.MfmNode[]): mfm.MfmMention['props'][] {
// TODO: 重複を削除 // TODO: 重複を削除
const mentionNodes = mfm.extract(nodes, (node) => node.type === 'mention'); const mentionNodes = mfm.extract(nodes, (node) => node.type === 'mention') as mfm.MfmMention[];
const mentions = mentionNodes.map(x => x.props); const mentions = mentionNodes.map(x => x.props);
return mentions; return mentions;

View File

@ -15,7 +15,7 @@ import 'intersection-observer';
describe('XHome', () => { describe('XHome', () => {
const renderHome = (user: Partial<Misskey.entities.UserDetailed>): RenderResult => { const renderHome = (user: Partial<Misskey.entities.UserDetailed>): RenderResult => {
return render(XHome, { return render(XHome, {
props: { user, disableNotes: true }, props: { user: user as Misskey.entities.UserDetailed, disableNotes: true },
global: { directives, components }, global: { directives, components },
}); });
}; };

View File

@ -29,7 +29,7 @@ describe('MkMediaImage', () => {
comment: null, comment: null,
properties: {}, properties: {},
...image, ...image,
} as DriveFile, } as Misskey.entities.DriveFile,
}, },
global: { directives, components }, global: { directives, components },
}); });

View File

@ -55,6 +55,7 @@
"./@types/**/*.ts" "./@types/**/*.ts"
], ],
"exclude": [ "exclude": [
".storybook/**/*" ".storybook/**/*",
"./src/**/*.stories.ts"
] ]
} }

View File

@ -2157,6 +2157,7 @@ declare namespace entities {
Note, Note,
NoteDraft, NoteDraft,
NoteReaction, NoteReaction,
NoteReactionWithNote,
NoteFavorite, NoteFavorite,
Notification_2 as Notification, Notification_2 as Notification,
DriveFile, DriveFile,
@ -2198,6 +2199,7 @@ declare namespace entities {
MetaLite, MetaLite,
MetaDetailedOnly, MetaDetailedOnly,
MetaDetailed, MetaDetailed,
UserWebhook,
SystemWebhook, SystemWebhook,
AbuseReportNotificationRecipient, AbuseReportNotificationRecipient,
ChatMessage, ChatMessage,
@ -2967,10 +2969,13 @@ type ModerationLog = {
} | { } | {
type: 'deleteChatRoom'; type: 'deleteChatRoom';
info: ModerationLogPayloads['deleteChatRoom']; info: ModerationLogPayloads['deleteChatRoom'];
} | {
type: 'updateProxyAccountDescription';
info: ModerationLogPayloads['updateProxyAccountDescription'];
}); });
// @public (undocumented) // @public (undocumented)
export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost", "deleteChatRoom"]; export const moderationLogTypes: readonly ["updateServerSettings", "suspend", "unsuspend", "updateUserNote", "addCustomEmoji", "updateCustomEmoji", "deleteCustomEmoji", "assignRole", "unassignRole", "createRole", "updateRole", "deleteRole", "clearQueue", "promoteQueue", "deleteDriveFile", "deleteNote", "createGlobalAnnouncement", "createUserAnnouncement", "updateGlobalAnnouncement", "updateUserAnnouncement", "deleteGlobalAnnouncement", "deleteUserAnnouncement", "resetPassword", "suspendRemoteInstance", "unsuspendRemoteInstance", "updateRemoteInstanceNote", "markSensitiveDriveFile", "unmarkSensitiveDriveFile", "resolveAbuseReport", "forwardAbuseReport", "updateAbuseReportNote", "createInvitation", "createAd", "updateAd", "deleteAd", "createAvatarDecoration", "updateAvatarDecoration", "deleteAvatarDecoration", "unsetUserAvatar", "unsetUserBanner", "createSystemWebhook", "updateSystemWebhook", "deleteSystemWebhook", "createAbuseReportNotificationRecipient", "updateAbuseReportNotificationRecipient", "deleteAbuseReportNotificationRecipient", "deleteAccount", "deletePage", "deleteFlash", "deleteGalleryPost", "deleteChatRoom", "updateProxyAccountDescription"];
// @public (undocumented) // @public (undocumented)
type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json']; type MuteCreateRequest = operations['mute___create']['requestBody']['content']['application/json'];
@ -3015,6 +3020,9 @@ type NoteFavorite = components['schemas']['NoteFavorite'];
// @public (undocumented) // @public (undocumented)
type NoteReaction = components['schemas']['NoteReaction']; type NoteReaction = components['schemas']['NoteReaction'];
// @public (undocumented)
type NoteReactionWithNote = components['schemas']['NoteReactionWithNote'];
// @public (undocumented) // @public (undocumented)
type NotesChildrenRequest = operations['notes___children']['requestBody']['content']['application/json']; type NotesChildrenRequest = operations['notes___children']['requestBody']['content']['application/json'];
@ -3818,6 +3826,9 @@ type UsersShowResponse = operations['users___show']['responses']['200']['content
// @public (undocumented) // @public (undocumented)
type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['content']['application/json']; type UsersUpdateMemoRequest = operations['users___update-memo']['requestBody']['content']['application/json'];
// @public (undocumented)
type UserWebhook = components['schemas']['UserWebhook'];
// @public (undocumented) // @public (undocumented)
type V2AdminEmojiListRequest = operations['v2___admin___emoji___list']['requestBody']['content']['application/json']; type V2AdminEmojiListRequest = operations['v2___admin___emoji___list']['requestBody']['content']['application/json'];

View File

@ -16,6 +16,7 @@ export type App = components['schemas']['App'];
export type Note = components['schemas']['Note']; export type Note = components['schemas']['Note'];
export type NoteDraft = components['schemas']['NoteDraft']; export type NoteDraft = components['schemas']['NoteDraft'];
export type NoteReaction = components['schemas']['NoteReaction']; export type NoteReaction = components['schemas']['NoteReaction'];
export type NoteReactionWithNote = components['schemas']['NoteReactionWithNote'];
export type NoteFavorite = components['schemas']['NoteFavorite']; export type NoteFavorite = components['schemas']['NoteFavorite'];
export type Notification = components['schemas']['Notification']; export type Notification = components['schemas']['Notification'];
export type DriveFile = components['schemas']['DriveFile']; export type DriveFile = components['schemas']['DriveFile'];
@ -57,6 +58,7 @@ export type ReversiGameDetailed = components['schemas']['ReversiGameDetailed'];
export type MetaLite = components['schemas']['MetaLite']; export type MetaLite = components['schemas']['MetaLite'];
export type MetaDetailedOnly = components['schemas']['MetaDetailedOnly']; export type MetaDetailedOnly = components['schemas']['MetaDetailedOnly'];
export type MetaDetailed = components['schemas']['MetaDetailed']; export type MetaDetailed = components['schemas']['MetaDetailed'];
export type UserWebhook = components['schemas']['UserWebhook'];
export type SystemWebhook = components['schemas']['SystemWebhook']; export type SystemWebhook = components['schemas']['SystemWebhook'];
export type AbuseReportNotificationRecipient = components['schemas']['AbuseReportNotificationRecipient']; export type AbuseReportNotificationRecipient = components['schemas']['AbuseReportNotificationRecipient'];
export type ChatMessage = components['schemas']['ChatMessage']; export type ChatMessage = components['schemas']['ChatMessage'];

View File

@ -3949,7 +3949,7 @@ export type components = {
*/ */
host: string | null; host: string | null;
/** Format: url */ /** Format: url */
avatarUrl: string | null; avatarUrl: string;
avatarBlurhash: string | null; avatarBlurhash: string | null;
avatarDecorations: { avatarDecorations: {
/** Format: id */ /** Format: id */
@ -4085,7 +4085,7 @@ export type components = {
unreadNotificationsCount: number; unreadNotificationsCount: number;
mutedWords: string[][]; mutedWords: string[][];
hardMutedWords: string[][]; hardMutedWords: string[][];
mutedInstances: string[] | null; mutedInstances: string[];
notificationRecieveConfig: { notificationRecieveConfig: {
note?: { note?: {
/** @enum {string} */ /** @enum {string} */
@ -4454,16 +4454,22 @@ export type components = {
reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null; reactionAcceptance: 'likeOnly' | 'likeOnlyForRemote' | 'nonSensitiveOnly' | 'nonSensitiveOnlyForLocalLikeOnlyForRemote' | null;
}; };
NoteReaction: { NoteReaction: {
/** /** Format: id */
* Format: id
* @example xxxxxxxxxx
*/
id: string; id: string;
/** Format: date-time */ /** Format: date-time */
createdAt: string; createdAt: string;
user: components['schemas']['UserLite']; user: components['schemas']['UserLite'];
type: string; type: string;
}; };
NoteReactionWithNote: {
/** Format: id */
id: string;
/** Format: date-time */
createdAt: string;
user: components['schemas']['UserLite'];
type: string;
note: components['schemas']['Note'];
};
NoteFavorite: { NoteFavorite: {
/** /**
* Format: id * Format: id
@ -5437,6 +5443,20 @@ export type components = {
cacheRemoteSensitiveFiles: boolean; cacheRemoteSensitiveFiles: boolean;
}; };
MetaDetailed: components['schemas']['MetaLite'] & components['schemas']['MetaDetailedOnly']; MetaDetailed: components['schemas']['MetaLite'] & components['schemas']['MetaDetailedOnly'];
UserWebhook: {
/** Format: id */
id: string;
/** Format: id */
userId: string;
name: string;
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
url: string;
secret: string;
active: boolean;
/** Format: date-time */
latestSentAt: string | null;
latestStatus: number | null;
};
SystemWebhook: { SystemWebhook: {
id: string; id: string;
isActive: boolean; isActive: boolean;
@ -6694,6 +6714,13 @@ export interface operations {
updatedAt: string | null; updatedAt: string | null;
text: string; text: string;
title: string; title: string;
icon: string | null;
display: string;
isActive: boolean;
forExistingUsers: boolean;
silence: boolean;
needConfirmationToRead: boolean;
userId: string | null;
imageUrl: string | null; imageUrl: string | null;
reads: number; reads: number;
}[]; }[];
@ -7655,6 +7682,10 @@ export interface operations {
folderId: string | null; folderId: string | null;
isSensitive: boolean; isSensitive: boolean;
isLink: boolean; isLink: boolean;
maybeSensitive: boolean;
maybePorn: boolean;
requestIp: string | null;
requestHeaders: Record<string, never> | null;
}; };
}; };
}; };
@ -9298,8 +9329,10 @@ export interface operations {
mcaptchaSecretKey: string | null; mcaptchaSecretKey: string | null;
recaptchaSecretKey: string | null; recaptchaSecretKey: string | null;
turnstileSecretKey: string | null; turnstileSecretKey: string | null;
sensitiveMediaDetection: string; /** @enum {string} */
sensitiveMediaDetectionSensitivity: string; sensitiveMediaDetection: 'none' | 'all' | 'local' | 'remote';
/** @enum {string} */
sensitiveMediaDetectionSensitivity: 'medium' | 'low' | 'high' | 'veryLow' | 'veryHigh';
setSensitiveFlagAutomatically: boolean; setSensitiveFlagAutomatically: boolean;
enableSensitiveMediaDetectionForVideos: boolean; enableSensitiveMediaDetectionForVideos: boolean;
/** Format: id */ /** Format: id */
@ -9362,6 +9395,7 @@ export interface operations {
privacyPolicyUrl: string | null; privacyPolicyUrl: string | null;
inquiryUrl: string | null; inquiryUrl: string | null;
repositoryUrl: string | null; repositoryUrl: string | null;
feedbackUrl: string | null;
/** /**
* @deprecated * @deprecated
* @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead. * @description [Deprecated] Use "urlPreviewSummaryProxyUrl" instead.
@ -24401,6 +24435,8 @@ export interface operations {
/** Format: date-time */ /** Format: date-time */
lastUsedAt?: string; lastUsedAt?: string;
permission: string[]; permission: string[];
iconUrl?: string | null;
description?: string | null;
}[]; }[];
}; };
}; };
@ -27636,20 +27672,7 @@ export interface operations {
[name: string]: unknown; [name: string]: unknown;
}; };
content: { content: {
'application/json': { 'application/json': components['schemas']['UserWebhook'][];
/** Format: misskey:id */
id: string;
/** Format: misskey:id */
userId: string;
name: string;
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
url: string;
secret: string;
active: boolean;
/** Format: date-time */
latestSentAt: string | null;
latestStatus: number | null;
}[];
}; };
}; };
/** @description Client error */ /** @description Client error */
@ -27715,20 +27738,7 @@ export interface operations {
[name: string]: unknown; [name: string]: unknown;
}; };
content: { content: {
'application/json': { 'application/json': components['schemas']['UserWebhook'];
/** Format: misskey:id */
id: string;
/** Format: misskey:id */
userId: string;
name: string;
on: ('mention' | 'unfollow' | 'follow' | 'followed' | 'note' | 'reply' | 'renote' | 'reaction')[];
url: string;
secret: string;
active: boolean;
/** Format: date-time */
latestSentAt: string | null;
latestStatus: number | null;
};
}; };
}; };
/** @description Client error */ /** @description Client error */
@ -35752,7 +35762,7 @@ export interface operations {
[name: string]: unknown; [name: string]: unknown;
}; };
content: { content: {
'application/json': components['schemas']['NoteReaction'][]; 'application/json': components['schemas']['NoteReactionWithNote'][];
}; };
}; };
/** @description Client error */ /** @description Client error */

View File

@ -167,6 +167,7 @@ export const moderationLogTypes = [
'deleteFlash', 'deleteFlash',
'deleteGalleryPost', 'deleteGalleryPost',
'deleteChatRoom', 'deleteChatRoom',
'updateProxyAccountDescription',
] as const; ] as const;
export const queueTypes = [ export const queueTypes = [
@ -193,7 +194,15 @@ export const reversiUpdateKeys = [
export type ReversiUpdateKey = typeof reversiUpdateKeys[number]; export type ReversiUpdateKey = typeof reversiUpdateKeys[number];
type AvatarDecoration = UserLite['avatarDecorations'][number]; type AvatarDecoration = {
id: string;
name: string;
url: string;
angle?: number;
flipH?: boolean;
offsetX?: number;
offsetY?: number;
};
type ReceivedAbuseReport = { type ReceivedAbuseReport = {
reportId: AbuseReportNotificationRecipient['id']; reportId: AbuseReportNotificationRecipient['id'];
@ -455,4 +464,8 @@ export type ModerationLogPayloads = {
roomId: string; roomId: string;
room: ChatRoom; room: ChatRoom;
}; };
updateProxyAccountDescription: {
before: string | null;
after: string | null;
}
}; };

View File

@ -203,6 +203,9 @@ export type ModerationLog = {
} | { } | {
type: 'deleteChatRoom'; type: 'deleteChatRoom';
info: ModerationLogPayloads['deleteChatRoom']; info: ModerationLogPayloads['deleteChatRoom'];
} | {
type: 'updateProxyAccountDescription';
info: ModerationLogPayloads['updateProxyAccountDescription'];
}); });
export type ServerStats = { export type ServerStats = {