From f53aa62878bc1332ad1cbb187c18fc6bfb15745f Mon Sep 17 00:00:00 2001 From: cannorin Date: Wed, 29 Jan 2025 17:21:44 +0000 Subject: [PATCH] Update misskey-js --- bun.lockb | Bin 8951 -> 8933 bytes index.ts | 7 +- misskey-js/LICENSE | 21 -- misskey-js/streaming.ts | 474 ---------------------------------- misskey-js/streaming.types.ts | 279 -------------------- package.json | 2 +- 6 files changed, 4 insertions(+), 779 deletions(-) delete mode 100644 misskey-js/LICENSE delete mode 100644 misskey-js/streaming.ts delete mode 100644 misskey-js/streaming.types.ts diff --git a/bun.lockb b/bun.lockb index 9e526fd69af245b6f0b827b32f035427e0cadb86..18edccab260420a77e8e77c3656029122678a4dc 100755 GIT binary patch delta 742 zcmZXSUr1AN6vuzRySuF|B@Ar$Zj+kSY@&CY&e#gQQVI@R!)izoqdyC_g{_E+0xcqY zXbG(oE+d*HnfAw*TQrmygI=PrrVk=WNzlVGD-0J!L}$aB58a3J`JO-Ab2;Dpqxoa= zRlyX$a(}txt|hJjC3PQk(-z5W`+ z6^0ce?Sd@E7hqvUs)P_m7Yt*(1X)&8cH`PTFwbsLzC-0Js9Gf0|UY*;nJSB|d> zFS#}F>c*Kwcp}8mE~ii@*lk4iFJ|4_V}4ri!cL7%u-6FAB-Hb~;s1UmzBT`(;W*FJ zDTv~fY~-r%@!qu!Z~9qk7hHk^r&vhwe4T83W|OovHNN0q?#sW%^G7YBvE7+i?s%YB g&(k1O==;#iv|dL&Fs+X$@UvmJVKGn1XS}QW3$7~7CjbBd delta 761 zcmaFr`rUPcp5ogNaqgvF=YMvVML1nEQgdD>BHXpMw*F3E_C_vKPKCGW6a6hca~T*I z#26SF@(WV)5;GYX!hn1(Aisc-fq@rDM+0e5AZ-N|w_svm-~{qpfiyReJ_V$CfOO5o zi{h45EDQ{?Ku$c6mIl&pKw1(=>j7yAAT0)^|1&c%hy(dAfi%eS%bOJ$*%=v|Cu=g< zGhUyZ$z(4m47Aq+DD{FJY!3tD!JQ zFM;H>$(k(ojN+3sfu#53l|XXFP|lK$bt4 z^%TxBVPjzM1&cKTS>9mQ85oOEd9x<_7AA+nG6$s?oAx7T7tWT=c%aL_WO}&A>Q;*& z?ave5Ols?Fi0`*$u%7CAVqw)5_48}aGzNFFzi*tc^Vh&%cJ4L%x3@OSa_O@(_HXtT ze9a~f3;57=|E5UnTJesF(FGXfLX-U^L^%_HEKp?RPR^AuW{jS^P(qTiVDfGWNoiR0 z1-|*ldS~7K1x$=4dM0`XK=l@r-%CiE)U%>>5f mK`C*@_{le=@_9`33=Q=RbrW+6G7=|yOMgWX*z7E`hz$V2F3;5f diff --git a/index.ts b/index.ts index 7b6a1b7..4c9225f 100644 --- a/index.ts +++ b/index.ts @@ -1,9 +1,8 @@ import { parseArgs } from "node:util"; import { api } from "misskey-js"; -import type { Stream as MisskeyStream } from "misskey-js"; +import { Stream } from "misskey-js"; import type { Note } from "misskey-js/entities.js"; -import Stream from "./misskey-js/streaming"; import OpenAI from "openai"; import type { ChatCompletionMessageParam } from "openai/resources/index.js"; @@ -209,7 +208,7 @@ async function processJob(job: Job) { const jobs: Job[] = []; -let stream: MisskeyStream; +let stream: Stream; let channel: ReturnType>; /** dispose stream for recreation */ @@ -230,7 +229,7 @@ function initializeStream() { { binaryType: "arraybuffer", }, - ) as unknown as MisskeyStream; + ); channel = stream.useChannel("main"); // notify when connected diff --git a/misskey-js/LICENSE b/misskey-js/LICENSE deleted file mode 100644 index 63473fc..0000000 --- a/misskey-js/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2021-2024 syuilo and other contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/misskey-js/streaming.ts b/misskey-js/streaming.ts deleted file mode 100644 index 63d492d..0000000 --- a/misskey-js/streaming.ts +++ /dev/null @@ -1,474 +0,0 @@ -import { EventEmitter } from "eventemitter3"; -import ReconnectingWebsocket, { type Options } from "reconnecting-websocket"; -import type { BroadcastEvents, Channels } from "./streaming.types.js"; - -export function urlQuery( - obj: Record, -): string { - const params = Object.entries(obj) - .filter(([, v]) => (Array.isArray(v) ? v.length : v !== undefined)) - .reduce( - // biome-ignore lint/style/noNonNullAssertion: - // biome-ignore lint/suspicious/noAssignInExpressions: - // biome-ignore lint/style/noCommaOperator: - (a, [k, v]) => ((a[k] = v!), a), - {} as Record, - ); - - return Object.entries(params) - .map((e) => `${e[0]}=${encodeURIComponent(e[1])}`) - .join("&"); -} - -type AnyOf> = T[keyof T]; - -export type StreamEvents = { - _connected_: undefined; - _disconnected_: undefined; -} & BroadcastEvents; - -export interface IStream extends EventEmitter { - state: "initializing" | "reconnecting" | "connected"; - - useChannel( - channel: C, - params?: Channels[C]["params"], - name?: string, - ): IChannelConnection; - removeSharedConnection(connection: SharedConnection): void; - removeSharedConnectionPool(pool: Pool): void; - disconnectToChannel(connection: NonSharedConnection): void; - send(typeOrPayload: string): void; - send(typeOrPayload: string, payload: unknown): void; - send(typeOrPayload: Record | unknown[]): void; - send( - typeOrPayload: string | Record | unknown[], - payload?: unknown, - ): void; - ping(): void; - heartbeat(): void; - close(): void; -} - -/** - * Misskey stream connection - */ -// eslint-disable-next-line import/no-default-export -export default class Stream - extends EventEmitter - implements IStream -{ - private stream: ReconnectingWebsocket; - public state: "initializing" | "reconnecting" | "connected" = "initializing"; - private sharedConnectionPools: Pool[] = []; - private sharedConnections: SharedConnection[] = []; - private nonSharedConnections: NonSharedConnection[] = []; - private idCounter = 0; - - constructor( - origin: string, - user: { token: string } | null, - options: { - WebSocket?: Options["WebSocket"]; - binaryType?: ReconnectingWebsocket["binaryType"]; - } = {}, - ) { - super(); - - this.genId = this.genId.bind(this); - this.useChannel = this.useChannel.bind(this); - this.useSharedConnection = this.useSharedConnection.bind(this); - this.removeSharedConnection = this.removeSharedConnection.bind(this); - this.removeSharedConnectionPool = - this.removeSharedConnectionPool.bind(this); - this.connectToChannel = this.connectToChannel.bind(this); - this.disconnectToChannel = this.disconnectToChannel.bind(this); - this.onOpen = this.onOpen.bind(this); - this.onClose = this.onClose.bind(this); - this.onMessage = this.onMessage.bind(this); - this.send = this.send.bind(this); - this.close = this.close.bind(this); - - const query = urlQuery({ - i: user?.token, - - // To prevent cache of an HTML such as error screen - _t: Date.now(), - }); - - const wsOrigin = origin - .replace("http://", "ws://") - .replace("https://", "wss://"); - - this.stream = new ReconnectingWebsocket( - `${wsOrigin}/streaming?${query}`, - "", - { - minReconnectionDelay: 1, // https://github.com/pladaria/reconnecting-websocket/issues/91 - WebSocket: options.WebSocket, - }, - ); - if (options.binaryType) { - this.stream.binaryType = options.binaryType; - } - this.stream.addEventListener("open", this.onOpen); - this.stream.addEventListener("close", this.onClose); - this.stream.addEventListener("message", this.onMessage); - } - - private genId(): string { - return (++this.idCounter).toString(); - } - - public useChannel( - channel: C, - params?: Channels[C]["params"], - name?: string, - ): Connection { - if (params) { - return this.connectToChannel(channel, params); - } - return this.useSharedConnection(channel, name); - } - - private useSharedConnection( - channel: C, - name?: string, - ): SharedConnection { - let pool = this.sharedConnectionPools.find((p) => p.channel === channel); - - if (pool == null) { - pool = new Pool(this, channel, this.genId()); - this.sharedConnectionPools.push(pool); - } - - const connection = new SharedConnection( - this, - channel, - pool, - name, - ); - this.sharedConnections.push(connection as unknown as SharedConnection); - return connection; - } - - public removeSharedConnection(connection: SharedConnection): void { - this.sharedConnections = this.sharedConnections.filter( - (c) => c !== connection, - ); - } - - public removeSharedConnectionPool(pool: Pool): void { - this.sharedConnectionPools = this.sharedConnectionPools.filter( - (p) => p !== pool, - ); - } - - private connectToChannel( - channel: C, - params: Channels[C]["params"], - ): NonSharedConnection { - const connection = new NonSharedConnection( - this, - channel, - this.genId(), - params, - ); - this.nonSharedConnections.push( - connection as unknown as NonSharedConnection, - ); - return connection; - } - - public disconnectToChannel(connection: NonSharedConnection): void { - this.nonSharedConnections = this.nonSharedConnections.filter( - (c) => c !== connection, - ); - } - - /** - * Callback of when open connection - */ - private onOpen(): void { - const isReconnect = this.state === "reconnecting"; - - this.state = "connected"; - this.emit("_connected_"); - - // チャンネル再接続 - if (isReconnect) { - for (const p of this.sharedConnectionPools) p.connect(); - for (const c of this.nonSharedConnections) c.connect(); - } - } - - /** - * Callback of when close connection - */ - private onClose(): void { - if (this.state === "connected") { - this.state = "reconnecting"; - this.emit("_disconnected_"); - } - } - - /** - * Callback of when received a message from connection - */ - private onMessage(message: { data: string }): void { - const { type, body } = JSON.parse(message.data); - - if (type === "channel") { - const id = body.id; - - let connections: Connection[]; - - connections = this.sharedConnections.filter((c) => c.id === id); - - if (connections.length === 0) { - const found = this.nonSharedConnections.find((c) => c.id === id); - if (found) { - connections = [found]; - } - } - - for (const c of connections) { - c.emit(body.type, body.body); - c.inCount++; - } - } else { - this.emit(type, body); - } - } - - /** - * Send a message to connection - * ! ストリーム上のやり取りはすべてJSONで行われます ! - */ - public send(typeOrPayload: string): void; - public send(typeOrPayload: string, payload: unknown): void; - public send(typeOrPayload: Record | unknown[]): void; - public send( - typeOrPayload: string | Record | unknown[], - payload?: unknown, - ): void { - if (typeof typeOrPayload === "string") { - this.stream.send( - JSON.stringify({ - type: typeOrPayload, - ...(payload === undefined ? {} : { body: payload }), - }), - ); - return; - } - - this.stream.send(JSON.stringify(typeOrPayload)); - } - - public ping(): void { - this.stream.send("ping"); - } - - public heartbeat(): void { - this.stream.send("h"); - } - - /** - * Close this connection - */ - public close(): void { - this.stream.close(); - } -} - -// TODO: これらのクラスを Stream クラスの内部クラスにすれば余計なメンバをpublicにしないで済むかも? -// もしくは @internal を使う? https://www.typescriptlang.org/tsconfig#stripInternal -class Pool { - public channel: string; - public id: string; - protected stream: Stream; - public users = 0; - private disposeTimerId: ReturnType | null = null; - private isConnected = false; - - constructor(stream: Stream, channel: string, id: string) { - this.onStreamDisconnected = this.onStreamDisconnected.bind(this); - this.inc = this.inc.bind(this); - this.dec = this.dec.bind(this); - this.connect = this.connect.bind(this); - this.disconnect = this.disconnect.bind(this); - - this.channel = channel; - this.stream = stream; - this.id = id; - - this.stream.on("_disconnected_", this.onStreamDisconnected); - } - - private onStreamDisconnected(): void { - this.isConnected = false; - } - - public inc(): void { - if (this.users === 0 && !this.isConnected) { - this.connect(); - } - - this.users++; - - // タイマー解除 - if (this.disposeTimerId) { - clearTimeout(this.disposeTimerId); - this.disposeTimerId = null; - } - } - - public dec(): void { - this.users--; - - // そのコネクションの利用者が誰もいなくなったら - if (this.users === 0) { - // また直ぐに再利用される可能性があるので、一定時間待ち、 - // 新たな利用者が現れなければコネクションを切断する - this.disposeTimerId = setTimeout(() => { - this.disconnect(); - }, 3000); - } - } - - public connect(): void { - if (this.isConnected) return; - this.isConnected = true; - this.stream.send("connect", { - channel: this.channel, - id: this.id, - }); - } - - private disconnect(): void { - this.stream.off("_disconnected_", this.onStreamDisconnected); - this.stream.send("disconnect", { id: this.id }); - this.stream.removeSharedConnectionPool(this); - } -} - -export interface IChannelConnection< - Channel extends AnyOf = AnyOf, -> extends EventEmitter { - id: string; - name?: string; - inCount: number; - outCount: number; - channel: string; - - send( - type: T, - body: Channel["receives"][T], - ): void; - dispose(): void; -} - -export abstract class Connection< - Channel extends AnyOf = AnyOf, - > - extends EventEmitter - implements IChannelConnection -{ - public channel: string; - protected stream: Stream; - public abstract id: string; - - public name?: string; // for debug - public inCount = 0; // for debug - public outCount = 0; // for debug - - constructor(stream: Stream, channel: string, name?: string) { - super(); - - this.send = this.send.bind(this); - - this.stream = stream; - this.channel = channel; - if (name !== undefined) { - this.name = name; - } - } - - public send( - type: T, - body: Channel["receives"][T], - ): void { - this.stream.send("ch", { - id: this.id, - type: type, - body: body, - }); - - this.outCount++; - } - - public abstract dispose(): void; -} - -class SharedConnection< - Channel extends AnyOf = AnyOf, -> extends Connection { - private pool: Pool; - - public get id(): string { - return this.pool.id; - } - - constructor(stream: Stream, channel: string, pool: Pool, name?: string) { - super(stream, channel, name); - - this.dispose = this.dispose.bind(this); - - this.pool = pool; - this.pool.inc(); - } - - public dispose(): void { - this.pool.dec(); - this.removeAllListeners(); - this.stream.removeSharedConnection(this as unknown as SharedConnection); - } -} - -class NonSharedConnection< - Channel extends AnyOf = AnyOf, -> extends Connection { - public id: string; - protected params: Channel["params"]; - - constructor( - stream: Stream, - channel: string, - id: string, - params: Channel["params"], - ) { - super(stream, channel); - - this.connect = this.connect.bind(this); - this.dispose = this.dispose.bind(this); - - this.params = params; - this.id = id; - - this.connect(); - } - - public connect(): void { - this.stream.send("connect", { - channel: this.channel, - id: this.id, - params: this.params, - }); - } - - public dispose(): void { - this.removeAllListeners(); - this.stream.send("disconnect", { id: this.id }); - this.stream.disconnectToChannel(this as unknown as NonSharedConnection); - } -} diff --git a/misskey-js/streaming.types.ts b/misskey-js/streaming.types.ts deleted file mode 100644 index 38eade4..0000000 --- a/misskey-js/streaming.types.ts +++ /dev/null @@ -1,279 +0,0 @@ -import type { - Antenna, - DriveFile, - DriveFolder, - Note, - Notification, - Signin, - User, - UserDetailed, - UserDetailedNotMe, - UserLite, -} from "./autogen/models.js"; -import type { ReversiUpdateKey } from "./consts.js"; -import type { - AnnouncementCreated, - EmojiAdded, - EmojiDeleted, - EmojiUpdated, - PageEvent, - QueueStats, - QueueStatsLog, - ReversiGameDetailed, - ServerStats, - ServerStatsLog, -} from "./entities.js"; - -type ReversiUpdateSettings = { - key: K; - value: ReversiGameDetailed[K]; -}; - -export type Channels = { - main: { - params: null; - events: { - notification: (payload: Notification) => void; - mention: (payload: Note) => void; - reply: (payload: Note) => void; - renote: (payload: Note) => void; - follow: (payload: UserDetailedNotMe) => void; // 自分が他人をフォローしたとき - followed: (payload: UserDetailed | UserLite) => void; // 他人が自分をフォローしたとき - unfollow: (payload: UserDetailed) => void; // 自分が他人をフォロー解除したとき - meUpdated: (payload: UserDetailed) => void; - pageEvent: (payload: PageEvent) => void; - urlUploadFinished: (payload: { marker: string; file: DriveFile }) => void; - readAllNotifications: () => void; - unreadNotification: (payload: Notification) => void; - unreadMention: (payload: Note["id"]) => void; - readAllUnreadMentions: () => void; - notificationFlushed: () => void; - unreadSpecifiedNote: (payload: Note["id"]) => void; - readAllUnreadSpecifiedNotes: () => void; - readAllAntennas: () => void; - unreadAntenna: (payload: Antenna) => void; - readAllAnnouncements: () => void; - myTokenRegenerated: () => void; - signin: (payload: Signin) => void; - registryUpdated: (payload: { - scope?: string[]; - key: string; - // biome-ignore lint/suspicious/noExplicitAny: - value: any | null; - }) => void; - driveFileCreated: (payload: DriveFile) => void; - readAntenna: (payload: Antenna) => void; - receiveFollowRequest: (payload: User) => void; - announcementCreated: (payload: AnnouncementCreated) => void; - }; - receives: null; - }; - homeTimeline: { - params: { - withRenotes?: boolean; - withFiles?: boolean; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - localTimeline: { - params: { - withRenotes?: boolean; - withReplies?: boolean; - withFiles?: boolean; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - hybridTimeline: { - params: { - withRenotes?: boolean; - withReplies?: boolean; - withFiles?: boolean; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - globalTimeline: { - params: { - withRenotes?: boolean; - withFiles?: boolean; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - userList: { - params: { - listId: string; - withFiles?: boolean; - withRenotes?: boolean; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - hashtag: { - params: { - q: string[][]; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - roleTimeline: { - params: { - roleId: string; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - antenna: { - params: { - antennaId: string; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - channel: { - params: { - channelId: string; - }; - events: { - note: (payload: Note) => void; - }; - receives: null; - }; - drive: { - params: null; - events: { - fileCreated: (payload: DriveFile) => void; - fileDeleted: (payload: DriveFile["id"]) => void; - fileUpdated: (payload: DriveFile) => void; - folderCreated: (payload: DriveFolder) => void; - folderDeleted: (payload: DriveFolder["id"]) => void; - folderUpdated: (payload: DriveFolder) => void; - }; - receives: null; - }; - serverStats: { - params: null; - events: { - stats: (payload: ServerStats) => void; - statsLog: (payload: ServerStatsLog) => void; - }; - receives: { - requestLog: { - id: string | number; - length: number; - }; - }; - }; - queueStats: { - params: null; - events: { - stats: (payload: QueueStats) => void; - statsLog: (payload: QueueStatsLog) => void; - }; - receives: { - requestLog: { - id: string | number; - length: number; - }; - }; - }; - admin: { - params: null; - events: { - newAbuseUserReport: { - id: string; - targetUserId: string; - reporterId: string; - comment: string; - }; - }; - receives: null; - }; - reversiGame: { - params: { - gameId: string; - }; - events: { - started: (payload: { game: ReversiGameDetailed }) => void; - ended: (payload: { - winnerId: User["id"] | null; - game: ReversiGameDetailed; - }) => void; - canceled: (payload: { userId: User["id"] }) => void; - changeReadyStates: (payload: { user1: boolean; user2: boolean }) => void; - updateSettings: (payload: { - userId: User["id"]; - key: K; - value: ReversiGameDetailed[K]; - }) => void; - log: (payload: Record) => void; - }; - receives: { - putStone: { - pos: number; - id: string; - }; - ready: boolean; - cancel: null | Record; - updateSettings: ReversiUpdateSettings; - claimTimeIsUp: null | Record; - }; - }; -}; - -export type NoteUpdatedEvent = { id: Note["id"] } & ( - | { - type: "reacted"; - body: { - reaction: string; - emoji: string | null; - userId: User["id"]; - }; - } - | { - type: "unreacted"; - body: { - reaction: string; - userId: User["id"]; - }; - } - | { - type: "deleted"; - body: { - deletedAt: string; - }; - } - | { - type: "pollVoted"; - body: { - choice: number; - userId: User["id"]; - }; - } -); - -export type BroadcastEvents = { - noteUpdated: (payload: NoteUpdatedEvent) => void; - emojiAdded: (payload: EmojiAdded) => void; - emojiUpdated: (payload: EmojiUpdated) => void; - emojiDeleted: (payload: EmojiDeleted) => void; - announcementCreated: (payload: AnnouncementCreated) => void; -}; diff --git a/package.json b/package.json index fdeef77..9d8edc8 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "typescript": "^5.0.0" }, "dependencies": { - "misskey-js": "^2024.11.1-alpha.0", + "misskey-js": "^2025.1.0", "openai": "5.0.0-alpha.0", "reconnecting-websocket": "^4.4.0" }