296 lines
7.7 KiB
TypeScript
296 lines
7.7 KiB
TypeScript
import type { EventEmitter } from "events";
|
|
import type Emitter from "strict-event-emitter-types";
|
|
import type { Channel } from "@/models/entities/channel.js";
|
|
import type { User } from "@/models/entities/user.js";
|
|
import type { UserProfile } from "@/models/entities/user-profile.js";
|
|
import type { Note } from "@/models/entities/note.js";
|
|
import type { Antenna } from "@/models/entities/antenna.js";
|
|
import type { DriveFile } from "@/models/entities/drive-file.js";
|
|
import type { DriveFolder } from "@/models/entities/drive-folder.js";
|
|
import type { UserList } from "@/models/entities/user-list.js";
|
|
import type { MessagingMessage } from "@/models/entities/messaging-message.js";
|
|
import type { UserGroup } from "@/models/entities/user-group.js";
|
|
import type { AbuseUserReport } from "@/models/entities/abuse-user-report.js";
|
|
import type { Signin } from "@/models/entities/signin.js";
|
|
import type { Page } from "@/models/entities/page.js";
|
|
import type { Packed } from "@/misc/schema.js";
|
|
import type { Webhook } from "@/models/entities/webhook";
|
|
|
|
//#region Stream type-body definitions
|
|
export interface InternalStreamTypes {
|
|
userChangeSuspendedState: {
|
|
id: User["id"];
|
|
isSuspended: User["isSuspended"];
|
|
};
|
|
userChangeSilencedState: {
|
|
id: User["id"];
|
|
isSilenced: User["isSilenced"];
|
|
};
|
|
userChangeModeratorState: {
|
|
id: User["id"];
|
|
isModerator: User["isModerator"];
|
|
};
|
|
userTokenRegenerated: {
|
|
id: User["id"];
|
|
oldToken: User["token"];
|
|
newToken: User["token"];
|
|
};
|
|
localUserUpdated: {
|
|
id: User["id"];
|
|
};
|
|
remoteUserUpdated: {
|
|
id: User["id"];
|
|
};
|
|
webhookCreated: Webhook;
|
|
webhookDeleted: Webhook;
|
|
webhookUpdated: Webhook;
|
|
antennaCreated: Antenna;
|
|
antennaDeleted: Antenna;
|
|
antennaUpdated: Antenna;
|
|
}
|
|
|
|
export interface BroadcastTypes {
|
|
emojiAdded: {
|
|
emoji: Packed<"Emoji">;
|
|
};
|
|
}
|
|
|
|
export interface UserStreamTypes {
|
|
terminate: Record<string, unknown>;
|
|
followChannel: Channel;
|
|
unfollowChannel: Channel;
|
|
updateUserProfile: UserProfile;
|
|
mute: User;
|
|
unmute: User;
|
|
follow: Packed<"UserDetailedNotMe">;
|
|
unfollow: Packed<"User">;
|
|
userAdded: Packed<"User">;
|
|
}
|
|
|
|
export interface MainStreamTypes {
|
|
notification: Packed<"Notification">;
|
|
mention: Packed<"Note">;
|
|
reply: Packed<"Note">;
|
|
renote: Packed<"Note">;
|
|
follow: Packed<"UserDetailedNotMe">;
|
|
followed: Packed<"User">;
|
|
unfollow: Packed<"User">;
|
|
meUpdated: Packed<"User">;
|
|
pageEvent: {
|
|
pageId: Page["id"];
|
|
event: string;
|
|
var: any;
|
|
userId: User["id"];
|
|
user: Packed<"User">;
|
|
};
|
|
urlUploadFinished: {
|
|
marker?: string | null;
|
|
file: Packed<"DriveFile">;
|
|
};
|
|
readAllNotifications: undefined;
|
|
unreadNotification: Packed<"Notification">;
|
|
unreadMention: Note["id"];
|
|
readAllUnreadMentions: undefined;
|
|
unreadSpecifiedNote: Note["id"];
|
|
readAllUnreadSpecifiedNotes: undefined;
|
|
readAllMessagingMessages: undefined;
|
|
messagingMessage: Packed<"MessagingMessage">;
|
|
unreadMessagingMessage: Packed<"MessagingMessage">;
|
|
readAllAntennas: undefined;
|
|
unreadAntenna: Antenna;
|
|
readAllAnnouncements: undefined;
|
|
readAllChannels: undefined;
|
|
unreadChannel: Note["id"];
|
|
myTokenRegenerated: undefined;
|
|
signin: Signin;
|
|
registryUpdated: {
|
|
scope?: string[];
|
|
key: string;
|
|
value: any | null;
|
|
};
|
|
driveFileCreated: Packed<"DriveFile">;
|
|
readAntenna: Antenna;
|
|
receiveFollowRequest: Packed<"User">;
|
|
}
|
|
|
|
export interface DriveStreamTypes {
|
|
fileCreated: Packed<"DriveFile">;
|
|
fileDeleted: DriveFile["id"];
|
|
fileUpdated: Packed<"DriveFile">;
|
|
folderCreated: Packed<"DriveFolder">;
|
|
folderDeleted: DriveFolder["id"];
|
|
folderUpdated: Packed<"DriveFolder">;
|
|
}
|
|
|
|
export interface NoteStreamTypes {
|
|
pollVoted: {
|
|
choice: number;
|
|
userId: User["id"];
|
|
};
|
|
deleted: {
|
|
deletedAt: Date;
|
|
};
|
|
reacted: {
|
|
reaction: string;
|
|
emoji?: {
|
|
name: string;
|
|
url: string;
|
|
} | null;
|
|
userId: User["id"];
|
|
};
|
|
unreacted: {
|
|
reaction: string;
|
|
userId: User["id"];
|
|
};
|
|
replied: {
|
|
id: Note["id"];
|
|
};
|
|
updated: {
|
|
updatedAt?: Note["updatedAt"];
|
|
};
|
|
}
|
|
type NoteStreamEventTypes = {
|
|
[key in keyof NoteStreamTypes]: {
|
|
id: Note["id"];
|
|
body: NoteStreamTypes[key];
|
|
};
|
|
};
|
|
|
|
export interface ChannelStreamTypes {
|
|
typing: User["id"];
|
|
}
|
|
|
|
export interface UserListStreamTypes {
|
|
userAdded: Packed<"User">;
|
|
userRemoved: Packed<"User">;
|
|
}
|
|
|
|
export interface AntennaStreamTypes {
|
|
note: Note;
|
|
}
|
|
|
|
export interface MessagingStreamTypes {
|
|
read: MessagingMessage["id"][];
|
|
typing: User["id"];
|
|
message: Packed<"MessagingMessage">;
|
|
deleted: MessagingMessage["id"];
|
|
}
|
|
|
|
export interface GroupMessagingStreamTypes {
|
|
read: {
|
|
ids: MessagingMessage["id"][];
|
|
userId: User["id"];
|
|
};
|
|
typing: User["id"];
|
|
message: Packed<"MessagingMessage">;
|
|
deleted: MessagingMessage["id"];
|
|
}
|
|
|
|
export interface MessagingIndexStreamTypes {
|
|
read: MessagingMessage["id"][];
|
|
message: Packed<"MessagingMessage">;
|
|
}
|
|
|
|
export interface AdminStreamTypes {
|
|
newAbuseUserReport: {
|
|
id: AbuseUserReport["id"];
|
|
targetUserId: User["id"];
|
|
reporterId: User["id"];
|
|
comment: string;
|
|
};
|
|
}
|
|
//#endregion
|
|
|
|
// 辞書(interface or type)から{ type, body }ユニオンを定義
|
|
// https://stackoverflow.com/questions/49311989/can-i-infer-the-type-of-a-value-using-extends-keyof-type
|
|
// VS Codeの展開を防止するためにEvents型を定義
|
|
type Events<T extends object> = { [K in keyof T]: { type: K; body: T[K] } };
|
|
type EventUnionFromDictionary<T extends object, U = Events<T>> = U[keyof U];
|
|
|
|
// name/messages(spec) pairs dictionary
|
|
export type StreamMessages = {
|
|
internal: {
|
|
name: "internal";
|
|
payload: EventUnionFromDictionary<InternalStreamTypes>;
|
|
};
|
|
broadcast: {
|
|
name: "broadcast";
|
|
payload: EventUnionFromDictionary<BroadcastTypes>;
|
|
};
|
|
user: {
|
|
name: `user:${User["id"]}`;
|
|
payload: EventUnionFromDictionary<UserStreamTypes>;
|
|
};
|
|
main: {
|
|
name: `mainStream:${User["id"]}`;
|
|
payload: EventUnionFromDictionary<MainStreamTypes>;
|
|
};
|
|
drive: {
|
|
name: `driveStream:${User["id"]}`;
|
|
payload: EventUnionFromDictionary<DriveStreamTypes>;
|
|
};
|
|
note: {
|
|
name: `noteStream:${Note["id"]}`;
|
|
payload: EventUnionFromDictionary<NoteStreamEventTypes>;
|
|
};
|
|
channel: {
|
|
name: `channelStream:${Channel["id"]}`;
|
|
payload: EventUnionFromDictionary<ChannelStreamTypes>;
|
|
};
|
|
userList: {
|
|
name: `userListStream:${UserList["id"]}`;
|
|
payload: EventUnionFromDictionary<UserListStreamTypes>;
|
|
};
|
|
antenna: {
|
|
name: `antennaStream:${Antenna["id"]}`;
|
|
payload: EventUnionFromDictionary<AntennaStreamTypes>;
|
|
};
|
|
messaging: {
|
|
name: `messagingStream:${User["id"]}-${User["id"]}`;
|
|
payload: EventUnionFromDictionary<MessagingStreamTypes>;
|
|
};
|
|
groupMessaging: {
|
|
name: `messagingStream:${UserGroup["id"]}`;
|
|
payload: EventUnionFromDictionary<GroupMessagingStreamTypes>;
|
|
};
|
|
messagingIndex: {
|
|
name: `messagingIndexStream:${User["id"]}`;
|
|
payload: EventUnionFromDictionary<MessagingIndexStreamTypes>;
|
|
};
|
|
admin: {
|
|
name: `adminStream:${User["id"]}`;
|
|
payload: EventUnionFromDictionary<AdminStreamTypes>;
|
|
};
|
|
notes: {
|
|
name: "notesStream";
|
|
payload: Note;
|
|
};
|
|
};
|
|
|
|
// API event definitions
|
|
// ストリームごとのEmitterの辞書を用意
|
|
type EventEmitterDictionary = {
|
|
[x in keyof StreamMessages]: Emitter<
|
|
EventEmitter,
|
|
{
|
|
[y in StreamMessages[x]["name"]]: (
|
|
e: StreamMessages[x]["payload"],
|
|
) => void;
|
|
}
|
|
>;
|
|
};
|
|
// 共用体型を交差型にする型 https://stackoverflow.com/questions/54938141/typescript-convert-union-to-intersection
|
|
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
k: infer I,
|
|
) => void
|
|
? I
|
|
: never;
|
|
// Emitter辞書から共用体型を作り、UnionToIntersectionで交差型にする
|
|
export type StreamEventEmitter = UnionToIntersection<
|
|
EventEmitterDictionary[keyof StreamMessages]
|
|
>;
|
|
// { [y in name]: (e: spec) => void }をまとめてその交差型をEmitterにかけるとts(2590)にひっかかる
|
|
|
|
// provide stream channels union
|
|
export type StreamChannels = StreamMessages[keyof StreamMessages]["name"];
|