merge: misskey 2024.7 (!583)

View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/583

Approved-by: Marie <github@yuugi.dev>
Approved-by: Julia Johannesen <julia@insertdomain.name>
This commit is contained in:
dakkar 2024-08-18 18:32:27 +00:00
commit f5560783ea
598 changed files with 23943 additions and 9812 deletions

View file

@ -14,6 +14,7 @@ import { CacheService } from '@/core/CacheService.js';
import { MiFollowing, MiUserProfile } from '@/models/_.js';
import type { StreamEventEmitter, GlobalEvents } from '@/core/GlobalEventService.js';
import { ChannelFollowingService } from '@/core/ChannelFollowingService.js';
import type { JsonObject } from '@/misc/json-value.js';
import type { ChannelsService } from './ChannelsService.js';
import type { EventEmitter } from 'events';
import type Channel from './channel.js';
@ -33,7 +34,7 @@ export default class Connection {
private wsConnection: WebSocket.WebSocket;
public subscriber: StreamEventEmitter;
private channels: Channel[] = [];
private subscribingNotes: any = {};
private subscribingNotes: Partial<Record<string, number>> = {};
private cachedNotes: Packed<'Note'>[] = [];
public userProfile: MiUserProfile | null = null;
public following: Record<string, Pick<MiFollowing, 'withReplies'> | undefined> = {};
@ -64,7 +65,7 @@ export default class Connection {
if (token) this.token = token;
if (rateLimiter) this.rateLimiter = rateLimiter;
this.logger = loggerService.getLogger('streaming', 'coral', false);
this.logger = loggerService.getLogger('streaming', 'coral');
}
@bindThis
@ -115,7 +116,7 @@ export default class Connection {
*/
@bindThis
private async onWsConnectionMessage(data: WebSocket.RawData) {
let obj: Record<string, any>;
let obj: JsonObject;
if (this.closingConnection) return;
@ -148,6 +149,8 @@ export default class Connection {
const { type, body } = obj;
if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
switch (type) {
case 'readNotification': this.onReadNotification(body); break;
case 'subNote': this.onSubscribeNote(body); break;
@ -188,7 +191,7 @@ export default class Connection {
}
@bindThis
private readNote(body: any) {
private readNote(body: JsonObject) {
const id = body.id;
const note = this.cachedNotes.find(n => n.id === id);
@ -200,7 +203,7 @@ export default class Connection {
}
@bindThis
private onReadNotification(payload: any) {
private onReadNotification(payload: JsonObject) {
this.notificationService.readAllNotification(this.user!.id);
}
@ -208,16 +211,14 @@ export default class Connection {
* 稿
*/
@bindThis
private onSubscribeNote(payload: any) {
if (!payload.id) return;
private onSubscribeNote(payload: JsonObject) {
if (!payload.id || typeof payload.id !== 'string') return;
if (this.subscribingNotes[payload.id] == null) {
this.subscribingNotes[payload.id] = 0;
}
const current = this.subscribingNotes[payload.id] ?? 0;
const updated = current + 1;
this.subscribingNotes[payload.id] = updated;
this.subscribingNotes[payload.id]++;
if (this.subscribingNotes[payload.id] === 1) {
if (updated === 1) {
this.subscriber.on(`noteStream:${payload.id}`, this.onNoteStreamMessage);
}
}
@ -226,11 +227,14 @@ export default class Connection {
* 稿
*/
@bindThis
private onUnsubscribeNote(payload: any) {
if (!payload.id) return;
private onUnsubscribeNote(payload: JsonObject) {
if (!payload.id || typeof payload.id !== 'string') return;
this.subscribingNotes[payload.id]--;
if (this.subscribingNotes[payload.id] <= 0) {
const current = this.subscribingNotes[payload.id];
if (current == null) return;
const updated = current - 1;
this.subscribingNotes[payload.id] = updated;
if (updated <= 0) {
delete this.subscribingNotes[payload.id];
this.subscriber.off(`noteStream:${payload.id}`, this.onNoteStreamMessage);
}
@ -261,17 +265,22 @@ export default class Connection {
*
*/
@bindThis
private onChannelConnectRequested(payload: any) {
private onChannelConnectRequested(payload: JsonObject) {
const { channel, id, params, pong } = payload;
this.connectChannel(id, params, channel, pong);
if (typeof id !== 'string') return;
if (typeof channel !== 'string') return;
if (typeof pong !== 'boolean' && typeof pong !== 'undefined' && pong !== null) return;
if (typeof params !== 'undefined' && (typeof params !== 'object' || params === null || Array.isArray(params))) return;
this.connectChannel(id, params, channel, pong ?? undefined);
}
/**
*
*/
@bindThis
private onChannelDisconnectRequested(payload: any) {
private onChannelDisconnectRequested(payload: JsonObject) {
const { id } = payload;
if (typeof id !== 'string') return;
this.disconnectChannel(id);
}
@ -279,7 +288,7 @@ export default class Connection {
*
*/
@bindThis
public sendMessageToWs(type: string, payload: any) {
public sendMessageToWs(type: string, payload: JsonObject) {
this.wsConnection.send(JSON.stringify({
type: type,
body: payload,
@ -290,7 +299,7 @@ export default class Connection {
*
*/
@bindThis
public connectChannel(id: string, params: any, channel: string, pong = false) {
public connectChannel(id: string, params: JsonObject | undefined, channel: string, pong = false) {
if (this.channels.length >= MAX_CHANNELS_PER_CONNECTION) {
return;
}
@ -341,7 +350,11 @@ export default class Connection {
* @param data
*/
@bindThis
private onChannelMessageRequested(data: any) {
private onChannelMessageRequested(data: JsonObject) {
if (typeof data.id !== 'string') return;
if (typeof data.type !== 'string') return;
if (typeof data.body === 'undefined') return;
const channel = this.channels.find(c => c.id === data.id);
if (channel != null && channel.onMessage != null) {
channel.onMessage(data.type, data.body);

View file

@ -8,6 +8,7 @@ import { isInstanceMuted } from '@/misc/is-instance-muted.js';
import { isUserRelated } from '@/misc/is-user-related.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { Packed } from '@/misc/json-schema.js';
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import type Connection from './Connection.js';
/**
@ -81,10 +82,12 @@ export default abstract class Channel {
this.connection = connection;
}
public send(payload: { type: string, body: JsonValue }): void
public send(type: string, payload: JsonValue): void
@bindThis
public send(typeOrPayload: any, payload?: any) {
const type = payload === undefined ? typeOrPayload.type : typeOrPayload;
const body = payload === undefined ? typeOrPayload.body : payload;
public send(typeOrPayload: { type: string, body: JsonValue } | string, payload?: JsonValue) {
const type = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).type : (typeOrPayload as string);
const body = payload === undefined ? (typeOrPayload as { type: string, body: JsonValue }).body : payload;
this.connection.sendMessageToWs('channel', {
id: this.id,
@ -93,11 +96,11 @@ export default abstract class Channel {
});
}
public abstract init(params: any): void;
public abstract init(params: JsonObject): void;
public dispose?(): void;
public onMessage?(type: string, body: any): void;
public onMessage?(type: string, body: JsonValue): void;
}
export type MiChannelService<T extends boolean> = {

View file

@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class AdminChannel extends Channel {
@ -14,7 +15,7 @@ class AdminChannel extends Channel {
public static kind = 'read:admin:stream';
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
// Subscribe admin stream
this.subscriber.on(`adminStream:${this.user!.id}`, data => {
this.send(data);

View file

@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class AntennaChannel extends Channel {
@ -27,8 +28,9 @@ class AntennaChannel extends Channel {
}
@bindThis
public async init(params: any) {
this.antennaId = params.antennaId as string;
public async init(params: JsonObject) {
if (typeof params.antennaId !== 'string') return;
this.antennaId = params.antennaId;
// Subscribe stream
this.subscriber.on(`antennaStream:${this.antennaId}`, this.onEvent);

View file

@ -11,6 +11,7 @@ import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import type { MiMeta } from '@/models/Meta.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { MiChannelService } from '../channel.js';
class BubbleTimelineChannel extends Channel {
@ -35,13 +36,13 @@ class BubbleTimelineChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.btlAvailable) return;
this.withRenotes = params.withRenotes ?? true;
this.withFiles = params.withFiles ?? false;
this.withBots = params.withBots ?? true;
this.withRenotes = !!(params.withRenotes ?? true);
this.withFiles = !!(params.withFiles ?? false);
this.withBots = !!(params.withBots ?? true);
this.instance = await this.metaService.fetch();
// Subscribe events

View file

@ -8,6 +8,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class ChannelChannel extends Channel {
@ -30,9 +31,10 @@ class ChannelChannel extends Channel {
@bindThis
public async init(params: any) {
this.channelId = params.channelId as string;
this.withFiles = params.withFiles ?? false;
this.withRenotes = params.withRenotes ?? true;
if (typeof params.channelId !== 'string') return;
this.channelId = params.channelId;
this.withFiles = !!(params.withFiles ?? false);
this.withRenotes = !!(params.withRenotes ?? true);
// Subscribe stream
this.subscriber.on('notesStream', this.onNote);

View file

@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class DriveChannel extends Channel {
@ -14,7 +15,7 @@ class DriveChannel extends Channel {
public static kind = 'read:account';
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
// Subscribe drive stream
this.subscriber.on(`driveStream:${this.user!.id}`, data => {
this.send(data);

View file

@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class GlobalTimelineChannel extends Channel {
@ -33,13 +34,13 @@ class GlobalTimelineChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.gtlAvailable) return;
this.withRenotes = params.withRenotes ?? true;
this.withFiles = params.withFiles ?? false;
this.withBots = params.withBots ?? true;
this.withRenotes = !!(params.withRenotes ?? true);
this.withFiles = !!(params.withFiles ?? false);
this.withBots = !!(params.withBots ?? true);
// Subscribe events
this.subscriber.on('notesStream', this.onNote);

View file

@ -9,6 +9,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class HashtagChannel extends Channel {
@ -28,11 +29,11 @@ class HashtagChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
if (!Array.isArray(params.q)) return;
if (!params.q.every(x => Array.isArray(x) && x.every(y => typeof y === 'string'))) return;
this.q = params.q;
if (this.q == null) return;
// Subscribe stream
this.subscriber.on('notesStream', this.onNote);
}

View file

@ -8,6 +8,7 @@ import type { Packed } from '@/misc/json-schema.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class HomeTimelineChannel extends Channel {
@ -29,9 +30,9 @@ class HomeTimelineChannel extends Channel {
}
@bindThis
public async init(params: any) {
this.withRenotes = params.withRenotes ?? true;
this.withFiles = params.withFiles ?? false;
public async init(params: JsonObject) {
this.withRenotes = !!(params.withRenotes ?? true);
this.withFiles = !!(params.withFiles ?? false);
this.subscriber.on('notesStream', this.onNote);
}
@ -59,7 +60,7 @@ class HomeTimelineChannel extends Channel {
const reply = note.reply;
if (this.following[note.userId]?.withReplies) {
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
} else {
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
if (reply.userId !== this.user!.id && !isMe && reply.userId !== note.userId) return;
@ -74,7 +75,7 @@ class HomeTimelineChannel extends Channel {
if (note.renote.reply) {
const reply = note.renote.reply;
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信のリノートは弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
}
}

View file

@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class HybridTimelineChannel extends Channel {
@ -35,14 +36,14 @@ class HybridTimelineChannel extends Channel {
}
@bindThis
public async init(params: any): Promise<void> {
public async init(params: JsonObject): Promise<void> {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.ltlAvailable) return;
this.withRenotes = params.withRenotes ?? true;
this.withReplies = params.withReplies ?? false;
this.withBots = params.withBots ?? true;
this.withFiles = params.withFiles ?? false;
this.withRenotes = !!(params.withRenotes ?? true);
this.withReplies = !!(params.withReplies ?? false);
this.withFiles = !!(params.withFiles ?? false);
this.withBots = !!(params.withBots ?? true);
// Subscribe events
this.subscriber.on('notesStream', this.onNote);
@ -78,7 +79,7 @@ class HybridTimelineChannel extends Channel {
const reply = note.reply;
if ((this.following[note.userId]?.withReplies ?? false) || this.withReplies) {
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信は弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId)) return;
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
} else {
// 「チャンネル接続主への返信」でもなければ、「チャンネル接続主が行った返信」でもなければ、「投稿者の投稿者自身への返信」でもない場合
if (reply.userId !== this.user!.id && !isMe && reply.userId !== note.userId) return;
@ -87,7 +88,15 @@ class HybridTimelineChannel extends Channel {
if (note.user.isSilenced && !this.following[note.userId] && note.userId !== this.user!.id) return;
if (isRenotePacked(note) && !isQuotePacked(note) && !this.withRenotes) return;
// 純粋なリノート(引用リノートでないリノート)の場合
if (isRenotePacked(note) && !isQuotePacked(note) && note.renote) {
if (!this.withRenotes) return;
if (note.renote.reply) {
const reply = note.renote.reply;
// 自分のフォローしていないユーザーの visibility: followers な投稿への返信のリノートは弾く
if (reply.visibility === 'followers' && !Object.hasOwn(this.following, reply.userId) && reply.userId !== this.user!.id) return;
}
}
if (this.user && note.renoteId && !note.text) {
if (note.renote && Object.keys(note.renote.reactions).length > 0) {

View file

@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import { isQuotePacked, isRenotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class LocalTimelineChannel extends Channel {
@ -34,14 +35,14 @@ class LocalTimelineChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
const policies = await this.roleService.getUserPolicies(this.user ? this.user.id : null);
if (!policies.ltlAvailable) return;
this.withRenotes = params.withRenotes ?? true;
this.withReplies = params.withReplies ?? false;
this.withBots = params.withBots ?? true;
this.withFiles = params.withFiles ?? false;
this.withRenotes = !!(params.withRenotes ?? true);
this.withReplies = !!(params.withReplies ?? false);
this.withFiles = !!(params.withFiles ?? false);
this.withBots = !!(params.withBots ?? true);
// Subscribe events
this.subscriber.on('notesStream', this.onNote);

View file

@ -7,6 +7,7 @@ import { Injectable } from '@nestjs/common';
import { isInstanceMuted, isUserFromMutedInstance } from '@/misc/is-instance-muted.js';
import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class MainChannel extends Channel {
@ -25,7 +26,7 @@ class MainChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
// Subscribe main stream channel
this.subscriber.on(`mainStream:${this.user!.id}`, async data => {
switch (data.type) {

View file

@ -6,6 +6,7 @@
import Xev from 'xev';
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
const ev = new Xev();
@ -22,19 +23,22 @@ class QueueStatsChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
ev.addListener('queueStats', this.onStats);
}
@bindThis
private onStats(stats: any) {
private onStats(stats: JsonObject) {
this.send('stats', stats);
}
@bindThis
public onMessage(type: string, body: any) {
public onMessage(type: string, body: JsonValue) {
switch (type) {
case 'requestLog':
if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
if (typeof body.id !== 'string') return;
if (typeof body.length !== 'number') return;
ev.once(`queueStatsLog:${body.id}`, statsLog => {
this.send('statsLog', statsLog);
});

View file

@ -9,6 +9,7 @@ import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { ReversiService } from '@/core/ReversiService.js';
import { ReversiGameEntityService } from '@/core/entities/ReversiGameEntityService.js';
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class ReversiGameChannel extends Channel {
@ -28,25 +29,41 @@ class ReversiGameChannel extends Channel {
}
@bindThis
public async init(params: any) {
this.gameId = params.gameId as string;
public async init(params: JsonObject) {
if (typeof params.gameId !== 'string') return;
this.gameId = params.gameId;
this.subscriber.on(`reversiGameStream:${this.gameId}`, this.send);
}
@bindThis
public onMessage(type: string, body: any) {
public onMessage(type: string, body: JsonValue) {
switch (type) {
case 'ready': this.ready(body); break;
case 'updateSettings': this.updateSettings(body.key, body.value); break;
case 'cancel': this.cancelGame(); break;
case 'putStone': this.putStone(body.pos, body.id); break;
case 'ready':
if (typeof body !== 'boolean') return;
this.ready(body);
break;
case 'updateSettings':
if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
if (typeof body.key !== 'string') return;
if (typeof body.value !== 'object' || body.value === null || Array.isArray(body.value)) return;
this.updateSettings(body.key, body.value);
break;
case 'cancel':
this.cancelGame();
break;
case 'putStone':
if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
if (typeof body.pos !== 'number') return;
if (typeof body.id !== 'string') return;
this.putStone(body.pos, body.id);
break;
case 'claimTimeIsUp': this.claimTimeIsUp(); break;
}
}
@bindThis
private async updateSettings(key: string, value: any) {
private async updateSettings(key: string, value: JsonObject) {
if (this.user == null) return;
this.reversiService.updateSettings(this.gameId!, this.user, key, value);

View file

@ -5,6 +5,7 @@
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class ReversiChannel extends Channel {
@ -21,7 +22,7 @@ class ReversiChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
this.subscriber.on(`reversiStream:${this.user!.id}`, this.send);
}

View file

@ -8,6 +8,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { bindThis } from '@/decorators.js';
import { RoleService } from '@/core/RoleService.js';
import type { GlobalEvents } from '@/core/GlobalEventService.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class RoleTimelineChannel extends Channel {
@ -28,8 +29,9 @@ class RoleTimelineChannel extends Channel {
}
@bindThis
public async init(params: any) {
this.roleId = params.roleId as string;
public async init(params: JsonObject) {
if (typeof params.roleId !== 'string') return;
this.roleId = params.roleId;
this.subscriber.on(`roleTimelineStream:${this.roleId}`, this.onEvent);
}

View file

@ -6,6 +6,7 @@
import Xev from 'xev';
import { Injectable } from '@nestjs/common';
import { bindThis } from '@/decorators.js';
import type { JsonObject, JsonValue } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
const ev = new Xev();
@ -22,19 +23,20 @@ class ServerStatsChannel extends Channel {
}
@bindThis
public async init(params: any) {
public async init(params: JsonObject) {
ev.addListener('serverStats', this.onStats);
}
@bindThis
private onStats(stats: any) {
private onStats(stats: JsonObject) {
this.send('stats', stats);
}
@bindThis
public onMessage(type: string, body: any) {
public onMessage(type: string, body: JsonValue) {
switch (type) {
case 'requestLog':
if (typeof body !== 'object' || body === null || Array.isArray(body)) return;
ev.once(`serverStatsLog:${body.id}`, statsLog => {
this.send('statsLog', statsLog);
});

View file

@ -10,6 +10,7 @@ import { NoteEntityService } from '@/core/entities/NoteEntityService.js';
import { DI } from '@/di-symbols.js';
import { bindThis } from '@/decorators.js';
import { isRenotePacked, isQuotePacked } from '@/misc/is-renote.js';
import type { JsonObject } from '@/misc/json-value.js';
import Channel, { type MiChannelService } from '../channel.js';
class UserListChannel extends Channel {
@ -36,10 +37,11 @@ class UserListChannel extends Channel {
}
@bindThis
public async init(params: any) {
this.listId = params.listId as string;
this.withFiles = params.withFiles ?? false;
this.withRenotes = params.withRenotes ?? true;
public async init(params: JsonObject) {
if (typeof params.listId !== 'string') return;
this.listId = params.listId;
this.withFiles = !!(params.withFiles ?? false);
this.withRenotes = !!(params.withRenotes ?? true);
// Check existence and owner
const listExist = await this.userListsRepository.exists({